Table of Contents generated with DocToc
Capability: contract:tracker
Kind: implementation
Vendor: Atlassian
JIRA REST helpers for the issue-* skill family. Adopters with JIRA-based issue trackers wire this in as their tracker bridge; adopters using GitHub Issues or other trackers contribute a parallel tools/<tracker>/ directory.
The bridge provides both read and write subcommands. Write operations require JIRA_API_TOKEN and follow the same write-path discipline as the GitHub bridge: every mutation is gated on explicit user confirmation in the calling skill — the bridge only executes confirmed actions.
PATH (groovy tools/jira/bridge.groovy …); @Grab pulls the HTTP-client dependencies on first run, no separate install step. Python 3.11+ via uv is needed only for the pytest test harness.groovy (4.x — the @Grab coordinate uses the org.apache.groovy group ID); uv only to run the tests.ISSUE_TRACKER_URL (required) and ISSUE_TRACKER_PROJECT exported by the caller; write subcommands require JIRA_API_TOKEN (JIRA_AUTH_SCHEME = Basic default, or Bearer for ASF PATs). Anonymous-read trackers need no auth for read subcommands.<issue-tracker> JIRA host (e.g. issues.apache.org/jira); @Grab reaches Maven Central on first run to resolve dependencies.groovy on PATH for the pytest suite — tests auto-skip when Groovy is absent.tools/jira/ ├── README.md (this file) ├── bridge.groovy (Groovy reference implementation) ├── pyproject.toml (Python test harness config) ├── src/jira_bridge/ (package stub for test harness) └── tests/ (pytest test suite)
Other languages (Python, Bash + curl) are welcome via PR.
groovy tools/jira/bridge.groovy <subcommand> [args]
The Groovy implementation uses @Grab for HTTP client dependencies — no separate install step. Requires Groovy 4.x or newer on PATH (the @Grab coordinate uses org.apache.groovy, which is the Groovy 4 group ID).
search <JQL>Run a JQL query against <issue-tracker> and emit matching issues as JSON to stdout:
groovy tools/jira/bridge.groovy search \ 'project = <KEY> AND status = Open AND resolution = Unresolved'
Output (truncated):
{ "total": 42, "issues": [ {"key": "<KEY>-9999", "title": "...", "status": "Open", "components": [...], "fixVersion": "..."}, ... ] }
The --limit <N> flag caps the result count (default: 50).
issue <KEY>Fetch a single issue's full state (body, comments, attachments list, labels, fixVersion, etc.) as JSON:
groovy tools/jira/bridge.groovy issue <KEY>-9999
Output is the JIRA REST /rest/api/2/issue/<KEY> response, shaped for skill consumption.
projectsList the JIRA projects available at the configured <issue-tracker> URL. Useful during initial adoption to confirm the project key is correct.
groovy tools/jira/bridge.groovy projects
All write subcommands require JIRA_API_TOKEN to be set and follow the write-path discipline described below.
comment <KEY> --body-file <path>Post a comment on an issue. The comment body is read from a file to avoid shell-quoting issues:
groovy tools/jira/bridge.groovy comment FOO-9999 --body-file /tmp/comment.txt
Output:
{"ok": true, "key": "FOO-9999", "commentId": "12345"}
transition <KEY> <transition-name>Move an issue to a new workflow state. The transition name is resolved case-insensitively against the issue's available transitions:
groovy tools/jira/bridge.groovy transition FOO-9999 "Resolve Issue"
Output:
{"ok": true, "key": "FOO-9999", "transition": "Resolve Issue", "transitionId": "21"}
If the transition name does not match any available transition, the command exits with an error listing the valid names.
label <KEY> --add <name> --remove <name>Toggle labels on an issue. Both --add and --remove can be specified multiple times in a single call:
groovy tools/jira/bridge.groovy label FOO-9999 --add security --remove needs-triage
Output:
{"ok": true, "key": "FOO-9999", "added": ["security"], "removed": ["needs-triage"]}
Uses JIRA's atomic update API — no read-modify-write race.
assign <KEY> <username>Set the assignee on an issue. Data Center only — Cloud uses accountId, which is not currently supported:
groovy tools/jira/bridge.groovy assign FOO-9999 jdoe
Output:
{"ok": true, "key": "FOO-9999", "assignee": "jdoe"}
field <KEY> <field-name> --value <value> / --value-json <json>Edit a single field (including custom fields) on an issue. Use --value for plain string/number values. Use --value-json for structured values (priority, version, single-select, user picker, etc.):
# String value groovy tools/jira/bridge.groovy field FOO-9999 customfield_10100 --value "high" # Structured value (e.g. priority) groovy tools/jira/bridge.groovy field FOO-9999 priority --value-json '{"name":"High"}' # Array value (e.g. fixVersions) groovy tools/jira/bridge.groovy field FOO-9999 fixVersions --value-json '[{"name":"1.2.3"}]'
Output:
{"ok": true, "key": "FOO-9999", "field": "priority", "value": {"name": "High"}}
attach <KEY> <file>Attach a file to an issue:
groovy tools/jira/bridge.groovy attach FOO-9999 /tmp/report.txt
Output:
{"ok": true, "key": "FOO-9999", "attachments": [{"id": "99", "filename": "report.txt"}]}
The bridge reads its configuration from the environment:
| Variable | Notes |
|---|---|
ISSUE_TRACKER_URL | required; e.g. https://issues.apache.org/jira |
ISSUE_TRACKER_PROJECT | project key (e.g. FOO) |
JIRA_API_TOKEN | required for write subcommands — see auth notes below |
JIRA_AUTH_SCHEME | Basic (default) or Bearer — see auth notes below |
The caller is responsible for exporting these (a skill resolves them from <project-config>/issue-tracker-config.md and passes them in the environment). Direct file-fallback inside the bridge is a possible future enhancement — it is not implemented today; the bridge exits if ISSUE_TRACKER_URL is unset.
For anonymous-read trackers, no auth is required for read subcommands. Write subcommands always require JIRA_API_TOKEN and exit with an error if it is unset.
Authentication: This bridge targets JIRA Data Center (DC), specifically ASF JIRA at issues.apache.org/jira. Cloud is not currently supported (assign uses DC name, not Cloud accountId).
JIRA_API_TOKEN to the base64-encoded username:password or username:pat string.JIRA_AUTH_SCHEME=Bearer and JIRA_API_TOKEN to the raw PAT string. ASF JIRA DC PATs use Authorization: Bearer <pat>.Every subcommand emits JSON to stdout on success, or a non-zero exit code with a human-readable error to stderr on failure.
Write subcommands return {"ok": true, "key": "<KEY>", ...} with operation-specific fields as documented per subcommand above.
The output schema is documented per subcommand above. Skills parse the JSON via standard JSON tooling — no special envelope, no wrapper.
The bridge executes mutations but does not decide whether to mutate. Every write operation is gated on explicit user confirmation in the calling skill — the bridge only executes confirmed actions.
This mirrors the GitHub bridge's write-path discipline (see tools/github/operations.md): skills surface the proposed action to the maintainer, wait for confirmation, then call the bridge to execute.
The test suite uses a mock HTTP server and requires groovy on PATH. Tests are skipped automatically when Groovy is not available.
cd tools/jira uv run pytest
issue-triage — primary consumer (selector resolution + per-issue fetch).issue-reassess — campaign-level consumer (pool fetch).security-issue-sync — write-path consumer (label, transition, comment, field updates).security-issue-invalidate — write-path consumer (close with label + comment).tools/github/operations.md — write-path discipline reference.<project-config>/issue-tracker-config.md — the adopter's tracker URL + project key.