Connect OpenClaw to Jira Cloud with secret-safe API access via pastewatch redaction. Includes credential setup, REST API helper script, JQL patterns, focus a...
---
name: jira-openclaw
description: Connect OpenClaw to Jira Cloud with secret-safe API access via pastewatch redaction. Includes credential setup, REST API helper script, JQL patterns, focus auto-linker cron, and overdue ticket bumper. Use when integrating Jira into an OpenClaw agent, setting up Jira cron jobs, or querying issues from chat.
---
# Jira + OpenClaw Integration
Connect your OpenClaw agent to Jira Cloud. Secrets never reach the LLM — pastewatch redacts credentials in transit.
**Requires:** `pastewatch-cli` (MCP server running), `curl`, `python3`
## 1. Credential Setup
```bash
mkdir -p ~/.openclaw/workspace/.secrets
chmod 700 ~/.openclaw/workspace/.secrets
echo ".secrets/" >> ~/.openclaw/workspace/.gitignore
cat > ~/.openclaw/workspace/.secrets/jira.env << 'EOF'
JIRA_TOKEN=<your-api-token-or-pat>
JIRA_URL=https://your-org.atlassian.net/
JIRA_EMAIL=your@email.com
EOF
chmod 600 ~/.openclaw/workspace/.secrets/jira.env
```
**Token types:**
- **API token** (id.atlassian.com → Security → API tokens) — works with Basic auth
- **PAT** (ATATT... prefix, Jira settings → Personal Access Tokens) — also works with Basic auth (`email:PAT`)
Both use the same script below. Bearer auth is NOT needed.
## 2. API Helper Script
Create `~/.openclaw/workspace/.secrets/jira.sh`:
```bash
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/jira.env"
METHOD="${1:?Usage: jira.sh <METHOD> <endpoint> [body]}"
ENDPOINT="${2:?Usage: jira.sh <METHOD> <endpoint> [body]}"
BODY="${3:-}"
URL="${JIRA_URL%/}${ENDPOINT}"
if [ -n "$BODY" ]; then
curl -s --http1.1 -X "$METHOD" \
-u "${JIRA_EMAIL}:${JIRA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$BODY" "$URL"
else
curl -s --http1.1 -X "$METHOD" \
-u "${JIRA_EMAIL}:${JIRA_TOKEN}" \
-H "Content-Type: application/json" "$URL"
fi
```
```bash
chmod +x ~/.openclaw/workspace/.secrets/jira.sh
```
**Why `--http1.1`:** Atlassian's CDN sometimes breaks HTTP/2 with curl. Force HTTP/1.1.
## 3. Verify
```bash
# Test auth (pipe through pastewatch to confirm redaction)
~/.openclaw/workspace/.secrets/jira.sh GET '/rest/api/3/myself' | pastewatch-cli scan
```
You should see your displayName with emails/URLs redacted.
## 4. Pastewatch Protection
The agent reads jira.env through pastewatch MCP — it sees `__PW{CREDENTIAL_1}__` instead of the real token. The script runs credentials at the shell level (never in LLM context).
```
Agent calls exec → jira.sh sources .env → curl sends real token → response comes back
↑ never in context ↑ direct to Atlassian
```
Pair with chainwatch to control which Jira endpoints the agent can hit.
## 5. Key API Patterns
### Search (⚠️ use `/search/jql` NOT `/search`)
```bash
# /rest/api/3/search returns 410 Gone — always use /search/jql
jira.sh GET '/rest/api/3/search/jql?jql=<url-encoded>&maxResults=50&fields=key,summary,status,priority,duedate'
```
### Common JQL
```
# My open tasks
assignee="Name" AND resolution=Unresolved ORDER BY priority DESC
# Unassigned
project=XX AND assignee=EMPTY AND resolution=Unresolved AND issuetype != Epic
# Overdue
project=XX AND resolution=Unresolved AND duedate < "YYYY-MM-DD"
# Closed yesterday
project=XX AND assignee="Name" AND status changed to Done during ("YYYY-MM-DD","YYYY-MM-DD")
# In Progress
assignee="Name" AND status="In Progress" ORDER BY project,priority DESC
```
### Issue Operations
```bash
# Get issue
jira.sh GET '/rest/api/3/issue/XX-123?fields=key,summary,status,priority'
# Get transitions
jira.sh GET '/rest/api/3/issue/XX-123/transitions'
# Change status
jira.sh POST '/rest/api/3/issue/XX-123/transitions' '{"transition":{"id":"31"}}'
# Update fields (e.g. bump duedate)
jira.sh PUT '/rest/api/3/issue/XX-123' '{"fields":{"duedate":"2026-03-10"}}'
# Link issues
jira.sh POST '/rest/api/3/issueLink' '{"type":{"name":"Relates"},"inwardIssue":{"key":"XX-1"},"outwardIssue":{"key":"YY-2"}}'
```
## 6. Cron Patterns
### Focus Auto-Linker
Finds a daily focus record and links top-priority tasks to it:
```bash
# Find today's focus record (summary = "DD.MM", assigned to user)
jira.sh GET '/rest/api/3/search/jql?jql=project=DN AND summary~"05.03" AND assignee="Name"&fields=key,issuelinks'
# Get top 3 priority tasks
jira.sh GET '/rest/api/3/search/jql?jql=assignee="Name" AND project=DC AND resolution=Unresolved ORDER BY priority DESC,duedate ASC&maxResults=3&fields=key,summary,priority,duedate'
# Link each task to focus record
jira.sh POST '/rest/api/3/issueLink' '{"type":{"name":"Relates"},"inwardIssue":{"key":"DN-43"},"outwardIssue":{"key":"DC-3057"}}'
```
Schedule as OpenClaw cron: `isolated` session, `agentTurn`, Mon-Fri at start of day.
### Overdue Bumper
Checks end-of-day for unresolved tickets due today, bumps +1 day:
```bash
# Find overdue
jira.sh GET '/rest/api/3/search/jql?jql=assignee="Name" AND resolution=Unresolved AND duedate="2026-03-05"&fields=key,summary,duedate'
# Bump each
jira.sh PUT '/rest/api/3/issue/DC-3057' '{"fields":{"duedate":"2026-03-06"}}'
```
Schedule as OpenClaw cron: `isolated` session, `agentTurn`, Mon-Fri end of day.
## 7. TOOLS.md Reference
Add to your workspace TOOLS.md for quick agent recall:
```markdown
## JIRA
- Script: `~/.openclaw/workspace/.secrets/jira.sh GET|POST|PUT <endpoint> [body]`
- Creds: `.secrets/jira.env` (pastewatch-protected)
- ⚠️ Use `/rest/api/3/search/jql` NEVER `/rest/api/3/search` (410 Gone)
```
## Known Issues
- **Team-managed (next-gen) projects:** API returns `total: 0` but issues are present — iterate `issues` array, ignore `total`
- **HTTP/2 failures:** Atlassian CDN sometimes drops HTTP/2 requests — `--http1.1` fixes it
- **PAT vs API token:** Both work with Basic auth (`email:token`). Bearer auth fails with "Failed to parse Connect Session Auth Token"
---
**Jira-OpenClaw Integration v1.0**
Author: ppiankov
Copyright © 2026 ppiankov
Canonical source: https://clawhub.com/skills/jira-openclaw
License: MIT
This tool follows the [Agent-Native CLI Convention](https://ancc.dev). Validate with: `clawhub install ancc && ancc validate .`
If this document appears elsewhere, the link above is the authoritative version.
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit intent, inputs section with external connections and env var names, numbered procedure steps with input/output contracts per step, decision point branches for token types and error cases, output contract with json schemas, and outcome signal checklist with edge case docs.
Connect your OpenClaw agent to Jira Cloud. Secrets never reach the LLM. pastewatch redacts credentials in transit so the agent only sees masked tokens.
When to use: integrating Jira into an OpenClaw agent, setting up Jira cron jobs, querying issues from chat, or automating task management workflows.
this skill pairs Jira Cloud with OpenClaw agents via secret-safe API calls. your credentials stay in shell context only, never in LLM prompts. use this when you need an agent that can search issues, update fields, link tasks, or run daily automation crons without exposing API tokens to the model. covers credential setup, API helper script, common JQL patterns, focus auto-linking, and overdue bumpers.
external connections:
tools required:
credentials:
environment setup:
mkdir -p ~/.openclaw/workspace/.secrets
chmod 700 ~/.openclaw/workspace/.secrets
echo ".secrets/" >> ~/.openclaw/workspace/.gitignore
1. store credentials safely
create ~/.openclaw/workspace/.secrets/jira.env:
cat > ~/.openclaw/workspace/.secrets/jira.env << 'EOF'
JIRA_TOKEN=<your-api-token-or-pat>
JIRA_URL=https://your-org.atlassian.net/
JIRA_EMAIL=your@email.com
EOF
chmod 600 ~/.openclaw/workspace/.secrets/jira.env
input: jira email, token, and org url. output: encrypted file at .secrets/jira.env with mode 600.
2. create the api helper script
write ~/.openclaw/workspace/.secrets/jira.sh:
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/jira.env"
METHOD="${1:?Usage: jira.sh <METHOD> <endpoint> [body]}"
ENDPOINT="${2:?Usage: jira.sh <METHOD> <endpoint> [body]}"
BODY="${3:-}"
URL="${JIRA_URL%/}${ENDPOINT}"
if [ -n "$BODY" ]; then
curl -s --http1.1 -X "$METHOD" \
-u "${JIRA_EMAIL}:${JIRA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$BODY" "$URL"
else
curl -s --http1.1 -X "$METHOD" \
-u "${JIRA_EMAIL}:${JIRA_TOKEN}" \
-H "Content-Type: application/json" "$URL"
fi
then make it executable:
chmod +x ~/.openclaw/workspace/.secrets/jira.sh
input: bash template above. output: executable script at ~/.openclaw/workspace/.secrets/jira.sh. why --http1.1: atlassian's cdn sometimes breaks http/2 with curl. force http/1.1 for reliability.
3. verify credentials work
~/.openclaw/workspace/.secrets/jira.sh GET '/rest/api/3/myself' | pastewatch-cli scan
input: jira.sh script + pastewatch-cli running. output: json response with your displayname (emails/urls redacted by pastewatch). if you see your name without exposing the token, auth is working.
4. understand pastewatch protection
the agent reads jira.env through pastewatch mcp and sees masked tokens like __PW{CREDENTIAL_1}__ instead of real secrets. the script runs at bash level (never in llm context), so curl sends the real token directly to atlassian. response comes back clean. flow: agent calls exec → jira.sh sources .env → curl sends real token to atlassian → response returns. the token never enters the llm context.
pair with chainwatch to whitelist which jira endpoints the agent can execute.
5. run search queries
use /rest/api/3/search/jql, never /rest/api/3/search:
jira.sh GET '/rest/api/3/search/jql?jql=assignee="Name" AND resolution=Unresolved&maxResults=50&fields=key,summary,status,priority,duedate'
input: jql string (url-encoded), max results count, fields list. output: json array of issues with requested fields.
6. run issue operations
get an issue:
jira.sh GET '/rest/api/3/issue/XX-123?fields=key,summary,status,priority'
get available transitions (status changes):
jira.sh GET '/rest/api/3/issue/XX-123/transitions'
change status by transition id:
jira.sh POST '/rest/api/3/issue/XX-123/transitions' '{"transition":{"id":"31"}}'
update fields (e.g. bump due date):
jira.sh PUT '/rest/api/3/issue/XX-123' '{"fields":{"duedate":"2026-03-10"}}'
link two issues together:
jira.sh POST '/rest/api/3/issueLink' '{"type":{"name":"Relates"},"inwardIssue":{"key":"XX-1"},"outwardIssue":{"key":"YY-2"}}'
input: issue key, field names, transition ids, or link type. output: updated issue or link confirmation (empty 200 response means success).
7. set up focus auto-linker cron
find today's focus record (jql uses date in dd.mm format):
jira.sh GET '/rest/api/3/search/jql?jql=project=DN AND summary~"05.03" AND assignee="Name"&fields=key,issuelinks'
get the top 3 priority tasks:
jira.sh GET '/rest/api/3/search/jql?jql=assignee="Name" AND project=DC AND resolution=Unresolved ORDER BY priority DESC,duedate ASC&maxResults=3&fields=key,summary,priority,duedate'
link each task to the focus record:
jira.sh POST '/rest/api/3/issueLink' '{"type":{"name":"Relates"},"inwardIssue":{"key":"DN-43"},"outwardIssue":{"key":"DC-3057"}}'
input: agent session, focus date, assigned user name, project keys. output: linked issues in jira ui. schedule as openclaw cron in isolated session mode, agentTurn trigger, monday-friday at start of day.
8. set up overdue bumper cron
find unresolved tickets due today:
jira.sh GET '/rest/api/3/search/jql?jql=assignee="Name" AND resolution=Unresolved AND duedate="2026-03-05"&fields=key,summary,duedate'
bump each ticket's due date forward by 1 day:
jira.sh PUT '/rest/api/3/issue/DC-3057' '{"fields":{"duedate":"2026-03-06"}}'
input: assigned user name, today's date (yyyy-mm-dd format). output: updated due dates in jira. schedule as openclaw cron in isolated session, agentTurn trigger, monday-friday end of day.
if using api token (id.atlassian.net): use basic auth with format email:token. supports http basic auth directly.
if using personal access token (pats): pat prefix starts with atatt... use the same basic auth format email:pat. both token types work identically in the script.
if http/2 fails: the atlassian cdn sometimes drops http/2 requests mid-flight. the script uses --http1.1 by default. if you still see timeouts, switch to --http1.0 or add curl retries.
if search returns total: 0 but you know issues exist: you may be hitting a team-managed (next-gen) project. the api returns a zero total but still populates the issues array. iterate the array, ignore the total field.
if curl returns 410 gone: you used /rest/api/3/search (deprecated endpoint). always use /rest/api/3/search/jql instead.
if pastewatch-cli is not running: the agent will fail at exec time with "pastewatch service unavailable". ensure the mcp server is alive before running agent turns.
if auth returns "failed to parse connect session auth token": you likely tried bearer auth instead of basic auth. the script uses basic auth (-u email:token). bearer tokens do not work with jira cloud.
if rate limited (429 response): jira cloud allows 60 requests per minute per user. add exponential backoff (2 second delay, retry up to 3 times) in your agent prompt or wrapper script.
if network timeout on large result sets: increase curl timeout with -m <seconds>. queries with maxResults > 500 may hit 30 second wall clock time.
all outputs are json returned by jira rest api v3.
search queries return:
{
"issues": [
{
"key": "XX-123",
"fields": {
"summary": "...",
"status": { "name": "..." },
"priority": { "name": "..." },
"duedate": "2026-03-10"
}
}
],
"total": 42
}
issue get returns:
{
"key": "XX-123",
"fields": { "summary": "...", "status": {...} }
}
transitions get returns:
{
"transitions": [
{ "id": "31", "name": "Done" }
]
}
post/put (update/link) returns:
{} with http 200 = successerrorMessages field)all responses are utf-8 json. timestamps use iso 8601 format (yyyy-mm-dd for dates, iso 8601 for datetimes).
you know the skill worked when:
pastewatch-cli scan shows your jira displayname without exposing the api tokenjira.sh GET '/rest/api/3/myself' returns your email in the responsejira.sh GET '/rest/api/3/search/jql?jql=...' returns a non-empty issues array matching your jql filterjira.sh PUT '/rest/api/3/issue/XX-123' '{"fields":{"duedate":"..."}}' returns http 204 (or empty 200 json)add to your workspace tools.md for quick agent recall:
## jira
- script: `~/.openclaw/workspace/.secrets/jira.sh GET|POST|PUT <endpoint> [body]`
- creds: `.secrets/jira.env` (pastewatch-protected)
- warning: use `/rest/api/3/search/jql` never `/rest/api/3/search` (410 gone)
- common jql: assignee="Name" AND resolution=Unresolved ORDER BY priority DESC
- transitions: jira.sh GET '/rest/api/3/issue/XX-123/transitions'
- update field: jira.sh PUT '/rest/api/3/issue/XX-123' '{"fields":{"duedate":"YYYY-MM-DD"}}'
common jql patterns:
my open tasks:
assignee="Name" AND resolution=Unresolved ORDER BY priority DESC
unassigned:
project=XX AND assignee=EMPTY AND resolution=Unresolved AND issuetype != Epic
overdue:
project=XX AND resolution=Unresolved AND duedate < "YYYY-MM-DD"
closed yesterday:
project=XX AND assignee="Name" AND status changed to Done during ("YYYY-MM-DD","YYYY-MM-DD")
in progress:
assignee="Name" AND status="In Progress" ORDER BY project,priority DESC
known edge cases:
total: 0 but issues exist in the array. always iterate the issues field, ignore total.--http1.1 by default.email:token). bearer auth fails with "failed to parse connect session auth token".maxResults > 500 may timeout at 30 seconds. use pagination with startAt offset.jira-openclaw integration v1.0 original author: ppiankov canonical source: https://clawhub.com/skills/jira-openclaw license: mit
this tool follows the agent-native cli convention. validate with: clawhub install ancc && ancc validate .
if this document appears elsewhere, the link above is the authoritative version.