| name | jira |
| description | Create, update, comment, transition, search, link, assign, and attach files on Jira tickets. Use when the user wants to "create a Jira ticket", "open a ticket", "commenta ticket", "sposta/transisci ticket", "trova ticket", "cerca su Jira", "assegna ticket", "collega ticket", "allega a Jira", "chiudi ticket", "ticket SMARTCHAT-123", "riapri ticket", or shares a Jira URL like `https://*.atlassian.net/browse/*`. Triggers on Italian and English equivalents. Not for bug-fixing workflow (use /bug-fixer for that). |
/jira — Jira Tickets & Tasks
Standalone Jira tooling for create / update / comment / transition / search / link / assign / attach. Backed by the jira-agent package (TypeScript, Bun). Its location is machine-dependent — resolve it at invocation time (see How to invoke).
Trigger
Invoke when Andrea says any of:
- Create: "crea ticket Jira", "apri un task", "open a ticket", "new Jira issue", "create ticket"
- Update: "aggiorna ticket", "cambia priorità", "add label", "modifica descrizione"
- Comment: "commenta SMARTCHAT-123", "add comment", "lascia un commento"
- Transition: "sposta in In Progress", "chiudi ticket", "move to Done", "transition", "riapri"
- Search: "trova i miei ticket aperti", "cerca ticket di Elisa", "my open tickets", "search JQL"
- Link: "collega questi ticket", "blocca", "relates to", "is blocked by"
- Assign: "assegna a Andrea", "assign to me", "unassign"
- Attach: "allega screenshot", "upload a Jira"
- Watch: "polla ticket nuovi", "watch my queue"
Also auto-trigger on any Jira URL (*.atlassian.net/browse/*) or issue key ([A-Z]+-\d+ pattern in context).
Do NOT auto-trigger for bug-fixing pipelines (screenshot comparison, iterative fix, pattern match against known bug types) — that's /bug-fixer's job. /bug-fixer uses /jira internally for ticket I/O, but you shouldn't duplicate its work.
Prerequisites
Credentials live in a single, machine-local env file: ~/.config/jira-agent.env (mode 0600, never committed). It exports JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_API_TOKEN. The token is created at https://id.atlassian.com/manage-profile/security/api-tokens.
- On the X1 (Linux, main runner) and the Mac Air the file already exists with the current token (last rotated 2026-06-01). The Mac's
~/.zshrc also sources it, so interactive shells inherit the vars.
jira-agent itself lives at a machine-dependent path — resolve it into $JIRA_AGENT (see below). Linux: ~/Development/claude/jira-agent; Mac: /Users/administrator/Development/Claude/jira-agent.
Credentials are read from process.env inside the handler — jira-agent does NOT load a dotenv file itself, so the env file must be sourced before each invocation (the snippet below does this). Do NOT fall back to raw curl + dangerouslyDisableSandbox — use the handler. If a handler errors with "JIRA_*_not set", check that ~/.config/jira-agent.env exists and is readable.
How to invoke
Preferred: direct Bash call to the CLI. Always prefix with the resolver snippet so the path and credentials are set regardless of machine:
JIRA_AGENT=$(for d in "$HOME/Development/claude/jira-agent" "/Users/administrator/Development/Claude/jira-agent"; do [ -d "$d" ] && echo "$d" && break; done)
set -a; source ~/.config/jira-agent.env; set +a
bun "$JIRA_AGENT/src/bin/jira-agent.ts" <tool> '<json-params>'
The CLI prints a ToolResult JSON to stdout ({success, tool, data|error}) and returns exit code 0/1. Parse the data field for useful info.
The examples below omit the two setup lines for brevity — always run them first in the same Bash call.
Tools
1. jira.create — Open a new issue
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.create '{
"projectKey": "SMARTCHAT",
"summary": "Short title",
"issueType": "Task",
"description": "## Context\nMarkdown supported (headings, lists, code, tables, links, bold, italic).\n\n## Steps\n- step 1\n- step 2",
"labels": ["tech-debt", "mobile"],
"priority": "Medium",
"assignee": "andrea@example.com",
"parentKey": "SMARTCHAT-900"
}'
issueType: defaults to "Task". Use "Bug", "Story", "Epic", "Sub-task" etc.
description: Markdown → ADF conversion internal. Supports headings, paragraphs, bullet/ordered lists, inline code, bold, italic, links, fenced code blocks with language, GFM tables, horizontal rules. Unknown syntax degrades to plain paragraphs, never throws.
assignee: accepts accountId (contains :) or email (resolved via /user/search, exact match preferred). Assignment failures are non-fatal — ticket is still created, warning is printed. Retry with jira.assign if needed.
- Returns
{key, id, url, assignee?}.
2. jira.update — Modify an existing issue
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.update '{
"issueKey": "SMARTCHAT-123",
"summary": "new title",
"description": "new markdown body",
"priority": "High",
"addLabels": ["urgent"],
"removeLabels": ["triage"]
}'
labels: replaces the full set. Use addLabels/removeLabels for additive changes.
- Any combination of fields is allowed. At least one must be set.
3. jira.comment — Post a comment
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.comment '{
"issueKey": "SMARTCHAT-123",
"body": "**Update:** fix shipped in v1.15.5 (build 95).\n\nSee PR #112."
}'
- Markdown supported (same converter as
jira.create).
4. jira.transition — Change status
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.transition '{
"issueKey": "SMARTCHAT-123",
"to": "Done",
"resolution": "Done"
}'
to: matched case-insensitively against either transition name or target status name. If not found, the error message lists all available transitions with their target statuses.
resolution: optional, needed when transitioning to closed statuses that require a resolution field (varies by workflow).
- Alternative:
transitionId for exact API id (skips name matching).
5. jira.search — JQL or structured query
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.search '{
"project": "SMARTCHAT",
"assignee": "currentUser",
"statuses": ["To Do", "In Progress"],
"maxResults": 20
}'
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.search '{
"jql": "project = SMARTCHAT AND labels = tech-debt ORDER BY created DESC",
"maxResults": 10
}'
- Structured fields (
project, assignee, statuses, issueTypes, labels, text) combine with AND. Use jql for full control.
assignee: "currentUser" maps to assignee = currentUser().
6. jira.link — Connect two issues
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.link '{
"fromKey": "SMARTCHAT-100",
"toKey": "SMARTCHAT-200",
"type": "Blocks",
"comment": "Blocked until telemetry lands"
}'
- Semantics:
fromKey is the outward issue (e.g. "SMARTCHAT-100 blocks SMARTCHAT-200" → fromKey=100, toKey=200, type=Blocks).
- Default
type: "Relates". Other common names: "Blocks", "Duplicate", "Clones", "Cause". Availability depends on the project's link types.
7. jira.assign — Assign / unassign
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.assign '{
"issueKey": "SMARTCHAT-123",
"assignee": "andrea@example.com"
}'
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.assign '{
"issueKey": "SMARTCHAT-123",
"assignee": null
}'
8. jira.attach — Upload files to an issue
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.attach '{
"issueKey": "SMARTCHAT-123",
"files": ["/path/to/screenshot.png", "/path/to/log.txt"]
}'
- Multipart upload with
X-Atlassian-Token: no-check header (required by the Jira REST API).
9. jira.fetch — Read an issue (+ optionally download attachments)
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.fetch '{
"url": "https://team.atlassian.net/browse/SMARTCHAT-123",
"downloadAttachments": true
}'
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.fetch '{
"issueKey": "SMARTCHAT-123"
}'
- Returns full issue: summary, description (ADF → plain text), status, priority, type, labels, assignee, reporter, comments, attachments metadata, created/updated timestamps.
downloadAttachments: true saves to ~/.claude/data/jira-agent/attachments/<KEY>/ by default (override with attachmentsDir). Only image/video/log/txt extensions by default (override with attachmentExtensions).
10. jira.watch — Poll for new tickets in a queue
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.watch '{
"project": "SMARTCHAT",
"statuses": ["To Do", "Open"],
"issueTypes": ["Bug"],
"maxTickets": 5
}'
- State persists in
~/.claude/data/jira-agent/jira-watch-state.json. Already-seen tickets are filtered out.
reset: true clears state and returns zero tickets. Useful after fixing everything in the queue.
- Use
jira.watch_done to mark a ticket as in_progress/fixed/partial/failed/done and optionally attach a PR URL + notes.
jira.watch_status returns the current state + counters.
Common workflows
Create a tech-debt ticket for SmartPMS
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.create '{
"projectKey": "CIAOB",
"summary": "feat(smartpms): OTA updates via expo-updates",
"issueType": "Story",
"description": "## Context\nReplicate the OTA setup that ships SmartChat.\n\n## Scope\n- Install `expo-updates ~0.28.18` + `expo-application ^6.1.5`\n- Add `updates` block + `runtimeVersion` to `app.json`\n- Wire `channel` in `eas.json` (preview→staging, production-store→production)\n- Enable updates in iOS Expo.plist + Android AndroidManifest.xml\n- Add non-blocking check in `src/services/otaUpdates.ts`\n\n## Acceptance\n- `eas update --branch staging` delivers a JS change to an installed staging build\n- Production builds accept `channel=production` OTAs",
"labels": ["smartpms", "infrastructure", "ota"],
"priority": "Medium"
}'
Move to "In Progress" + post a status comment
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.transition '{"issueKey":"CIAOB-123","to":"In Progress"}'
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.comment '{"issueKey":"CIAOB-123","body":"Starting work. Branch: `feat/CIAOB-123-ota-updates`. ETA: 2 giorni."}'
Find all my open bugs in SmartChat
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.search '{
"project":"SMARTCHAT",
"assignee":"currentUser",
"issueTypes":["Bug"],
"statuses":["To Do","In Progress","Reopened"]
}'
Close a ticket with a resolution
bun "$JIRA_AGENT/src/bin/jira-agent.ts" jira.transition '{"issueKey":"CIAOB-123","to":"Done","resolution":"Done"}'
Consumption from other skills (TypeScript direct import)
Skills that live inside a TypeScript project can import directly from jira-agent without shelling out to the CLI. This is how /bug-fixer consumes it after the extraction:
import { jiraCreateHandler } from 'jira-agent/tools/create'
import { markdownToAdf } from 'jira-agent/lib/markdown-to-adf'
const result = await jiraCreateHandler({
projectKey: 'SMARTCHAT',
summary: 'Fix X',
description: '## Context\n...',
})
package.json: "jira-agent": "file:../../../jira-agent".
Rules
- Never fall back to raw
curl + dangerouslyDisableSandbox. The handler reads credentials from env inside the skill script; Bash-side credential probing is unnecessary and defeats the sandbox.
- Pass Markdown, not ADF, for descriptions/comments. The converter handles ~95% of cases. Use
descriptionAdf/bodyAdf raw only if you need constructs the converter doesn't support (blockquotes, nested lists, panels).
- Assignment failure is non-fatal on
jira.create. If the email doesn't resolve, the ticket is still created; the caller can retry with jira.assign.
- Keep issue keys in UPPERCASE. The Jira API is case-sensitive on project prefixes.
- Never delete issues from this skill. There's no
jira.delete. If a ticket is wrong, transition it to "Cancelled"/"Won't Do" via jira.transition instead.
Troubleshooting
"JIRA_BASE_URL not set" → the invocation didn't source ~/.config/jira-agent.env (see How to invoke), or the file is missing on this machine. Verify with ls -l ~/.config/jira-agent.env and re-run the resolver snippet.
"Jira API 401" → API token expired or wrong email. Regenerate at https://id.atlassian.com/manage-profile/security/api-tokens.
"Jira API 403" → account lacks permission on the project. Check with your Jira admin.
"No transition matching X" → the error lists available transitions. Match exactly (case-insensitively). Workflow transitions are project-specific.
"No Jira user found for X" → email typo, or user is deactivated. Try with accountId instead.