Install
$ agentstack add skill-ramboz-jig-spec-workflow ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
> Spec 003 promoted this skill from stub to active. The deterministic state > mutations live in workflow.py; this SKILL.md drives the judgment layer.
What this skill does
- Guides SPIDR-splitting a new spec into vertical slices (Spike last, not first —
try Rules / Data / Interface / Path first).
- Flags slices that look like horizontal phasing (no user-facing layer touched).
- Drives the spec lifecycle state transitions via
workflow.py. - Coordinates implementer + reviewer subagent invocations at the right points.
- Enforces the reconciliation checklist before a slice goes DONE.
- Consults
docs/memory/glossary.mdwhen drafting ACs to surface unknown domain terms. - Surfaces skill-routing observability via
workflow.py routing-stats [--days N]—
a read-only histogram of which skills fired (jig baseline vs. richer/"other" skill per category) from .codex/skill-usage.jsonl (slice 041-02).
- Surfaces use-case coverage via
workflow.py coverage [--project-dir DIR]— a
read-only, advisory (non-blocking), project-wide bidirectional check (slice 068-03): a deterministic set-difference over the use_cases: trace links that reports use cases with no implementing spec (coverage gap) and specs citing no parent use case (scope creep). No-op when the project has no ## Use cases section.
- Surfaces gate-bypass telemetry via
workflow.py gate-stats [--days N]— a
read-only per-gate histogram of how often each gate honored its env-var override (an override-frequency audit trail, not a gate-value verdict) from .codex/skill-usage.jsonl (slice 078-02).
SPIDR splitting
All non-trivial specs are SPIDR-split into vertical slices before implementation begins. Spike is the last resort — try Path / Interface / Data / Rules first.
- S — Spike: research/learning activity. Only when none of P/I/D/R
apply. AI agents default to spiking too eagerly — resist.
- P — Path: split by alternative paths through the story (happy
path first, edge paths later).
- I — Interface: split by UI / platform / channel (minimal first,
polish later).
- D — Data: split by data subset or format (less data first).
- R — Rules: split by business rules (simple first, edge cases later).
Anti-horizontal-phasing rule: every slice must touch the user-facing layer and deliver end-to-end value. A slice that touches only the DB or only the parser is horizontal phasing — re-split.
See [worked-example-spidr-split.md](worked-example-spidr-split.md) for one applied example per axis plus a jig-native dogfood case (spec 017's three-axis split). The canonical primer for all five axes lives at [docs/spec-workflow/spidr-primer.md](../../docs/spec-workflow/spidr-primer.md).
Spike slices
When SPIDR's S axis fires during decomposition (none of P / I / D / R apply because the team doesn't yet know enough to pick), the resulting slice is marked kind: spike in its frontmatter — the typed enum that spec_lint.py validates.
When to introduce a spike during decomposition. Reach for S only after trying R / D / I / P. The bias to resist is "let me research this first" as a prelude to "now let me build it as one big slab" — that is horizontal phasing in a trench coat. If the spike would conclude with "now ship the implementation," the implementation IS the slice, and the research goes inside it.
Body shape (four labelled blocks). A kind: spike slice carries four blocks alongside the standard Goal / DoR / AC / DoD scaffolding. Each label must be written with the trailing colon (**Question:**, etc.) — that is what spec_lint.py matches against.
- Question: — one sentence stating the open question. Set at DRAFT.
- Time-box: — explicit budget (e.g., "1 day", "4 hours"). Set at DRAFT.
- Findings: — bullet evidence collected during the spike. Filled
during IN_PROGRESS.
- Outcome: — one of
ADR-NNNN created/spec NNN-NN unblocked/
abandoned (reason). Multiple outcomes separated by ; (e.g., ADR-0007 created; spec 030-02 unblocked). Set at DONE.
spec_lint.py soft-warns when a kind: spike slice is missing any of the four labels — mid-flight spikes legitimately have empty Findings / Outcome, so this is a warning, not a hard error.
Always nested, never standalone. Spike slices live inside a real spec — never as a standalone docs/spikes/ artifact. The 1-slice-spec case (no clear downstream spec yet, just an investigation) collapses to "spawn a normal spec where the only slice is kind: spike." This forces the investigator to articulate the downstream change up front and keeps jig at two numbered families (specs+slices, ADRs).
Abandoned-spike manual-reshape failure mode. When a spike's Outcome is abandoned (reason), dependents are NOT automatically cascade-flagged. The human (or the next session) audits each dependent slice and decides whether the original design still holds. Automation here over-fires: "approach A abandoned" often means "approach B from the same findings still satisfies the dependents." workflow.py deliberately stays out of the cascade business; the SKILL.md hand-off is the documented gate.
How to use
Creating a new spec
- Step 0 — confirm the project is scaffolded (spec 063 / ADR-0011).
BEFORE reserving a number or drafting ANY docs/specs/ or slice structure, confirm this project is a scaffolded jig project. If it isn't, route — do not hand-roll directories:
- Greenfield (no jig structure yet) → tell the user to run
/jig:scaffold-init. It lays down conventions, templates, hooks, the status board, and a seed reference spec.
- Existing spec/
slices/layout, but not jig-scaffolded (no
scaffold.json) → tell the user to run /jig:migrate. It adopts the existing layout into jig structure.
You don't have to decide the state yourself: workflow.py new (step 2) classifies and routes for you (spec 063-01) — a scaffold.json-bearing project proceeds; a greenfield project is refused naming /jig:scaffold-init; an adoptable spec-driven project is refused naming /jig:migrate. The deterministic gate and this human-readable precondition agree by construction, so don't restate the detection heuristic here — run the helper and let it route. (Bypass for a deliberate out-of-band flow: JIG_SCAFFOLD_PRECONDITION=0.)
The anti-pattern this step exists to kill: an auto-triggered spec-workflow run improvising a loose slices/ folder (or any ad-hoc docs/specs/ skeleton) because /jig:scaffold-init was skipped. That produces a non-jig layout that then needs migrating — exactly the reported failure. When in doubt, route to setup first; never invent the structure by hand.
- Confirm the work needs a spec. Trivial fixes don't.
- Reference moved? Reframe first. If a load-bearing reference changed
from outside the system (a design system, vendor / API contract, test infra, compliance regime, platform, or product-positioning / strategic-vision shift), reach for /jig:reframe before drafting — re-baseline the corpus onto the new reference so you draft against it, not the dead premise (spec 067 / [ADR-0024](../../docs/decisions/adr-0024-reference-reframe.md)). 1a. Read the vision ## Use cases section as framing — before drafting (spec 068-02 / [ADR-0025](../../docs/decisions/adr-0025-use-cases-breadth-layer.md)). If the project's docs/product-vision.md carries a ## Use cases section (the breadth-layer behaviors captured at init), read it first as framing context for this spec — which captured behavior does this work serve? The section is the shared frame specs anchor against; reading it before you draft is what keeps behavior-dense projects from each spec inventing its own slice of the world. (If there is no ## Use cases section, the layer isn't adopted for this project — skip this step; nothing here applies.) You record the answer as a trace link in the spec's use_cases: frontmatter (step 2a). 1b. Cross-check tracked bugs before drafting ACs. For feedback/triage specs, read docs/bugs/README.md and any overlapping docs/bugs/NNN-*.md record before turning reported symptoms into acceptance criteria. If an item is a tracked defect with a bug record, route it through bug-fix (or link to that bug as an explicit dependency) instead of copying the defect into the spec as a second owner. Keep polish/design/new-behaviour items in the spec.
- Reserve the next free number on origin/main:
``bash python3 "${PLUGIN_ROOT}/skills/spec-workflow/workflow.py" new ``
The helper computes max(NNN) + 1 across docs/specs/, writes a minimum stub docs/specs/NNN-/spec.md (frontmatter + Overview
- SPIDR-analysis headers), commits it as
docs(specs): reserve NNN-, and pushes to origin/main. If the push is refused by branch protection / permissions, the helper automatically falls back to a reserve/NNN- branch + gh pr create. This locks the number team-wide before any drafting begins, killing the parallel-worktree spec-number-collision failure mode logged across specs 014/015/016/017.
Works from any branch or worktree (ADR-0015 / spec 051). The helper routes on the current branch: on main it runs the proven in-place flow (clean tree required, since the commit lands on local main); off main — a feature branch or a linked .codex/worktrees/* worktree — it builds the reservation commit in an ephemeral detached worktree checked out at origin/main and pushes it by SHA, never touching your branch, cwd, or working tree. You no longer need to switch to main (and a linked worktree can't, anyway).
Flags: --no-push for solo machines without a remote, or for an off-main provisional reservation committed on the current branch (the number is local-view and may collide at merge — treat it as provisional); --pr to skip the direct-push attempt on protection-locked main. 2a. Record the use-case trace link — and grow the vision on discovery (spec 068-02 / [ADR-0025](../../docs/decisions/adr-0025-use-cases-breadth-layer.md)). The stub seeds an empty use_cases: frontmatter list. Fill it with the UC-N id(s) (from the vision ## Use cases section, step 1a) this spec serves — the dependencies:-style flow-list shape, e.g. use_cases: [UC-1, UC-3]. This is the machine-resolvable trace link the reconcile-phase coverage check (slice 03) reads.
The discipline is soft — an empty/absent use_cases: never blocks a transition (AC4 / [ADR-0011](../../docs/decisions/adr-0011-spec-gate-model.md)). But it is not silent. The trigger is mechanical and deterministic — the classify_spec predicate in [skills/_common/use_cases.py](../common/usecases.py) computes one of no_section / empty / resolved / unresolvable for this spec — not a voluntary "is this new?" self-report. Whenever classify_spec returns empty or unresolvable (the spec cites nothing, or cites a UC-N with no match in the vision) at draft/framing, surface a three-path prompt — every path is one step and none blocks drafting:
- (a) cite an existing use case — this spec serves a behavior already in
the vision: put its UC-N id(s) in use_cases:. Done.
- (b) grow the vision — this spec serves a behavior not yet captured:
reuse vision-elicitation's capture loop, seeded with the existing entries (so the author sees the current set), → normalize → confirm, then write additively (append, never discard-and-replace) and assign the next free UC-N (use_cases.next_use_case_id allocates max + 1; retired numbers are never reused). The confirm step guards grow quality so a reachable trigger can't silently bloat the section: (i) enforce goal-level grain — reject spec-shaped / requirements-level phrasing, re-running slice 01's normalize ("[actor] can [goal]"); (ii) run a near-duplicate check against the seeded existing entries (use_cases.is_near_duplicate) — on an apparent match, route back to path (a)-cite rather than minting a duplicate. Then record the new id in use_cases:.
- (c) decline — legitimately untraced (infra / refactor / no user-facing
behavior) or defer: leave use_cases: []. The vision is unchanged, and any resulting gap is slice 03's advisory coverage backstop. No-op.
CRITICAL — the no-section no-op. When classify_spec returns no_section (the project has no ## Use cases section — the breadth layer is not adopted, e.g. jig's own repo), the prompt is suppressed entirely: nothing prompts and nothing errors. A project with specs but no use-case layer is wholly unaffected. The trigger fires only on empty / unresolvable, which presuppose the section exists.
- Create
docs/specs/NNN-/{spec.md,plan.md,tasks.md}with the conventional
structure: status frontmatter, overview, SPIDR analysis, ordered slices.
- SPIDR-split: for each slice, the goal is one vertical piece that delivers
end-to-end value. Spike is the last resort, not the first reach.
- For each new slice, use the template at
templates/docs/specs/slice-template.md — it ships the canonical frontmatter shape (status, dependencies, last_verified) plus DoR / AC / DoD / Close-out sections. Set status: DRAFT in the frontmatter. Legacy slices that use prose **STATUS: DRAFT** markers still work (lazy migration); no need to rewrite them.
- Ground your factual claims (spec 064-02 / ADR-0020 §1–§2). Any
load-bearing factual claim about a runnable surface — library/API capability, version/perf behavior, behavior of existing code — must be backed by an executed probe (run the command, read the source / node_modules) or a citation. Everything you cannot verify goes in the spec stub's risk-gated ## Assumptions section, marked explicitly — never asserted as fact. This makes mandatory + derived the existing informal "Current state (verified …)" discipline that the 064-01 retro found jig already half-practices by hand: it was grounding-by-probe all along, just reliant on author diligence. The ## Assumptions you surface here has downstream value — slice 064-04 derives the frame_review trigger mechanically from it, so honest framing now is what decides later whether the adversarial frame-critique pass fires. The section is risk-gated: write "None" / omit when there are no unverified load-bearing assumptions; don't pad with boilerplate. (For a worked example of marked assumptions plus probe-grounded claims, see [ADR-0020](../../docs/decisions/adr-0020-spec-frame-hardening.md) ## Assumptions A1–A4 + ## Kill criteria, and the [spec 064-01 retro](../../docs/specs/064-spec-frame-hardening/retro.md), which probe-verified its three most load-bearing claims before recording them.)
- Let the assumptions decide
frame_review(spec 064-04 / ADR-0020).
You are not asked "is frame-review needed?" — the ## Assumptions you just surfaced decide it, mechanically. Set the slice's frame_review flag from workflow.py frame-review-needed:
``bash python3 "${PLUGIN_ROOT}/skills/spec-workflow/workflow.py" \ frame-review-needed "docs/specs/NNN-/spec.md" "" ``
The rule is a derivation, not a judgment call: true iff the slice's ## Assumptions section carries ≥1 real (non-placeholder) assumption — so honest framing in step 6 is exactly what fires (or silences) the adversarial frame-critique pass. An inline-mirror / refactor slice with no unverified assumptions (`#
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ramboz
- Source: ramboz/jig
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.