/speckit.linear.push
Summary
Reconcile every specs/NNN-feature/ directory in the consumer repo
into Linear (filesystem → Linear, idempotent, drift-aware — writes from
any worktree, warns on backward-drift, never blocks).
Reconcile the consumer repo's specs/NNN-feature/ directories into
Linear. This is the load-bearing path that mirrors filesystem state
into Linear Issues, task-phase sub-issues, checklists, blocking
relations, clarify-session comments, and lifecycle-phase labels.
Direction: one-way, filesystem → Linear (Principle I).
Semantics: idempotent (Principle II — zero-churn on unchanged
state, SC-002).
Authority: drift-aware (Constitution Principle IV v2.0.0). ANY
worktree may write a spec's Linear state regardless of its current git
branch (FR-051) — the invoking worktree's filesystem is the write
authority. The v1.0.0 FR-025 branch-gate is REMOVED. Before each write
the reconciler computes a backward-drift signal (FR-052) from
lifecycle-phase ordering and spec-dir git-commit recency; on
backward-drift (Linear appears ahead of disk) it surfaces a structured
WARNING row (FR-054) and lets the operator decide — interactively it
prompts proceed/abort, non-interactively it proceeds-and-warns by
default (override with on-drift=abort). It NEVER refuses the write of
its own accord (warn, don't block). Forward / no-drift writes proceed
silently. Spec 003 (003-drift-aware-authority, FR-051..FR-064)
implements this. FR-026's current-state surfacing obligation is
retained (FR-060): speckit.linear.status shows Linear's view from any
worktree without writing. See the contracts:
drift-warning-surface,
recency-comparison,
drift-detection-graphql.
Layer: this command implements Layer D. The GitHub Action template
that ships with /spec-kit-linear-install implements Layer E and is
out of scope here.
The deterministic work happens in src/reconcile.sh; this command is
the AI-agent entry point that runs the shell and surfaces its output.
The formal API contract is contracts/command-shapes.md §1
(speckit.linear.push); the mutations issued are enumerated in
contracts/linear-graphql-mutations.md §4. Operators reading this
file are looking at the markdown the AI agent reads — the same
operations are available via bash src/reconcile.sh directly. For
the operator-facing end-to-end walkthrough see
quickstart.md.
Usage
| Argument | Default | Meaning |
|---|---|---|
spec |
(none — uses --all) |
Feature number (e.g. 003). Reconcile only this spec. |
dry-run |
false | Log every mutation that WOULD fire; issue none. Safe inspection mode. |
retroactive |
false | DEPRECATED no-op alias (Constitution Principle IV v2.0.0 / spec 003 FR-061). Write-from-any-branch is now the default (FR-051), so this flag changes nothing behaviorally; it emits exactly one deprecation INFO row per invocation and still implies --all (the historical first-time-adoption convenience). A documented v0.1.1 command that still carries --retroactive runs identically to omitting it. Removed in a later release. |
on-drift |
(unset → proceed-and-warn) | abort|proceed — non-interactive backward-drift disposition (FR-056). The default writes the disk state and records a WARNING row so CI logs stay auditable (hooks keep converging). abort skips drifted specs with a WARNING row + a skip note (Linear unchanged) instead of writing. Has no observable effect when no backward-drift fires. An unrecognised value is a usage error. |
Exactly one of spec or "all specs" is in effect — if spec is not
passed, the reconciler walks every specs/NNN-*/ directory in the
consumer repo. If retroactive is set and spec is not, --all is
implied. dry-run is orthogonal to retroactive and spec.
CLI shape
speckit.linear.push [--spec NNN | --all] [--dry-run] [--retroactive]
Default: --all.
Algorithm (what the AI agent executes)
Verify prerequisites. Refuse to proceed if any of these fail.
- Bash 4 or newer is on
PATH. Runbash --versionand confirm the major version number is≥ 4. macOS ships bash 3.2 by default; the operator mustbrew install bashand ensure/opt/homebrew/bin/bash(Apple Silicon) or/usr/local/bin/bash(Intel) is earlier onPATHthan/bin/bash. - The consumer repo's config is present at
.specify/extensions/linear/linear-config.yml. If absent, surface "run/spec-kit-linear-installfirst" and exit; do NOT attempt to run the reconciler. jqis installed (command -v jq).curlis installed (command -v curl).gitis installed and the working directory is inside a git working tree.
- Bash 4 or newer is on
Compose the invocation. Translate the user-facing arguments into
src/reconcile.shflags:spec=NNN→--spec NNN- no
specand noretroactive→--all dry-run=true→--dry-runretroactive=true→--retroactive- Always pass
--quietUNLESS the user has explicitly asked for verbose output, since the structured summary is the operator-visible contract per FR-023.
Execute the reconciler. Shell out:
bash src/reconcile.sh <flags>The script:
- Loads + validates
linear-config.yml(src/config.sh). On missing/malformed UUIDs it halts with exit 2 and an operator-actionable diagnostic (Principle VIII). - Enumerates the requested specs and processes each:
- Applies write authority per Constitution Principle IV v2.0.0
(drift-aware, spec 003): ANY worktree may write regardless of
its current branch (FR-051) — the legacy FR-025 branch-gate is
removed. The bridge computes a backward-drift signal and
surfaces a WARNING row when Linear is ahead, but does not refuse
the write (interactive prompt / non-interactive
on-driftresolution decide proceed vs abort; the default is proceed-and-warn). Forward / no-drift writes proceed silently. The spec's current Linear state is surfaced read-only regardless (FR-026 / FR-060). - Infers the lifecycle phase from artifacts on disk
(
spec.md→clarifying→planning→tasking→red_team→implementing→analyzing→ready_to_merge→merged) per FR-012, with PR-state hints fromgit_helpers::pr_state(gh CLI → git-only branch-reachability fallback per FR-030) for the terminalready_to_mergeandmergedstates. - Find-or-creates the spec Issue by
speckit-spec:NNNlabel scoped to the configured Project (FR-004b). On race (>1 match) keeps the most-recently-updated and surfaces the others as warnings. On retroactive sync setsstateIddirectly to the inferred end-state (FR-014). - Rewrites the spec Issue's description in canonical order (overview → memory block → diagrams) per FR-004. The bridge fully owns the description body; any prior content is discarded. Operator annotations belong in Linear comments per FR-008 (the canonical escape hatch the bridge never touches). The memory block surfaces lifecycle phase, current task phase, branch, worktree path(s), last-touched timestamp, the GitHub source link, operator assignee (FR-034), and the Fibonacci estimate rollup (FR-035).
- Reconciles task-phase sub-issues per
## Phase N: <Name>header intasks.md(FR-005). Each sub-issue carries a checklist mirror with a read-only header (FR-006). Workflow state is Todo / In Progress / Done based on checklist completion ratio. - Wires inter-task-phase blocking relations (FR-007) by reading
"Phase N depends on Phase M" hints from
plan.md/tasks.md. Nativesave_issue.blocksper the MCP runtime probe; pre-queries existing relations to avoid duplicate-add. - Mirrors each
### Session YYYY-MM-DDclarify block under## Clarificationsto a Linear Issue comment, idempotent via a deterministic comment marker (FR-008 + FR-015). - Ensures the spec Issue carries
phase:<current>andspeckit-spec:NNNlabels; strips stalephase:*labels. When phase ismerged, nophase:*label is set (FR-013). FR-036 agent labels — see spec for stamping rules.
- Applies write authority per Constitution Principle IV v2.0.0
(drift-aware, spec 003): ANY worktree may write regardless of
its current branch (FR-051) — the legacy FR-025 branch-gate is
removed. The bridge computes a backward-drift signal and
surfaces a WARNING row when Linear is ahead, but does not refuse
the write (interactive prompt / non-interactive
- Loads + validates
Render the structured summary. The script emits a block to stderr at the end of every invocation (FR-023). The block looks like:
===== speckit.linear summary ===== speckit.linear reconcile — spec 003 Created: 1 Updated: 4 Archived: 0 Skipped: 0 Warned: 1 Errors: 0 ----- warnings ----- - spec 003: 2 task line(s) outside any ## Phase header ==================================Surface this verbatim to the operator. The block IS the operator-visible result of the command per Principle VIII Rule 1.
Handle the exit code. Per
contracts/command-shapes.md§1.6:0— success (possibly with warnings). Report success; include the summary block verbatim.1— partial failure. Some specs failed; others succeeded. Surface the warnings from the summary and recommend re-running/speckit.linear.push spec=<NNN>for any spec named in the warnings list.2— workspace config error (per FR-022). The script halted before any mutation. Surface the exact remediation the script printed (typically: run/spec-kit-linear-installor/spec-kit-linear-seed). Do NOT retry automatically.3— transport failure. Linear was unreachable; nothing was written. Recommend re-running once network connectivity is restored.
When this command fires
- Operator-driven.
/speckit.linear.pushfrom the AI agent chat — the primary on-demand path for recovery from missed hooks and ad-hoc reconcile. - Auto-fired hooks (post-install via
/spec-kit-linear-install). Every/speckit-*lifecycle command in.specify/extensions.ymlis wired to invoke this command per FR-031. - Local git hooks (
post-checkout,post-commit,post-merge) invokesrc/reconcile.shdirectly per FR-033, bypassing this markdown and skipping the prerequisite re-verification.
All three paths converge on src/reconcile.sh (FR-011 — same
outcome regardless of trigger).
Output channel discipline
stdoutofsrc/reconcile.shis reserved for future structured-output modes (none in v1) — it stays empty during a normal reconcile.stderrcarries:- per-mutation log lines (suppressed by
--quiet) - the final structured summary block (always, unless
sync.emit_summary: falseis set inlinear-config.yml)
- per-mutation log lines (suppressed by
- No filesystem writes (Principle I + FR-016). The reconciler reads the spec directories, the config, and the git state; everything else flows out over the Linear API.
Failure surface
Each failure mode is surfaced as a named warning in the summary (Principle VIII) so the operator can act on it without trawling logs:
spec NNN: spec.md missing or empty; skipping— edge case from spec § 1. Reconcile continues with the next spec.spec NNN: N task line(s) outside any ## Phase header— FR-024. Tasks lacking a phase grouping are still flagged and the rest of the spec syncs.duplicate spec Issues with label speckit-spec:NNN: kept <id>, archiving N loser(s)— FR-004b race resolution. The most-recently -updated wins; losers are flagged for archival.clarify-session DATE: existing comment body diverges from spec.md; not overwriting— FR-015 + contracts §9. Hand-edits to comments are preserved; the reconciler does not silently overwrite.spec NNN backward-drift: disk=<phase> linear=<phase> signals=<csv>— Principle IV v2.0.0 (drift-aware, spec 003) WARNING row: Linear appears ahead of the invoking worktree's disk state. It surfaces the drift but does NOT block the write; the operator decides (interactive prompt, oron-driftnon-interactively — default proceed-and-warn). This REPLACES the removed v1.0.0non-authoritative worktree … read-only modeskip. A recency-signal drift appends a detail line naming the spec-dir last-commit time vs Linear'supdatedAt.spec NNN skipped by operator (backward-drift abort) — Linear unchanged— the operator (oron-drift=abort) chose to skip a drifted spec; zero Linear mutation for that spec (FR-057).linear-config.yml not found at <path>; run /spec-kit-linear-install— FR-022 halt. Exit code 2.
Related commands
/speckit.linear.pull— read-only inspect Linear's current view (works from any worktree, never mutates)./speckit.linear.status— drift report (filesystem vs Linear) without actually issuing mutations./speckit.linear.seed— one-shot workspace setup. Run once per Linear workspace before the first push./speckit.linear.install— per-repo install ceremony. Run once per consumer repo before the first push.
See contracts/command-shapes.md for the formal contract on each
and
quickstart.md
for the end-to-end operator walkthrough.
FRs surfaced
This command implements (in whole or in part):
- FR-001 / FR-011 — convergent reconcile across hook and manual paths.
- FR-004 — bridge-owned spec Issue description (overview → memory → diagrams; no fence markers).
- FR-004b —
speckit-spec:NNNworkspace label as the stable lookup key. - FR-005 / FR-006 — task-phase sub-issues with mirrored checklists.
- FR-007 — inter-task-phase blocking relations.
- FR-008 / FR-015 — clarify-session comments (operator escape hatch).
- FR-012 / FR-013 — lifecycle-phase inference and
phase:*label hygiene. - FR-014 — retroactive first-time-adoption mode (deprecated to a no-op alias by spec 003 FR-061).
- FR-016 / FR-017 — unidirectional sync; no PR mutations.
- FR-022 — halt with operator-actionable diagnostic on unseeded workspace.
- FR-023 / FR-024 — structured summary block; named warnings.
- FR-025 / FR-026 — write authority. v1.0.0 per-spec branch-gate (FR-025) SUPERSEDED by Constitution Principle IV v2.0.0 / spec 003 drift-aware model (FR-051..FR-060); FR-026's current-state surfacing is retained (FR-060).
- FR-030 — gh CLI primary / git-only fallback for PR-state hints.
- FR-031 / FR-033 — auto-fire from
after_*hooks and local git hooks. - FR-034 — operator assignee captured into the memory block.
- FR-035 — Fibonacci
[N]estimate rollup. - FR-036 — agent labels — see spec for stamping rules.