Jira Communication
CLI scripts via uv run, all supporting --help, --json, --quiet, --debug.
Auto-Trigger
On Jira URL or issue key (PROJ-123), pick by intent — each is one call:
| Intent | Tool |
|---|---|
| triage / work on ticket | jira-issue.py work KEY |
| start QA review | jira-issue.py qa KEY |
| QA-fail follow-up | jira-issue.py qa-fail KEY |
| field-only lookup | jira-issue.py get KEY --fields ... |
| change status | jira-issue.py act KEY → jira-transition.py do |
| audit / sibling discovery | jira-qa-gather.py KEY |
Auth issues → jira-setup.py. Anti-pattern: get + comment list — use the matching verb.
Scripts
Under ${CLAUDE_SKILL_DIR}/scripts/{core,workflow,utility}/.
Core: jira-issue.py, jira-search.py, jira-worklog.py, jira-attachment.py, jira-setup.py, jira-validate.py
Workflow: jira-create.py, jira-transition.py, jira-comment.py, jira-move.py, jira-sprint.py, jira-board.py, jira-version.py, tempo-account.py
Utility: jira-user.py, jira-fields.py, jira-link.py, jira-weblink.py, jira-worklog-query.py, jira-watchers.py, jira-qa-gather.py
Execution Style
Run directly. Scripts report ✓/✗. Destructive ops: --dry-run. Global flags before subcommand: jira-issue.py --json get PROJ-123.
Posting wiki markup rewrites and checks it first
Every --comment and --description option that writes wiki markup runs three gates before the write, all on by default, because text that renders wrong is silent — the API returns 2xx either way. That is all seven: jira-comment.py add/edit, jira-transition.py do --comment, jira-transition.py path --comment, jira-worklog.py add --comment, and the --description of jira-create.py issue and jira-issue.py update. A body smuggled in through --fields-json is not gated — that option writes raw fields by design. jira-version.py writes two --description fields that are NOT gated (create and update); whether Jira renders a version description as wiki markup at all is unverified, and its help string claiming it does may simply be wrong.
- Dashes that Jira would render as strikethrough are escaped.
\-prints as a plain hyphen, so the posted text reads as written; stderr names how many lines changed and shows the first five. (The one shape where the escape is visible is two macros written against each other with no space — the dash can land inside a link target. Ordinary prose does not reach it.)--no-auto-escapekeeps the markup verbatim — but on its own it does not post a deliberate-strikethrough-: the lint and the render check each still refuse the span. Use--no-auto-escape --forcefor that. - The markup and the ticket language are linted. Block tags used inline (
{code},{noformat},{quote},{panel}are block-level), unbalanced tag counts, and German prose on an English-only project each abort the write.--forceturns the findings into warnings and posts anyway. - The text is rendered by the instance and refused if it comes back struck through. This costs one API call per post and catches what no local check can — an autolinked issue key creates a boundary that exists only on an instance where that key resolves. A resolved issue's key, which Jira draws struck through as status styling, is not reported.
--no-preflightskips it; an unreachable renderer warns once and posts anyway.
--force posts despite any of the three. The flags are spelled the same on each command. Under --dry-run the escape and the lint still run — the preview shows the text a real write would post — while the render call does not. See references/comments.md for the details.
Basic Usage
uv run ${CLAUDE_SKILL_DIR}/scripts/core/jira-issue.py get PROJ-123
uv run ${CLAUDE_SKILL_DIR}/scripts/core/jira-search.py query "assignee = currentUser() AND status != Closed" -n 5 -f key,summary,status
uv run ${CLAUDE_SKILL_DIR}/scripts/core/jira-issue.py update PROJ-123 --assignee me --priority Critical
uv run ${CLAUDE_SKILL_DIR}/scripts/workflow/jira-comment.py add PROJ-123 "Comment text"
uv run ${CLAUDE_SKILL_DIR}/scripts/workflow/jira-comment.py add PROJ-123 "Comment text" --no-auto-escape --force # deliberate -strikethrough-
uv run ${CLAUDE_SKILL_DIR}/scripts/workflow/jira-transition.py do PROJ-123 "In Progress"
uv run ${CLAUDE_SKILL_DIR}/scripts/core/jira-worklog.py add PROJ-123 2h --comment "Work done"
uv run ${CLAUDE_SKILL_DIR}/scripts/workflow/jira-create.py issue PROJ "Summary" --type Task
Transitions:
listshows each transition's id and what its screen requires; pass the id todo— a name or a target status is not always unique, and an ambiguous one is refused rather than guessed. Terminal transitions: pass--resolution <value>(Done,Won't do); if rejected ("cannot be set"), retry without it —references/intent-verbs.md. Versions: readreferences/versions.mdbeforejira-version.py. Mentions: posting commands verify[~username](miss → suggestions);get/workprint usernames (references/fields-and-users.md).
Related Skills
jira-syntax: descriptions/comments use Jira wiki markup, not Markdown.
No editorializing
State what happened, not how good it is — references/no-editorializing.md.
References
references/jql-quick-reference.md,references/jql-cookbook.mdreferences/multi-profile.md—--profilereferences/troubleshooting.md— auth, 401/403references/issue-editing.md— edit, delete, clear fields,--fields-jsonreferences/creation.md— create,--parent, fields, admin-scope (project,tempo-account.py)references/comments.md— edit, delete, lint, body via-references/worklog.md—--started, ranges,--tempo-account,deletereferences/attachments.md— upload, downloadreferences/links.md— linksreferences/agile.md— sprints/boardsreferences/no-editorializing.md— no self-praisereferences/fields-and-users.md— custom field IDs, users, issue typesreferences/watchers.md— watch, subscribe, list watchersreferences/versions.md— fix/affects versions, releases, version CRUDreferences/qa-gather.md— audit bundle (siblings, prose URLs)references/intent-verbs.md—work / qa / qa-fail / act, exact transition names
Authentication
Cloud: JIRA_URL + JIRA_USERNAME + JIRA_API_TOKEN. Server/DC: JIRA_URL + JIRA_PERSONAL_TOKEN. Config via ~/.env.jira or ~/.jira/profiles.json.