Releases: ashbrener/spec-kit-jira-sync
v0.3.0 — ADR mirroring + author attribution
MINOR feature release. Two new user-facing features since v0.2.1.
ADR / decision-record mirroring (feature 005)
Each spec's research.md decision records — the Decision / Rationale / Alternatives blocks (both the bold-lead and stock-bullet grammars) — are mirrored as one idempotent comment per decision on the spec's Jira issue. Re-runs are zero-churn; a changed decision updates its single comment in place (never a duplicate). The ADR comment stream is disjoint from clarify-session comments (speckit-adr: vs speckit-note: markers) and parity-locked to the Linear sibling's ADR layout (Linear-008 parity). Carried through the neutral workstate.decisions[] floor field; the reconcile engine stays vendor-neutral. Additive and on by default — no config, no new command.
Author-based attribution (feature 007)
Opt-in two-track attribution that makes the board reflect who authored each spec:
- an account-independent
author:<handle>label stamped on the spec issue always (works for authors with no Jira account), plus - a Jira assignee set on create only when the author maps to a real
accountId(never re-sent on update, so a manual reassignment survives — Linear bridge FR-034 semantics).
Author resolution is vendor-neutral (Owner:/Author: line wins, else first git author to add the spec dir, else a graceful unknown no-op). The email→accountId/handle mapping is the sink's job via a gitignored operator map (jira-authors.local.yml; only a .sample placeholder ships, as the map holds PII). Off by default — absent/enabled: false is byte-identical to prior behavior.
Install
The GitHub source ZIP at the v0.3.0 tag is the install artifact:
https://github.com/ashbrener/spec-kit-jira-sync/archive/refs/tags/v0.3.0.zip
Note: the v0.3.0 tag currently sits on the
release/v0.3.0branch. After release PR #14 merges, the tag will be re-pointed to the merge commit onmain(matching the v0.2.0 / v0.2.1 process).
v0.2.1 — multi-spec & dry-run fixes
PATCH bug-fix release over v0.2.0. No new features — both fixes landed on main after the v0.2.0 tag, so the cataloged v0.2.0 still carried the multi-spec collision bug. The GitHub source ZIP at this tag is the install artifact.
Fixed
- #10 — spec-scoped phase Subtask identity (fixes cross-spec collision on multi-spec repos). The feature-003 unified level loop matched a phase Subtask by its
task-phase:Nidentity label alone;task-phase:Nis a phase number (unique only within a spec), so across a multi-spec repo every spec's "Phase N" matched the same Subtask — specs 2..N updated spec 1's Subtask instead of creating their own. The phase find is now parent-scoped (parent = <story> AND labels = task-phase:N), restoring 001 behaviour. No label-scheme change; single-spec boards are unaffected; a plainreconcile.sh --allself-heals a mis-scoped board.- Empty
taskList→ HTTP 400 INVALID_INPUT guard: a## Phasewith zero task lines no longer renders a childless ADFtaskList(which Jira rejects) — a paragraph placeholder is emitted, and everytaskItemcarries non-empty content. - Field-level error detail: a non-2xx write now surfaces the Jira response body (
errorMessages/errors) in the failure line.
- Empty
- #9 — dry-run of an unmirrored spec no longer spuriously exits 3: a
--dry-runcreate synthesizes theDRY-0placeholder key; the post-create reconciles read against it, which 404s on a live Jira → fail-closedrc 3→ the whole dry-run exited 3 even though the board was fully readable. The existence-check read is now skipped for theDRY-0placeholder (scoped toDRY-0only — a real key still fails closed).
Install: specify extension add jira-sync --from https://github.com/ashbrener/spec-kit-jira-sync/archive/refs/tags/v0.2.1.zip
v0.2.0 — re-mode + engine unification
Minor release on top of v0.1.0. Install via the GitHub-generated source tarball at this tag.
Feature 004 — guarded re-mode / orphan pruning (new, user-facing)
An opt-in, controlled-destruction reconcile.sh --remode that converges a board to the shape the current mapping projects:
- Orphan pruning — prunes the bridge-owned artifacts a prior mapping shape left behind, identified by a vendor-neutral diff
O = E \ Dover thespeckit-*identity labels, then regenerates the new shape in one pass. - Fail-safe scoping — an issue carrying no
speckit-*identity label (e.g. operator-created) is structurally excluded and never touched. - Dry-run preview —
--remode --dry-runpreviews the exact prune + regenerate set with zero writes, byte-faithful to the real run. - Fail-closed — reads are fail-closed (an unreadable read aborts before any delete); a partial prune failure is surfaced and completable by a re-run; backward-drift on a to-be-pruned issue is warned first.
- Selectable destruction model —
remode.destruction: hard-delete(default) orarchive. - Ordinary reconcile stays strictly non-destructive — it only warns when it detects prior-shape orphans.
- Governance — gated on a constitution v1.1.0 amendment: a scoped controlled-destruction carve-out to Principle I (flag-only, bridge-owned-only, dry-run-previewable, fail-closed). No principle removed.
Feature 003 — engine orchestration unification (internal, behavior-preserving)
Re-platforms the engine onto one neutral, mapping-driven projection (sync_level_artifact + link_to_parent) driven by a vendor-neutral level loop; the 001-era orchestrators (~450 lines) are removed. An enforced committed gate keeps the engine path free of Jira issue-type / artifact-name / relationship knowledge, so the eventual engine extraction is a near-mechanical lift. No operator-observable change — behavior is byte-for-byte identical and the full suite passes unchanged.
Full changelog: https://github.com/ashbrener/spec-kit-jira-sync/blob/v0.2.0/CHANGELOG.md
spec-kit-jira-sync v0.1.0
spec-kit-jira-sync v0.1.0
A real reconcile engine — idempotent, drift-aware, fail-closed — that mirrors
your spec-kit specs into Jira and never corrupts your board.
This is not a prompt that asks an LLM to "make some Jira tickets." It is a
deterministic reconcile engine (the same hardened core the shipped
spec-kit-linear-sync runs) wired to Jira's REST API. The filesystem is the
single source of truth; Jira is a one-way, read-only mirror. Every run converges
the board to disk:
- Idempotent — a re-run over an unchanged spec corpus performs zero
writes. It reuses the existing issues instead of duplicating them. Run it as
often as you like. - Drift-aware — before each write the engine computes a backward-drift
signal (lifecycle ordering + commit recency). If Jira is ahead of disk it
surfaces a named WARNING rather than silently clobbering, and you choose the
disposition (--on-drift=proceedwarns and writes;--on-drift=abortskips
the drifted spec). - Fail-closed — invalid config exits
2; an unreadable Jira exits3.
When the engine cannot read the board reliably it refuses to write rather than
risk a duplicate. No partial corruption. - Schema-gated — every record is validated against the neutral
workstate
schema (underuv, PEP 668-safe) before any write touches Jira.
What it mirrors
By default, the zero-config projection is:
- Epic per repo — one per-repository Epic.
- Story per spec — one Story per
specs/NNN-feature/directory, linked under
the repo Epic, transitioned through your workflow as the spec's lifecycle phase
advances. - Subtask per phase — one Subtask per task phase, with that phase's tasks
rendered as a done/not-done ADF checklist in the Subtask body.
Feature 001 — the core bridge (Layer D reconcile)
A single src/reconcile.sh command mirrors a spec-kit project's specs into Jira
through parser → schema-valid workstate → Jira sink. The parser reads the
on-disk spec corpus (spec.md / plan.md / tasks.md), infers the lifecycle
phase, and emits neutral workstate JSON; the Jira sink consumes only
workstate. The reconcile engine (drift detection, commit-recency gating,
layered idempotency) is vendor-neutral — Jira lives only in the sink and config.
Feature 002 — configurable artifact mapping
An optional mapping: block in jira-config.yml makes the spec-kit→Jira
projection operator-configurable, while keeping today's behavior as the frozen,
zero-config default (a no-config upgrade is byte-for-byte identical — the
regression anchor):
- Per-level mapping + available-type detection — each
workstatelevel
(repo/spec/phase/task) maps to a configurable Jira issue type and a
parent-link relationship, validated at config-load against the project's
live available issue types, with a per-levelon_absentfallback. All
fail-closed before any write. - 2-level checklist mode — phases/tasks collapse into a keyed in-body
checklist on the spec issue (no Subtask children), diffed as an isolated
byte-stable sub-tree so re-runs stay zero-churn and human prose edits survive. - Status rollup (off by default) — rolls phase/spec completion up to issue
status (phase done when all tasks checked, repo Epic done when all specs
merged), transitioning only on a real completion change. - Initiative super-level (off by default) — a narrative level above the Epic,
mapping to a Jira Initiative where available and degrading gracefully onto the
Epic (behind a stable marker + repo label) where it is not — never
hard-failing. Narrative is sourced only from the explicitspec.mdInput:
line. --workstate <file|->direct input — feeds a schema-validatedworkstate
document straight to the sink, skipping the parser, so any producer can drive
the mirror.
Install
specify extension add jira
Then copy config-template.yml to .specify/extensions/jira/jira-config.yml,
fill in your project key, issue-type ids, and phase→status ids, and set
JIRA_BASE_URL / JIRA_EMAIL / JIRA_API_TOKEN in a gitignored .env.
Two commands ship: /speckit.jira.push (reconcile/write) and
/speckit.jira.status (read-only dry-run drift preview).
Privacy
No real Jira coordinates or PII ship in this release. The Basic-auth token and
all site/project binding values live only in your gitignored .env and
jira-config.yml. A privacy guard gates CI.
License: MIT