jira-communication · diff
v4.2.0 to v4.3.0
1 added, 1 removed. Audit A to A.
---
# SPDX-License-Identifier: CC-BY-SA-4.0
# SPDX-FileCopyrightText: Netresearch DTT GmbH
name: jira-communication
description: "Use when handling Jira issues, sprints, boards, links, fields, worklogs, attachments, or users, or on any Jira intent without a key (\"create/find a ticket\", \"pick a project\"). Auto-triggers on Jira URLs and issue keys (PROJ-123). Also use when MCP Atlassian tools fail or are unavailable for Jira Server/DC."
license: "(MIT AND CC-BY-SA-4.0). See LICENSE-MIT and LICENSE-CC-BY-SA-4.0"
compatibility: "Requires python 3.11+, uv. Jira Server/DC or Cloud instance with API access."
metadata:
author: Netresearch DTT GmbH
- version: "4.2.0"
+ version: "4.3.0"
repository: https://github.com/netresearch/jira-skill
allowed-tools: Bash(uv run ${CLAUDE_SKILL_DIR}/scripts/*) Bash(${CLAUDE_SKILL_DIR}/scripts/*) Read Write
---
# 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 / "am I reviewing my own work?" | `jira-qa-gather.py KEY` |
Auth issues → `jira-setup.py`. **Anti-pattern:** `get` + `comment list` — use the matching verb.
**`work` flags a ticket you have not taken:** when it is not assigned to you, or its status says nobody works on it (To Do category, a review status such as QA, or resolved), a `!! CLAIM KEY` notice on stderr (`claim` in `--json`) lists the commands — `jira-issue.py update KEY --assignee me`, then the start or reopen transition from `jira-transition.py list KEY`. Run them before your first comment, measurement or edit. `jira-comment.py add` warns once before posting when the ticket is neither yours nor in a working status; it still posts.
## 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`.
## Every write ends with the ticket's state
After a successful write, these commands print the ticket's state to stderr: `jira-comment.py add`/`edit`, `jira-transition.py do`/`path`, `jira-issue.py update`, `jira-worklog.py add`, `jira-weblink.py add`, `jira-link.py create` (FROM_KEY, which is `--target` in the named form), `jira-attachment.py add` and `jira-create.py issue`:
```text
── PROJ-123 · Task · Open · resolution: – · assignee: unassigned
time: logged 15m / estimate – / remaining – · labels: –
(!) ticket is "Open" while you work on it: claim it (assign + start work)
```
**Read the `(!)` lines and act on them before reporting the work done.** They appear when the ticket is Open or Backlog while you write to it, unassigned while In Progress, assigned to someone else while you write to it, already done while you write to it, done without a resolution, carries a resolution while not done, or has more time logged than estimated. An unassigned ticket in a review status such as QA gets no hint: it waits for the team pool by design. After a transition or a create only the resolution and time checks run, because the status and assignee are what the command just set.
With `--json` the same facts arrive as a `ticket_state` field in the output object, beside the keys it already had: `key`, `status`, `status_category`, `issuetype`, `resolution`, `assignee`, `assignee_is_you`, `time_spent_seconds`, `original_estimate_seconds`, `remaining_estimate_seconds`, `labels` and `hints`, the last being the `(!)` lines as strings. **Read `ticket_state.hints` as you would the `(!)` lines.** `jira-attachment.py add --json` prints a list, so its state goes to stderr as text instead. `--quiet` prints no state.
The state costs one extra read per write (`jira-comment.py add` reads once more before posting, for its claim warning) and never fails the command: a lookup error prints one line, or becomes `"ticket_state": {"key": …, "error": "<type>"}` in JSON. `JIRA_TICKET_STATE=0` turns it off everywhere, together with the warning `jira-comment.py add` prints before posting; the `work` claim notice stays. `logged` is Jira's own time tracking: time booked elsewhere shows only once it is synced into a Jira worklog.
## 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.
1. **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-escape` keeps 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 --force` for that.
2. **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. `--force` turns the findings into warnings and posts anyway.
3. **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-preflight` skips 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. All seven also take `--dry-run`: the escape and the lint still run — the preview shows the text a real write would post — while the render call and the write do not. See `references/comments.md` for the details.
## Basic Usage
```bash
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**: `list` shows each transition's id and what its screen requires; pass the **id** to `do` — 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**: read `references/versions.md` before `jira-version.py`.
> **Mentions**: posting commands verify `[~username]` (miss → suggestions); `get`/`work` print 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.md`
- `references/multi-profile.md` — `--profile`
- `references/troubleshooting.md` — auth, 401/403
- `references/issue-editing.md` — edit, delete, clear fields, `--fields-json`
- `references/creation.md` — create, `--parent`, fields, admin-scope (`project`, `tempo-account.py`)
- `references/comments.md` — edit, delete, lint, body via `-`, restricted comments (`--visibility`)
- `references/worklog.md` — `--started`, ranges, `--tempo-account`, `delete`
- `references/attachments.md` — upload, download
- `references/links.md` — links
- `references/agile.md` — sprints/boards
- `references/no-editorializing.md` — no self-praise
- `references/fields-and-users.md` — custom field IDs, users, issue types, screen fields (`jira-fields.py meta`)
- `references/watchers.md` — watch, subscribe, list watchers
- `references/versions.md` — fix/affects versions, releases, version CRUD
- `references/qa-gather.md` — audit bundle (siblings, prose URLs, self-review check from changelog + worklog — not the assignee)
- `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`.