Skip to main content

jira-claude-toolkit

Turn a Jira issue into a Spec-Kit technical specification, from inside Claude Code or from a plain shell.

Install it once, use it in every repository. The toolkit discovers each repository's own Spec-Kit conventions instead of imposing its own.

Jira  →  Jira Client  →  Normalized Issue Context  →  Claude Code
      →  Grill / Clarification  →  Decision  →  Spec-Kit  →  Technical Specification
                                      │
                    ┌─────────────────┼──────────────┬──────────────────┐
                    ▼                 ▼              ▼                  ▼
              CREATE_SPEC       UPDATE_SPEC       NO_OP        NEEDS_CLARIFICATION
                    └─────────────────┘                              / BLOCKED
                        └──► spec.md                                 (no spec)

Quick start

pipx install jira-claude-toolkit          # or: pip install jira-claude-toolkit

cd ~/code/your-project
jira-claude install --config-files        # writes skills + starter config
$EDITOR .jira-claude.yaml                 # base_url, project_key
cp .env.example .env && $EDITOR .env      # JIRA_EMAIL, JIRA_API_TOKEN
jira-claude doctor                        # verify everything

Then in Claude Code:

/jira-speckit PROJ-25

That fetches the ticket, investigates your codebase, grills the requirements, decides whether a specification is actually needed, and — if it is — drives your repository's own Spec-Kit specify command. It produces a specification and nothing else; it never implements the feature.

Commands

jira-claude doctor            # every check: config, Jira, Spec-Kit, skills, secrets
jira-claude validate-env      # configuration only, no network
jira-claude connect           # authenticate and confirm project access
jira-claude ticket PROJ-25    # normalized issue context (Markdown or --json)
jira-claude grill PROJ-25     # clarification questions derived from the ticket
jira-claude decide PROJ-25    # CREATE_SPEC / UPDATE_SPEC / NO_OP / NEEDS_CLARIFICATION / BLOCKED
jira-claude smoke-test PROJ-25  # read-only checks against a REAL Jira site
jira-claude install           # write the Claude Code skills into a repository
jira-claude scan-secrets      # fail if a credential reached a committable file

stdout is data, stderr is diagnostics, exit codes are stable:

jira-claude ticket PROJ-25 --json | jq '.acceptance_criteria'
Code Meaning Code Meaning
0 ok 7 not found
2 usage 8 wrong project
3 missing dependency 9 malformed response
4 config invalid 11 unexpected HTTP status
5 Jira unreachable 12 Spec-Kit missing
6 auth failed 14 secret found

Claude Code commands

Command Purpose
/jira-speckit <TICKET_ID> Jira ticket → codebase investigation → grilling → decision → specification
/jira-connect Diagnostics, when something failed

Status: 1.0.0. Verified against a mock Jira (415 tests, 95% coverage), a CI matrix spanning Python 3.9–3.13 on Ubuntu and Windows, and a live Atlassian site over both REST v2 and v3. See docs/testing.md and CHANGELOG.md for what live data did and did not exercise.

/jira-speckit does not require /jira-connect to have been run. It validates the connection itself and points at /jira-connect only if something breaks. There is no connection-state file: every Jira call authenticates, so a cached "connected" flag could only ever produce a misleading error message.

A Jira ticket does not imply a specification

The workflow ends in an explicit, reportable decision — not in a document by default:

Outcome Meaning
CREATE_SPEC Nothing covers this ticket; write a specification
UPDATE_SPEC One exists but is unfinished; extend it, do not fork it
NO_OP An existing specification already covers the request
NEEDS_CLARIFICATION Blocking questions must be answered first
BLOCKED Something outside the ticket prevents progress
$ jira-claude decide PROJ-25
Jira Issue: PROJ-25
Repository Investigation: COMPLETE
Existing Specification: FOUND
Grill: RESOLVED

Decision: NO_OP

Reason:
Existing specification completely covers this Jira request.

jira-claude decide computes a mechanical proposal from files on disk and ticket fields — it searches the specs directory for a specification citing this Jira key. /jira-speckit then confirms or overrides it after reading the codebase, which is the one part of the pipeline that needs judgement.

Concluding NO_OP is a success. A pipeline that always emits a document emits duplicates.

Exit code 0 means a decision was computed, not that the answer was "yes". Branch on the outcome, never on the exit status:

outcome=$(jira-claude decide PROJ-25 --json | jq -r .outcome)
case "$outcome" in
  CREATE_SPEC|UPDATE_SPEC) run-spec-kit ;;
  NO_OP)                   echo "already specified — nothing to do" ;;
  NEEDS_CLARIFICATION)     echo "needs answers first" ;;
  BLOCKED)                 exit 1 ;;
esac

Failures that prevent a decision — invalid key (2), config (4), auth (6), not found (7), wrong project (8) — still use their own exit codes.

Configuration: two files, one rule each

.env                  credentials ONLY — JIRA_EMAIL, JIRA_API_TOKEN. Git-ignored.
.jira-claude.yaml     everything else — base URL, project key, limits. Committed.

Putting a credential in the YAML file is a hard error, not a warning: that file is meant to be committed, so accepting a token there would create the exact leak the split exists to prevent.

Precedence: process environment → .env.jira-claude.yaml → defaults. The environment wins so CI needs no files on disk.

See docs/configuration.md.

How it stays repo-agnostic

The skills contain no Jira logic, no credentials, and no paths. Before doing anything, /jira-speckit runs:

jira-claude doctor --json --offline

and reads this repository's actual conventions out of the result — the specs directory, feature numbering (003-name vs 20260319-143022-name), and the real specify command (/speckit-specify or /speckit.specify). Nothing is assumed, so the same two files work in Engineering OS, Product Intelligence, TokenHelm and repositories that do not exist yet.

Override discovery per project in .jira-claude.yaml when a repository does something unusual.

Architecture

Layering is enforced by import direction, not convention:

Module Knows about Knows nothing about
client Jira HTTP Claude Code, Spec-Kit, YAML, the CLI
issue Jira's data shape HTTP
grill normalized issues Jira
speckit the host repository Jira
config files HTTP
installer Claude Code Jira
decision specs on disk Jira, HTTP
smoke real-site verification Spec-Kit, the CLI
cli all of the above

So the Jira client is usable on its own:

from jira_claude.client import JiraClient
from jira_claude.issue import normalize
from jira_claude.secrets import Secret

client = JiraClient("https://acme.atlassian.net", "dev@acme.io", Secret(token))
issue = normalize(client.issue("PROJ-25"))
print(issue.acceptance_criteria)

…and the Claude Code integration is usable against any repository.

See docs/architecture.md.

Requirements

Python 3.9+. One runtime dependency: PyYAML. HTTP is stdlib urllib.

Tests

pip install -e ".[dev]"
pytest                       # 389 tests — mock only, no credentials, no network
pytest -m "not integration"  # unit tests only
pytest --cov=jira_claude     # coverage

Real-Jira tests are a separate layer and are deselected by default. They need JIRA_REAL_TEST=1 plus real credentials plus -m realjira; any gate closed means skipped, never failed. They are read-only.

jira-claude smoke-test PROJ-25   # the same checks, without pytest

See docs/testing.md.

Security

The API token is wrapped in a Secret that cannot be printed by accident — str(), repr(), f-strings and format() all yield ***, and pickling raises. It travels in an HTTP header, never in a URL, a process argument, or a file. Redirects are refused so it is never forwarded to another host.

jira-claude scan-secrets     # pre-commit hook material

See docs/security.md.

Documentation

Licence

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jira_claude_toolkit-1.0.0.tar.gz (84.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jira_claude_toolkit-1.0.0-py3-none-any.whl (61.1 kB view details)

Uploaded Python 3

File details

Details for the file jira_claude_toolkit-1.0.0.tar.gz.

File metadata

  • Download URL: jira_claude_toolkit-1.0.0.tar.gz
  • Upload date:
  • Size: 84.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for jira_claude_toolkit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 855c3f581401b3013898c25a54ee2c59d455385405dbc6041840ff42e7de4c65
MD5 ca265294f284e2b00c7efcd14b1b1d95
BLAKE2b-256 f776e1ab7a5a84bf301628cbfa86e81767d4c5b0c62b5a941285768de8a7c055

See more details on using hashes here.

Provenance

The following attestation bundles were made for jira_claude_toolkit-1.0.0.tar.gz:

Publisher: publish-pypi.yml on srinitrumatics/jira_claude

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jira_claude_toolkit-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for jira_claude_toolkit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17b5bb7e441dcc276af71de2825dbc18b55a7f4ce25427a267221e5b05ae4ccd
MD5 7d0f6a1505920b720f8746a7acc3ead9
BLAKE2b-256 3154aaf091acd23d09264e463b2d4dbd21687128b44a2e2f2fdf1867ab171a3a

See more details on using hashes here.

Provenance

The following attestation bundles were made for jira_claude_toolkit-1.0.0-py3-none-any.whl:

Publisher: publish-pypi.yml on srinitrumatics/jira_claude

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page