diff --git a/.github/workflows/mcp-tests.yml b/.github/workflows/mcp-tests.yml new file mode 100644 index 0000000..cea4460 --- /dev/null +++ b/.github/workflows/mcp-tests.yml @@ -0,0 +1,30 @@ +name: spec-kit tests + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r spec-kit-mcp-server/requirements.txt + + - name: Validate skill files (frontmatter, references, templates) + run: python3 spec-kit-mcp-server/test_skills.py + + - name: Run MCP server workflow tests + run: python3 spec-kit-mcp-server/test_workflow.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17cd2fc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.venv/ +__pycache__/ +*.pyc +.pytest_cache/ diff --git a/AGENT.md b/AGENT.md index 469ec04..11990aa 100644 --- a/AGENT.md +++ b/AGENT.md @@ -1,90 +1,589 @@ # Hermes Spec Kit — Agent Instructions -Project-level context for Hermes Agent when working on the spec-kit repository. Read before making changes. - -## Project Overview - -A **spec-driven development (SDD) workflow system** for Hermes Agent. 13 skills implementing two development modes: - -- **Specify** (default): Constitution → Specify → [Clarify] → Plan → Tasks → Implement → Test → Close -- **Bugfix**: Test → [Clarify] → Plan → Tasks → Implement → Test → Close (auto-chain inner loop) - -## Key Files - -| File | Purpose | -|------|---------| -| `user-guide.md` | Complete workflow documentation | -| `README.md` | Project overview and quick start | -| `AGENT.md` | This file — agent project context | -| `src/skills/*.md` | 12 source skill files (installed via install.sh) | -| `src/skills/spec-kit/SKILL.md` | Umbrella skill overview | -| `src/templates/` | 13 template files | -| `src/references/` | Reference files (auto-commit.md) | -| `scripts/install.sh` | Installs skills + templates + references | - -## Skills (12) - -| Skill | Phase | Purpose | -|-------|-------|---------| -| spec-kit-workflow | — | Orchestrator — routes requests to phases | -| spec-kit-constitution | 0 | Project principles (mandatory before specify/plan) | -| spec-kit-specify | 1 | Feature specification | -| spec-kit-clarify | 1.5 | Ambiguity resolution (optional) | -| spec-kit-plan | 2 | Implementation planning | -| spec-kit-tasks | 3 | Task breakdown (asks user about TDD) | -| spec-kit-implement | 4 | Phase-level TDD execution | -| spec-kit-test | 5 | Bug tracking (manual) | -| spec-kit-summarize | 6 | Close/summary (mandatory) | -| spec-kit-refresh | — | Artifact alignment | - -## Key Behaviors - -- **Constitution is mandatory** — specify and plan block without it -- **Design phases (0-3) do not auto-commit** — batch commit at start of Phase 4 -- **Phase-level TDD** — all tests RED first, all code GREEN, one commit per phase -- **TDD bypass** — user asked at task generation, tracked in tasks.md header -- **Umbrella regression** — one BF-REGRESSION-001 task, not individual bugs -- **Phase 6 mandatory** — feature cannot complete without close or summary -- **Spec health score** — computed at close: (resolved + acknowledged) / total * 100 -- **Analyze works from spec.md alone** — plan/tasks optional for richer analysis - -## Template Management - -Templates in `src/templates/` installed to `~/.hermes/skills/spec-kit/templates/`. -Edit source files in `src/templates/`, run `./scripts/install.sh` to deploy. - -## Phase State Detection - -| Artifacts Present | Phase | -|---|---| -| constitution.md only | Ready to Specify | -| spec.md exists | Specified | -| clarify.md exists | Clarified | -| plan.md exists | Planned | -| tasks.md exists | Tasked | -| tasks.md with completions | Implementing | -| bugs.md with open bugs | Testing | -| bugs.md all verified | Testing complete — must close | -| implementation-summary.md or close.md exists | Complete | - -## Conventions - -- Spec numbering: `NNN-feature-name` (sequential, 3 digits) -- Branch naming: `feature/NNN-feature-name`, `fix/NNN-name` -- Commit messages: see `src/references/auto-commit.md` -- Design phases: NO individual commits (batch at Phase 4) -- Implementation: one commit per phase - -## Installation +Project-level context for Hermes Agent when working on the **spec-kit** repository. +Read this file before making any changes. It covers architecture, conventions, phase +state machine, MCP integration, testing, and how skills/templates/references are +organized and maintained. + +**This is the AI agent's working context — not a user-facing guide.** +For users, see `user-guide.md` (workflow docs) and `README.md` (quick start). + +--- + +## Project Identity + +| Field | Value | +|-------|-------| +| Repository | `kmarecki/hermes-spec-kit` | +| What it is | Spec-driven development (SDD) workflow for Hermes Agent — 14 skills + MCP server | +| License | MIT | +| Author | Hermes Agent | +| Maturity | Active development — `feat/mcp-orchestrator` branch | +| Source of truth for specs | `specs/` directory in consumer projects | +| Source of truth for state | the files under `specs//` — derived by the MCP server (v3) or by the skills' phase-detection table (fallback) | + +--- + +## Architecture Overview + +The system has three operational layers plus an optional MCP state layer: + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Workflow Orchestration Layer │ +│ spec-kit-workflow — routes user intent → phase skill │ +│ Phase detection via artifact scan or MCP state │ +│ Session continuity detection for cross-session resumption │ +├──────────────────────────────────────────────────────────────┤ +│ 14 Skills Layer │ +│ One skill per phase + review, refresh, epic, design │ +│ Each skill: preflight → phase work → history append → commit│ +│ All skills loadable independently, none depend on each │ +│ other at runtime (only on artifact state) │ +├──────────────────────────────────────────────────────────────┤ +│ Artifact & Storage Layer │ +│ Markdown files in specs/ — additive-only, never overwritten │ +│ Templates in spec-kit/templates/ — 17 templates │ +│ References in spec-kit/references/ — 7 shared files │ +│ history.md — per-phase record, kept for size L by default │ +│ (history: large); change-record.md at close carries the │ +│ timeline that survives the squash-merge │ +├──────────────────────────────────────────────────────────────┤ +│ MCP State Management Layer (optional) │ +│ FastMCP stdio server — 19 tools, no stored state │ +│ No stored state — derived from specs// per call │ +│ Fallback: filesystem-based artifact detection │ +│ All skills backward-compatible with or without MCP │ +└──────────────────────────────────────────────────────────────┘ +``` + +### Key Architectural Principles + +1. **Skills are self-contained** — each phase skill has full instructions for its + phase, references preflight.md for shared checks, and never calls another skill. +2. **Routing is separate from execution** — `spec-kit-workflow` routes but never + executes phase work. Phase skills execute but never route. +3. **Artifacts are the source of truth** — the filesystem (specs/ directory) is the + primary state store. MCP server mirrors and enhances it with deterministic tools, + but is optional. +4. **Additive-only mutation** — no spec artifact is ever overwritten. All edits are + append, insert, or targeted patch. This is enforced at every phase. +5. **Phase 6 is mandatory** — a feature is not complete until Close/Summarize is + done. This prevents feature accretion and ensures traceability. +6. **Ceremony follows size** — S / M / L (`references/sizing.md`) make the workflow and the + artifacts progressively leaner (S = a bugfix or small enhancement: a few-line spec with 1–2 + ACs, one commit for spec+plan+tasks, no pre-implement review). Evidence never shrinks: + RED/GREEN files, probes per seam, the acceptance round documenting every AC, the oracle + rule, the final review, the change record. +7. **Scale is opt-in** — `adr_dir`, `design_dir`, `epics_dir` in git-conventions.md decide + which documents exist; absent → the close has nothing to patch and never creates them. + Roles: spec = one feature · epic = what and in what order (time) · design doc = how a + part works now (space) · ADR = why · AGENTS.md = where things are and what never to do. +8. **Skills are the delta** — the one-screen SKILL.md (≤ 60 lines) is the procedure; the + `references/skills/` file holds only what it leaves out. Never restate one in the other. + +--- + +## Three Development Modes + +| Mode | When | Trigger | Phase Sequence | User Involvement | +|------|------|---------|---------------|-----------------| +| **Specify** (default) | New feature, low uncertainty | "Create a spec for..." | Constitution → Specify (asks Size S/M/L; ACs with ids + verify level) → [Clarify] → Plan → Tasks → [Review] → Implement → Accept loop (auto) → Test → Final review → Close | Manual — user says "plan", "implement", etc.; size S auto-chains specify → plan → tasks | +| **Bugfix** | Working feature with known bugs | "bugfix [feature]" | Auto-chain: Plan → Tasks → Implement → Test → Final review → Close | Minimal — inner loop is automatic | +| **Reopen** | Closed feature needs more work | "reopen [feature]" | Creates bugfix branch from main, preserves original close, routes through bugfix loop | Additive-only edits; must close again | + +### Bugfix vs Quickfix + +- **bugfix** (default): separate commits per phase — plan commit, tasks commit, + implementation commits. Full traceability. +- **quickfix** (user opt-in): one batch commit for trivial fixes (config typos, + obvious one-liners). Plan ref and task entry still exist in docs. + +--- + +## Phase Reference — Complete + +| Phase | Skill | Artifact(s) | Prerequisite | Code Allowed? | Persona | +|-------|-------|-------------|-------------|---------------|---------| +| **Project** | `spec-kit-constitution` | `specs/constitution.md` | None (one-time project setup) | ❌ | Project designer | +| 1 | `spec-kit-specify` | `specs/NNN-name/spec.md` | None (creates first feature artifact) | ❌ | Product manager | +| 1.5 | `spec-kit-clarify` | `specs/NNN-name/clarify.md`, amends spec.md | spec.md | ❌ | Requirements analyst | +| 2 | `spec-kit-plan` | `plan.md`, `research.md`, `data-model.md`, `contracts/*`, `quickstart.md` | spec.md | ❌ | Architect | +| 3 | `spec-kit-tasks` | `specs/NNN-name/tasks.md` | plan.md + spec.md | ❌ | Tech lead | +| 3.5 | `spec-kit-review` | Pre-implement review report | spec+plan+tasks | ❌ | Quality engineer | +| 5.5 | `spec-kit-review` (final) | `review-final.md` (rounds: Verdict + Reviewed-commit), `evidence/final-*` | all tasks [X], no open bug | ❌ (runs build/test/lint) | Senior reviewer — merge gate | +| 4 | `spec-kit-implement` | Source code, `tasks.md` (completions), `bugs.md` (mark resolved) | tasks.md | ✅ | Developer | +| 5 | `spec-kit-test` | `specs/NNN-name/bugs.md` | Implement (or spec for bugfix) | ❌ | QA engineer | +| 6 | `spec-kit-summarize` | `close.md` + `change-record.md`, patched spec/plan, ADRs + ADR index, AGENTS.md patches | Fresh READY final review, no open bug | ❌ | Auditor / archivist | +| — | `spec-kit-refresh` | Patched spec/plan/data-model/contracts | Any (standalone) | ❌ | Archivist | +| — | `spec-kit-epic` | `[epics_dir]//{epic,plan,features,review}.md` — E1 specify → E2 plan → E3 breakdown → E3.5 review (+ devil's advocate) → build → E6 close (optional: `epics_dir` set) | — | ❌ | Delivery lead + architect | +| — | `spec-kit-design` | `[design_dir]/.md` — living module design doc (optional: `design_dir` set) | — | ❌ | Architect describing what is built | + +### Phase 6 — Mandatory Close + +No feature enters Complete state without Phase 6. The close artifact includes: + +- **Spec health score**: `(resolved + acknowledged) / total FRs * 100` +- **Gap analysis**: which FRs were deferred or only partially met +- **Deviation patching**: spec.md and plan.md patched to reflect intentional + deviations +- **One commit**: `spec(phase-6): [feature] summary (health: N%)` + +--- + +## Phase State Machine + +### Artifact → Phase Mapping + +| Artifacts Present | Implied Phase | +|------------------|---------------| +| constitution.md only (project root) | Project bootstrapped — ready to specify | +| spec.md exists | Specified (Phase 1) | +| clarify.md exists | Clarified (Phase 1.5) | +| plan.md exists (no tasks.md) | Planned (Phase 2) | +| tasks.md exists (no completions) | Tasked (Phase 3) | +| tasks.md with [X] completions | Implementing (Phase 4) | +| bugs.md with open bugs | Testing / Bugfix loop (Phase 5) | +| bugs.md all verified, no close.md | Testing complete — must close | +| close.md (legacy: implementation-summary.md) exists | Complete (Phase 6) | +| close.md + bugs.md with open bugs | Reopened — bugfix in progress | + +### Prerequisite Graph (enforced by MCP server and skills) + +**Constitution is NOT a feature-level prerequisite.** It is project-level +bootstrap state, checked once by the workflow orchestrator before routing. +Features start at Phase 1 (specify) and have no constitution dependency. + +``` +Phase 1 (specify) — no feature-level prereqs + ↓ +Phase 1.5 (clarify) — needs spec.md + ↓ +Phase 2 (plan) — needs spec.md + ↓ +Phase 3 (tasks) — needs plan.md + spec.md + ↓ +Phase 3.5 (review) — needs spec + plan + tasks (pre) or spec + code (post) + ↓ +Phase 4 (implement) — needs tasks.md + ↓ +Phase 5 (test) — needs implement (phase 4 done) + ↓ +Phase 6 (close) — needs implement + test (phases 4 + 5) +``` + +### Phase Transitions via MCP + +When the MCP server is active, every phase transition is **validated** by +`mcp_spec_kit_advance_phase` against the files on disk (derived phase must +match, required artifacts must exist). The server writes nothing — the +artifacts are the state. + +**Rule**: Only the skill that OWNS a phase transition may call `advance_phase`. +The specify skill advances 1→2. The constitution skill does NOT call +`advance_phase` — it calls `project_set_constitution`. Never advance a phase +outside its owning skill context. + +--- + +## MCP Server Integration + +### Location +- Source: `spec-kit-mcp-server/server.py` +- Installed to: `~/.hermes/skills/spec-kit/mcp-server/server.py` (Claude Code symlinks to it) +- State: **none** — derived from `specs//` on every call (v3). A legacy + `specs/.spec-kit/state.json` is ignored; consumer projects should delete it + and gitignore `specs/.spec-kit/`. +- Framework: FastMCP (stdin/stdout transport) + +### MCP Tools (prefixed `mcp_spec_kit_` in Hermes) + +| Tool | Purpose | When to Call | +|------|---------|-------------| +| `init_feature` | Create `specs//` + history.md header | In specify skill when creating a new feature | +| `get_feature_state` | Derived phase, status, artifacts, task/bug counts + phase card | Phase detection, status queries | +| `get_next_actions` | Available actions + the ten-line **phase card** | Before any write; after context compaction | +| `advance_phase` | Validate a transition against the files (writes nothing) | In the phase skill that owns the transition | +| `project_status` | Constitution/git-conventions present?, feature count, legacy state file? | Workflow bootstrap check | +| `project_set_constitution` | Confirm `specs/constitution.md` exists (stores nothing) | In constitution skill | +| `list_features` | Every feature's derived phase/status/bug counts | Status queries, diagnostics | +| `reopen_feature` | Check closed-on-disk, return branch hint (writes nothing) | Reopen flow | +| `close_feature` | Validate close: close doc with Architecture Decisions, fresh READY final review, no open bugs, verified bugs have Verified-by; lists claimed-unverified | Before the Phase 6 commit | +| `update_artifact` | Confirm an artifact is on disk (or absent) | After writing an artifact file | +| `auto_detect_features` | Derived state of every feature; flags a legacy state.json | First-use, diagnostics | +| `next_id` | Next BUG-NNN / T### / BF-### by scanning the files; next ADR number in the project's ADR dir | Before adding an entry / an ADR | +| `acceptance_freeze` | Checksum the `[TEST] [AC-###]` test files after their RED run; refuse silent changes | Implement, after each RED sub-phase | +| `acceptance_status` | AC → test → result matrix from spec.md, tasks.md and JUnit/TRX files; regressions; frozen changes | Accept mode (each loop round) | +| `diff_scan` | Mechanical merge-readiness scan of the branch diff (conflicts, secrets, forbidden files, focused tests, TODOs, unplanned files) | Final review (phase 5.5) | +| `lint_artifacts` | Schema lint of bugs.md / tasks.md / ACs / rounds; probes per [SEAM]; RED files per done [TEST] | Before every commit | +| `timestamp` | Real UTC time | Every history entry and evidence file | +| `history_guard` | Is there a fresh history entry for this phase since the last commit? | Pre-commit guard | +| `append_history` | Append a fixed-field, time-stamped, word-capped history entry | End of every phase / bugfix / regression / close | + +### Critical MCP Rules + +- **`advance_phase`** — only call within the phase skill that owns the transition. + Never advance a phase from outside its owning skill. Constitution uses + `project_set_constitution`, not `advance_phase`. +- **`project_set_constitution`** — only call from `spec-kit-constitution` skill + after writing the constitution file. Never call this from a feature-level skill. +- **Bug tracking is file-based** — `bugs.md` is the single source of truth. The + MCP server has NO bug tools (removed in adc6b79): bug tools tempted the agent + to bypass the bugs.md write and user-confirmation step. Bugfix/verify routing + parses `bugs.md` directly in the skills. +- **Constitution is project state** — features never check or advance it. The + `project_status` tool is read-only for all skills except `spec-kit-constitution`. +- **Fallback** — when MCP is not configured, all skills fall back to filesystem + artifact detection, `date -u` for timestamps and manual id counting. +- **No persistence** — the server never writes under `specs/` except + `init_feature` (directory + history header). If a tool "succeeds", it means + the files already prove the state; if it errors, fix the files. + +### MCP Error Handling + +The server returns JSON with either `{"success": true, ...}` or +`{"error": "...", ...}`. Skills must check for `"error"` key before proceeding. +Common errors: +- `"Feature 'X' not found"` — `specs/X/` does not exist; `init_feature` creates it +- `"Phase mismatch"` — the files put the feature in a different phase than the skill assumed +- `"not on disk"` — the skill claimed an artifact it never wrote +- `"Feature 'X' is closed"` — log an open bug via spec-kit-test to reopen +- `"Prerequisite not met"` — required artifact is absent or bugs are open + +--- + +## Codebase Tour + +``` +hermes-spec-kit/ +├── AGENT.md # ← This file — agent project context +├── README.md # User-facing quick start +├── user-guide.md # Full workflow documentation (1071+ lines) +├── design.md # Original system design document +├── automation.md # Cron job & automation config +├── migration.md # Migration notes (old → new formats) +├── .hermes/ # Project-level Hermes config (if any) +│ +├── src/ +│ ├── skills/ # 12 skill .md files (source of truth) +│ │ ├── spec-kit-workflow.md # Orchestrator — routes to phase skills +│ │ ├── spec-kit-constitution.md # Phase 0 — project principles +│ │ ├── spec-kit-specify.md # Phase 1 — feature specification +│ │ ├── spec-kit-clarify.md # Phase 1.5 — ambiguity resolution +│ │ ├── spec-kit-plan.md # Phase 2 — implementation planning +│ │ ├── spec-kit-tasks.md # Phase 3 — task breakdown +│ │ ├── spec-kit-review.md # Phase 3.5 — quality review +│ │ ├── spec-kit-implement.md # Phase 4 — TDD implementation +│ │ ├── spec-kit-test.md # Phase 5 — bug tracking +│ │ ├── spec-kit-summarize.md # Phase 6 — close/summary +│ │ ├── spec-kit-refresh.md # Standalone — artifact reconciliation +│ │ ├── spec-kit-epic.md # Standalone — epic plan (time: many features, one goal); optional epics_dir +│ │ ├── spec-kit-design.md # Standalone — module design doc (space: how a part works now); optional design_dir +│ │ └── spec-kit/ +│ │ └── SKILL.md # Umbrella skill — overview only +│ ├── templates/ # 18 template files (*-template.md) +│ │ ├── spec-template.md +│ │ ├── plan-template.md +│ │ ├── tasks-template.md +│ │ ├── constitution-template.md +│ │ ├── bugs-template.md +│ │ ├── close-template.md +│ │ ├── change-record-template.md # the auditor's one page, written at close +│ │ ├── epic-template.md · epic-plan-template.md · epic-features-template.md · epic-review-template.md · epics-index-template.md +│ │ ├── design-doc-template.md # optional document types (epics_dir / design_dir) +│ │ ├── data-model-template.md +│ │ ├── research-template.md +│ │ ├── AGENTS-template.md +│ │ ├── git-conventions-template.md +│ │ └── gitignore-template.md +│ ├── scripts/spec-kit-log.sh · spec-kit-history.sh # no-MCP history appender · git timeline when history is off +│ └── references/ # 8 shared files + skills/ (full procedures — the delta over SKILL.md) +│ ├── preflight.md # Pre-action self-check + commit procedure + no-overwrite rule +│ ├── commits.md # Commit messages per skill (history entry first) +│ ├── history-tracking.md # history.md: when kept (history: always|large|never, spec override), format, guard +│ ├── sizing.md # S / M / L — leaner workflow and artifacts per tier; evidence never shrinks +│ ├── evidence.md # Oracles, evidence files (every tier), status vocabulary +│ ├── acceptance.md # AC ids, verify levels, freeze, the acceptance loop +│ ├── constitution-principles.md # 12 principles × 3 options with pros/cons +│ └── constitution-tables.md # Wizard tables and brownfield detection data +│ +├── spec-kit-mcp-server/ # MCP server (Python, FastMCP) +│ ├── server.py # 19 tools, Python + mcp SDK (<2) +│ ├── test_workflow.py # MCP integration tests in temp git projects +│ ├── test_skills.py # skill/template/reference integrity checks +│ ├── test_server.py # Test runner entry point +│ └── README.md # MCP server docs +│ +├── scripts/ +│ ├── install.sh # Installs skills + templates + MCP to ~/.hermes/ +│ └── uninstall.sh # Full clean uninstall +│ +├── research/ +│ └── sdd-2026.md # Industry research on SDD (June 2026) +│ +└── specs/ # Demo/test feature artifacts (not installed) + ├── bug-life/ + ├── reopen-test/ + └── ... +``` + +--- + +## Installation & Testing + +### Installing ```bash ./scripts/install.sh +# Then in Hermes: /reload-skills && /reload-mcp ``` -Then `/reload-skills` in Hermes. +The install script: +1. Copies each `src/skills/*.md` → `~/.hermes/skills//SKILL.md` +2. Copies umbrella `src/skills/spec-kit/SKILL.md` → `~/.hermes/skills/spec-kit/SKILL.md` +3. Copies templates to `~/.hermes/skills/spec-kit/templates/` +4. Copies references to `~/.hermes/skills/spec-kit/references/` (incl. `references/skills/` — the full per-skill procedures) +5. Copies MCP server to `~/.hermes/skills/spec-kit/mcp-server/server.py` +6. Auto-configures `~/.hermes/config.yaml` with MCP server entry +7. Cleans up old skill formats (flat `.md` files, renamed/obsolete directories) + +**Claude Code edition** — `./scripts/install-claude.sh` generates +`~/.claude/skills//SKILL.md` from the SAME `src/skills/*.md` (frontmatter +reduced to `name`/`description`/`argument-hint`; `terminal`→`Bash`, +`write_file`/`patch`→`Write`/`Edit`, `read_file`→`Read`, `search_files`→`Grep`/`Glob`, +`skill_view`→`Skill`, `mcp_spec_kit_*`→`mcp__spec-kit__*`; `spec-kit/references/…` +paths resolved to `~/.claude/skills/spec-kit/references/…`), symlinks +`references/`, `templates/`, `mcp-server/` and per-skill `references/` to +`~/.hermes/skills/…`, and runs `claude mcp add -s user spec-kit …`. The transform +lives in that one script — when you add a Hermes tool name or a new shared path to +a skill, extend the `subs` table there and re-run both installers. Never edit +`~/.claude/skills/spec-kit*/SKILL.md` by hand. + +### Testing + +**MCP server workflow tests**: +```bash +cd spec-kit-mcp-server +python3 test_workflow.py +``` +Tests: happy path forward, prerequisite enforcement, wrong phase rejection, +duplicate feature, missing feature, reopen flow, reopen guard, update artifact, +next actions progression, auto-detect features. + +**Skill validation tests**: +```bash +python3 spec-kit-mcp-server/test_skills.py +``` +Tests: all skills present, frontmatter YAML, phase coverage, reference/existence, +template existence, cross-skill references, preflight reference, trigger descriptions, +umbrella coverage, reference inventory, workflow diagram phases. + +**Run both:** +```bash +cd spec-kit-mcp-server && python3 test_workflow.py && python3 test_skills.py +``` + +### Skill shape (one screen + full procedure) + +Each `src/skills/.md` is a one-screen checklist (≤ 60 lines, validated by +`test_skills.py`; the whole skill set stays under ~55k tokens): phase, persona, purpose, before-writing checks, steps, done-when +gates, next. The complete procedure lives in `src/references/skills/.md` +and is read on demand. Edit both when behaviour changes; the checklist is what +the agent holds in context across a long phase, the reference is the detail. +Phase skills do not load `spec-kit-workflow`; preflight carries the guardrails +and the MCP phase card carries the state. + +### After modifying skills/templates + +Run validation tests before committing to catch: +- Broken YAML frontmatter +- Missing template/reference references +- Cross-skill link rot +- Phase number mismatches +- Missing preflight or workflow references + +--- + +## Conventions & Rules + +### File Naming + +| Entity | Convention | Example | +|--------|-----------|---------| +| Feature ID | `NNN-kebab-case-name` | `003-user-auth` | +| Feature branch | `feat/NNN-name` or `fix/NNN-name` | `feat/003-user-auth` | +| Skill file | `spec-kit-.md` | `spec-kit-implement.md` | +| Skill directory | `/SKILL.md` | `spec-kit-plan/SKILL.md` | +| Template | `-template.md` | `spec-template.md` | +| Reference | `.md` | `preflight.md` | +| Evidence dir | `specs//evidence/` | per-feature, committed | +| Assumptions log | `specs//decisions.md` | per-feature; unanswered ASKs as assumptions, rulings quoted | +| (legacy) State file | `specs/.spec-kit/state.json` | ignored since v3 — delete + gitignore | + +### Git Conventions + +- **Design phases (0-3)**: Each phase commits immediately — no batch. +- **Implementation (Phase 4)**: One commit per implement sub-phase. + All tests RED first (run saved under `evidence/`), `[SEAM]` tasks probed + against the real system first, all code GREEN (run saved), then commit. +- **Bugfix sub-rounds**: Separate phase commits by default (`bugfix`); + opt-in batch via `quickfix`. +- **Phase 6 close**: ONE commit — patched spec/plan + close.md. +- **Never --no-verify**: hooks are the project's guardrails; fix a hook that + blocks a spec artifact instead of bypassing it. +- **One commit per phase, documentation included**: status-only document + changes (task [X], bug status, evidence) ride the phase's + code commit; only requirement/design-intent changes are committed first. +- **Commit messages**: Follow `commits.md`; the history.md entry is appended first. + Template: `spec(phase-N): [feature] description` for spec phases, + `feat:` / `fix:` for code phases. +- **Branch guardrails**: Block git operations on main/master. Preflight check #1 + enforces this. + +### Evidence of Done (Universal) + +`src/references/evidence.md`. The agent's own statement is never evidence. Gates +name an oracle: `user`, `ci:`, `review:`; claims carry +`output:`/`probe:` files under `specs/[feature]/evidence/`. Bug statuses: +`open → in-progress → claimed → verified(+Verified-by)`; the implementing agent +never sets `verified`. History records `Implemented-by`; review labels itself +`review:` or `self-review`. With two agents installed, the implementer +does not review. + +### Additive-Only Rule (Universal, All Phases) + +**Never overwrite a spec artifact that already has substantive content.** +Every modification must be additive (append new sections, insert new entries) +or targeted-edit (update specific lines/fields). + +- **Allowed**: Append new FR-###, mark tasks [X], change bug status, + insert new sections, patch specific lines. +- **Forbidden**: Delete existing entries, renumber IDs, reformat entire file, + replace >50% of lines. +- **Exception**: First creation (file doesn't exist yet) — may write from template. +- **Exception**: `plan.md` `## Current Design` is REGENERATED at close (and by + refresh) — the one section that is replaced. Bugfix rounds append dated + ADR-style sections under `## Rounds (ADR log)` and name what they supersede. +- **history.md is append-only**: never edit or delete past entries; the close copies its timeline into `change-record.md`. + +Preflight.md section 3 enforces this with a 50-line threshold check. + +### Template Path Convention + +All skills reference templates as `spec-kit/templates/-template.md` — +NOT bare paths like `templates/.md`. This ensures correct resolution +regardless of Hermes profile or working directory. + +### AGENTS.md Downstream Guidelines + +When a consumer project uses spec-kit, their `AGENTS.md` should contain: +- Which spec-kit skills are available +- Active spec directories (features in progress) +- Project tech stack and build commands +- Project-specific conventions + +AGENTS.md should NOT contain: +- Trigger phrase lists (belong in skill files) +- Routing tables (belong in workflow skill) +- Phase diagrams (belong in user guide) +- Bugfix loop mechanics (belong in skills) + +The template at `src/templates/AGENTS-template.md` provides the starter. + +--- + +## Key Design Decisions (with Rationale) + +| Decision | Rationale | +|----------|-----------| +| **Constitution is mandatory bootstrap** (project-level), not per-feature | The constitution defines project-wide principles. Once it exists, all features implicitly operate under it. Per-feature blocking was a category error that caused the LLM to suggest running constitution mid-feature. | +| **Constitution is injected as guidance, enforced by review** | Phase skills receive constitution principles as context and use them as guidance. They never gate or block on constitution. The review skill is the designated enforcement point — it checks alignment and reports findings, but doesn't block. | +| **Phase 6 is mandatory** | Prevents feature accretion and half-finished work. Every feature gets a close audit. | +| **Additive-only artifacts** | Prevents AI from accidentally destroying work. The only safe mutation mode for AI-generated content. | +| **Design phases commit individually** | Each design decision is checkpointed. The user can review and amend per-phase without losing prior work. | +| **Phase-level TDD** | Scales TDD to feature level. One RED→GREEN cycle per implement sub-phase, not per function. | +| **TDD bypass at user request** | Not all features benefit from test-first. Pragmatic > dogmatic. | +| **One umbrella regression task** | Individual bugs would create noise. A single BF-REGRESSION-001 task covers the regression round. | +| **MCP is optional** | Keeps the skill set usable even without MCP infrastructure. The filesystem is always available. | +| **Project state separate from feature state in MCP** | Prevents the constitution from being treated as a per-feature phase. Clean separation of concerns between project bootstrap and feature lifecycle. | +| **9 purposes × 25 architectures** | Covers the full spectrum of project types while keeping the decision tree manageable. | +| **Free-text + guided + brownfield** | Three modes for three user contexts — fast (free-text), thorough (guided), or detected (brownfield). | +| **Separate workflow skill** | Prevents routing logic from mixing with phase execution logic. Each skill stays focused. | +| **history.md append-only** | The process record that survives the squash-merge; `change-record.md` at close copies it for the auditor. | + +--- + +## Working on This Repo — Common Tasks + +### Adding a new template + +1. Create `src/templates/-template.md` with YAML frontmatter +2. Add the filename to `EXPECTED_TEMPLATES` in `test_skills.py` +3. Update relevant skills to reference the new template +4. Run validation tests +5. Run `./scripts/install.sh` to deploy + +### Adding a new reference + +1. Create `src/references/.md` with relevant content +2. Add the filename to `EXPECTED_REFERENCES` in `test_skills.py` +3. Update skills to reference (`spec-kit/references/.md`) +4. Run validation tests +5. Run `./scripts/install.sh` to deploy + +### Modifying a skill + +1. Edit `src/skills/.md` — never edit `~/.hermes/skills/` directly +2. Update frontmatter version if making substantive changes +3. Run `test_skills.py` to validate cross-references and structure +4. Run `./scripts/install.sh` to deploy +5. Verify with `skill_view(name='')` in Hermes + +### Modifying the MCP server + +1. Edit `spec-kit-mcp-server/server.py` +2. Run `test_workflow.py` to verify state machine integrity +3. Run `test_skills.py` to verify no skill reference breakage +4. Run `./scripts/install.sh` to deploy +5. If adding tools: update the AGENT.md tool table AND the MCP section in + `src/skills/spec-kit/SKILL.md` AND `spec-kit-mcp-server/README.md` + +### Adding a new feature (for spec-kit itself) + +Follow the spec-kit workflow! This repo uses its own skills: +1. Ensure constitution exists (`specs/constitution.md`) +2. Create spec (`specs/NNN-name/spec.md`) +3. Plan, task, implement, test, close +4. Branch: `feat/NNN-kebab-name` + +--- + +## Important Guardrails (CAUTION) + +0. **Read first, build second.** When a skill or template mirrors an existing system (upstream spec-kit, a project's ADR or review format), read its actual design docs, templates and workflows before writing — never build a simplified approximation from memory. + +1. **Never restructure existing working skills without explicit user consent.** + One new file = one new file. Refactoring skills is a conversation, not an action. +2. **Never delete content from spec artifacts.** The additive-only rule is universal. +3. **Never run git operations on main/master.** Preflight check #1 enforces this. +4. **Never advance a phase outside its owning skill.** Only the phase skill that + produces the transition artifact may call advance_phase. +5. **Never overwrite ~/.hermes/skills/ with partial installs.** Always run the + full `./scripts/install.sh`. +6. **Never edit installed files in ~/.hermes/skills/.** Edit source files in + `src/` and reinstall. +7. **Pre-flight self-check is not optional.** Branch, mode, logged bug, phase card, history — + run them before every action. +8. **When in doubt about the current state, run `get_feature_state` or + `project_status` (MCP), or scan the artifact directory.** Do not guess. + +--- ## Communication Style -Concise. Show commands over explanations. Confirm before destructive operations. Ask for clarification when blocked. +Concise. Show commands over explanations. Confirm before destructive operations. +Ask for clarification when blocked. When reporting errors from MCP or tests, +include the raw error message so the user can diagnose. -**Never restructure existing working skills without explicit user consent.** One new file = one new file. +For downstream project AGENTS.md templates, keep routing mechanics out — only +project-specific context belongs there. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..08b5f1f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,414 @@ +# Changelog + +All notable changes to the Hermes Spec Kit project. + +Format: [Keep a Changelog](https://keepachangelog.com/). + +--- + +## [Unreleased] + +### Added — epics and module design docs (opt-in) + +- **`spec-kit-epic`** — an epic is one body of work in *time*, run through the same shape as + a feature in `[epics_dir]/NNN-name/` (NNN = the tracker's epic number, e.g. the ADO epic; + else `next_id kind="EPIC"`): **E1 specify** `epic.md` (goal, scope and non-goals, + `EAC-###` epic acceptance criteria with how each is verified, cross-feature rules, epic-level + Security & Privacy) → **E2 plan** `plan.md` (current state, target architecture, seams + today → after, `ED-###` cross-feature decisions, sequencing, rollout / rollback, risks) → + **E3 breakdown** `features.md` (the epic's tasks are features: ordered rows with size, + depends-on, modules, EACs, status) → **E3.5 review** `review.md` (coverage, fit, sequencing + + **devil's advocate**: the case against the epic and the ~80 % alternative, a six-month + pre-mortem, system-level abuse cases, the riskiest assumption; verdict GO / GO-WITH-CHANGES + / NO-GO, required before the first feature) → **E4 build** (features run the normal + workflow; `specify` fills the row, each close flips it) → **E6 close** (every EAC verified + with evidence, close review round, `ED-###` through the ADR bar). +- **`spec-kit-design`** — a living module design doc (`design-doc-template.md` in + `design_dir`): one bounded part of the system in *space* — purpose, components, data flow, + seams, invariants and security (`path:line`), testing, debt, ADRs; ≤ 3–4 pages, patched in + place, never copied to `-v2`. The plan names the modules it touches (`**Modules**:`); the + feature close patches the affected sections with approval. +- Both are **opt-in**: `epics_dir` / `design_dir` in `specs/git-conventions.md`. A small + project sets neither and nothing is ever created unprompted; `lint_artifacts` warns when a + spec or plan names an epic / module the project does not keep, and `project_status` hints + when 3+ specs share an epic or 3+ closed features share a module without the dir. + +- **Epic as a PRD**: `epic.md` carries *Problem and users (why now)*, *Success metrics* + (post-launch, lagging — today / target / measured how) and *Alternatives considered* (incl. + do nothing) before Scope — the PR-FAQ shape for a programme. +- **Epics index** (`[epics_dir]/README.md`, `epics-index-template.md`) — the roadmap table, one + row per epic (id · status · owner · tracker · features closed / planned), maintained by + `spec-kit-epic` and by every feature close; `epics_index: on | off` in git-conventions.md + (default on). `project_status` hints when it is missing. +- **`system.md`** — the reserved module name in `design_dir`: the one-page C4 L1/L2 system view + (containers, stores, external systems, trust boundaries) every module doc links to. +- **Close widens "docs the diff makes wrong"** to runbooks (`runbooks_dir`) and adds one + Keep-a-Changelog *Unreleased* line (`changelog`); both opt-in keys in git-conventions.md. + +### Changed — leaner tiers, the change record, devil's advocate + +- **Size tiers are progressively leaner in workflow and artifact length — never in evidence** + (`references/sizing.md`, `references/evidence.md`). S is for a single bugfix or a small + enhancement: a few-line spec (1–3 FRs, 1–2 ACs, one Security & Privacy line), a half-page + plan, a flat task list, one commit for spec+plan+tasks, no pre-implement review. M runs a + **lite** pre-implement review (coverage, underspecification, codebase fit, design soundness + + devil's advocate), L the full one. Every tier saves RED/GREEN files per phase and a probe + per seam, and ends with an acceptance round that documents every AC — automated where a + harness exists, `manual` with the user's quoted confirmation where none can. +- **`change-record.md` at close** (`change-record-template.md`) — the one page an auditor + reads: ticket, branch/PR, size, what/why, Security & Privacy impact, data/config changes, + implemented-by, reviewed-by (agent + human PR reviewer), verification, decisions, deployment + approval, rollback, follow-ups, and the timeline from git. `close_feature` requires it. +- **Security & Privacy section in spec.md** (authorization / tenant boundary, personal data, + new surface, input validation, logging) — "None — because …" is a valid answer; the plan + answers each non-empty row, the pre-implement review checks it, the final review §2 verdicts it. +- **`history.md` is a project setting, default `history: large`** (git-conventions.md: + `always | large | never`; spec.md `**History**: on | off` overrides per feature). Size L keeps + the per-phase record (entry before every commit, `history_guard` enforces); S/M do not — the + close builds the change record's timeline from the branch's git log + (`scripts/spec-kit-history.sh`, before the squash) and `Implemented-by` lives in the tasks.md + header. The MCP server stores nothing: the setting is in the files, so both agents and every + machine see the same answer and it travels with the PR. `init_feature` writes history.md only + under `always`; `lint_artifacts` requires it only when on. `references/commits.md` replaces + `auto-commit.md`. Commit hashes are still never recorded. +- **Final review is exceptions-only** (`review-final-template.md`): §1 is one coverage line + + rows for ⚠️ / ❌ / ↔ / 👤 (the AC matrix lives in acceptance.md, the FR map in tasks.md). New + verdict **`AWAITING-OWNER`** — no defect, owner confirmations pending; a specs-only Round + N+1 with the owner's quoted answers turns it READY without a bugfix cycle. `close_feature` + names the owner instead of sending the feature to bugfix. +- **Devil's advocate pass in both reviews** (§4 of the final round; a section of the + pre-implement report): strongest case against + simpler alternative, pre-mortem, abuse cases + per seam, riskiest assumptions; concrete break attempts and "would this test still pass if + the code were wrong?" after implementation. ≤ 5 objections, each answered (accepted / + rebutted with evidence / deferred); unanswered blocks READY for L, where it runs as a separate + sub-agent. The final review reads code and spec **before** decisions.md. +- **One close template.** `implementation-summary-template.md` is gone; `close-template.md` + carries the gap table at the depth the tier needs (M exceptions, L "summarize" full). + `implementation-summary.md` is still recognised as a legacy close document. +- **Deduplicated skills.** One-screen SKILL.md files are ≤ 60 lines; `references/skills/*.md` + hold only the delta (clarify and refresh need none). `preflight.md` 173 → 40 lines; the + workflow procedure 331 → 70; the tasks template is a legend plus one example, not a + greenfield scaffold; the umbrella and workflow skills no longer trigger on phase commands. + Whole skill set: ~85k → ~45k tokens; `test_skills.py` enforces the budget. +- `decisions.md` records only questions the **user** would want to decide; design choices + within the plan's remit stay in plan.md (preflight check 6). +- Installers: `install.sh` moves unshipped top-level references aside (`references/local/`) + and removes superseded full procedures; the Claude edition note block is four lines. + +## [Previous unreleased] + +### Added + +- **Acceptance criteria and the automatic acceptance loop** (`references/acceptance.md`). + spec.md criteria are `**AC-###** (FR-…) Given/When/Then — Verify: `, the level being + the lowest that proves it (unit · integration · component · e2e (reason) · command · probe · + manual (reason)). The plan maps each AC to a harness and test file; tasks tag the tests + `[TEST] [AC-###]` and test names carry the id. Implement freezes the acceptance tests after + their RED run (`acceptance_freeze`). After implement, `accept [feature]` (spec-kit-test + accept mode) runs the full fast suites plus only this feature's e2e specs (only when the + stack is up — else deferred), builds the AC matrix from JUnit/TRX (`acceptance_status`), + logs every failure as a bug and auto-chains the bugfix loop, round after round, until PASS + or a stop condition (5 rounds, no progress, spec or frozen-test change, run cannot + execute). `acceptance.md` rounds (Result + Commit) gate the final review and the close. +- **Final review (phase 5.5) — mandatory merge gate.** `spec-kit-review` final mode replaces + the optional post-implement review: requirement-by-requirement spec conformance (code + `path:line` + proving test), every applicable constitution MUST / project rule verdicted, + code quality and best practice, test quality, and a merge checklist + (`specs/merge-checklist.md`, template `merge-checklist-template.md`) whose commands run with + saved evidence. Output: `review-final.md` rounds with `**Verdict**` and `**Reviewed-commit**`. + CRITICAL/HIGH findings become bugs. Prefers the other agent or a fresh-context sub-agent. +- **ADRs and AGENTS.md at close.** `spec-kit-summarize` harvests decisions (decisions.md + rulings, plan rounds, research, review findings, deviations), applies the ADR bar, and + writes / supersedes / amends project ADRs (project template, else `adr-template.md`), + updates the ADR index, and proposes targeted AGENTS.md patches. Close documents carry an + `## Architecture Decisions` table. +- **Size tiers S / M / L** (`references/sizing.md`): specify always asks, recommendation + first; `**Size**:` in spec.md. S trims the templates and auto-chains specify → plan → tasks + into one commit; L requires the pre-implement review. Evidence, history and the final-review + gate do not shrink with the tier. +- MCP: `diff_scan` tool (merge conflicts, secrets, forbidden files, focused tests, TODOs, + unplanned files); `next_id(kind="ADR")`; `get_feature_state` reports `size` and + `final_review` (verdict, reviewed commit, stale); `advance_phase(5)` and `close_feature` + require a fresh READY final review, `close_feature` an Architecture Decisions section; + `lint_artifacts` checks review-final rounds, the Size line and the ADR section; + `project_status` reports the merge checklist and ADR directory. +- git-conventions template: `## Documentation locations` (`adr_dir`, `adr_index`, + `agents_file`, `merge_checklist`). + +### Fixed + +- **install.sh / uninstall.sh corrupted `~/.hermes/config.yaml`** when the + `spec-kit` MCP block was written with `args:` as a YAML list (4 lines): the + line-count `sed` left a dangling `- …server.py` line and appended a second + `mcp_servers:` key. Replaced by `scripts/hermes-mcp-config.py`, which edits + by indentation, keeps other servers, reuses an existing `mcp_servers:` key + and backs the file up first. + +### Changed + +- **Hygiene.** (1) Assumptions log: `decisions-template.md` and preflight + check 6 — an ASK that no human answered is recorded as an *assumption* with + the alternative not taken, never as a self-made ruling; real rulings quote + the user; reviews read `decisions.md` first and the close lists open + assumptions. (2) `--no-verify` removed everywhere: hooks are the project's + guardrails. (3) Commit granularity: one commit per phase carrying its + status-only document changes; spec-before-code only for requirement or + design-intent changes. + +- **TDD rules that can be checked.** The "Iron Law" (delete code written + before the test) is replaced by file-based rules: a `[TEST]` task's RED run + is saved under `specs/[feature]/evidence/` before implementation; a `[SEAM]` + task (database function, HTTP contract, file format, external service) starts + with a read-only probe of the real system and its fixture must match the + probe's shape; legacy code gets a characterisation test first; GREEN and the + regression runs are saved too. tasks template documents `[TEST]`/`[SEAM]`; + `lint_artifacts` warns on `[SEAM]` done without a probe file and `[TEST]` + done without a RED file. + +- **plan.md: Current Design + ADR rounds.** The plan template gains a + `## Current Design` section (≤ 1 page, what is built; regenerated at every + close and by refresh — the only replaced section) and a `## Rounds (ADR log)` + section where each bugfix/reopen round appends one dated entry (Context / + Decision / Consequences / Plan Ref) naming what it supersedes. Append-only + plans no longer contradict themselves across rounds. `lint_artifacts` warns + when a closed feature's plan lacks the section. + +- **history.md is a record, not a story.** Fixed-field entries (timestamp | + phase | skill | agent; Artifacts, Tests, Evidence, Commit, Note ≤ 25 words; + ≤ 60 words total), appended by the new `append_history` MCP tool or the + shipped `spec-kit/scripts/spec-kit-log.sh` — both stamp the real UTC time. + Narrative moves to implementation-summary.md. `history-tracking.md` and the + template rewritten; the Shared Commit Procedure uses the appender. + +- **Skill diet.** Every `src/skills/.md` is now a one-screen checklist + (≈40 lines: phase, persona, purpose, before-writing, steps, done-when, next); + the full procedure moved to `src/references/skills/.md` and is loaded on + demand. Phase skills no longer ask to load `spec-kit-workflow` — preflight + carries the guardrails and the MCP phase card carries the state. Per-phase + instruction load drops from 6–10 k tokens to roughly 2.7 k (most of it the + shared preflight). `test_skills.py` + enforces the ≤ 110-line limit and the pointer to the full procedure; both + installers ship `references/skills/`. + +- **MCP server v3 — derive-and-enforce, no persisted state.** `state.json` was a + second source of truth that drifted (30 of 34 features out of sync in one + deployment) and conflicted on every merge. Every tool now derives the phase + from `specs//` on each call and writes nothing (`init_feature` + creates the directory + history header only). `advance_phase`, + `close_feature`, `update_artifact`, `project_set_constitution` validate + against disk. New enforcement tools: `next_id`, `lint_artifacts`, + `timestamp`, `history_guard`; `get_next_actions`/`get_feature_state` return a + ten-line phase card to re-read after compaction. Legacy `state.json` is + flagged and ignored; gitignore template ignores `specs/.spec-kit/`. Tests + rewritten against real files in temp projects. + +### Added + +- **Evidence of Done** (`src/references/evidence.md`) — every gate needs an + oracle the agent did not author (`user`, `ci:`, `review:`) + or evidence files (`output:`, `probe:` under `specs/[feature]/evidence/`). + Bug status split `claimed` (agent's word) vs `verified` (+`Verified-by`); + legacy `resolved`/`fixed` read as `claimed`. The implementing agent never + sets `verified`; summarize never changes statuses and lists unverified + claims. History records `Implemented-by`; review labels `review:` or + `self-review`. External seams require a real-data `probe:` whose shape the + test fixture must match. + +- **Claude Code edition** (`scripts/install-claude.sh`) — installs the same + skills for Claude Code from the same `src/skills/*.md` sources (generated + `~/.claude/skills//SKILL.md` with Hermes tool names translated and a + "Claude Code edition" header), symlinks `references/`, `templates/` and + `mcp-server/` to the installed Hermes tree so both agents read identical + shared files, and registers the spec-kit MCP server for Claude Code at user + scope (`mcp__spec-kit__`). Enables dual-agent hand-offs on one `specs/` + tree (e.g. Claude Code: specify → plan → tasks; Hermes: implement). + `--no-mcp` and `--uninstall` flags. + +## [2.0.0] — 2026-07-10 + +Version 2 adds an MCP server for deterministic workflow state management, +decouples the constitution from the per-feature phase cycle, and strengthens +the review skill with codebase architecture analysis and a nitpick filter. + +### Added + +- **MCP server** (`spec-kit-mcp-server/server.py`) — FastMCP stdio server with + 14 tools for deterministic workflow orchestration: `init_feature`, + `get_feature_state`, `get_next_actions`, `advance_phase`, `project_status`, + `project_set_constitution`, `list_features`, `reopen_feature`, + `close_feature`, `update_artifact`, `auto_detect_features`. + State stored in `specs/.spec-kit/state.json` per project. +- **Project-level state model** — `project {}` namespace in state separates + constitution status from feature lifecycle. Features start at phase 1 + (specify). Constitution is tracked via `project_status` / + `project_set_constitution` tools. +- **Workflow bootstrap gate** — `spec-kit-workflow` checks constitution once + per session and routes to `spec-kit-constitution` if missing. No feature + skill ever blocks on constitution. +- **Constitution context injection** — Workflow injects constitution principles + as guidance (not gates) when routing to feature skills. +- **Review scope boundaries** — Pre-implement review has explicit IN/OUT + scope rules. Project-level issues go to a "Project-Level Notes" section + instead of blocking the feature. +- **Codebase architecture analysis** — Pre-implement review scans existing + project structure to evaluate plan fit and integration risk. +- **Best-practice validation** — Pre-implement review researches current + recommended practices for each technology in the plan. +- **Design soundness evaluation** — Pre-implement review assesses abstraction + level, scalability, and data flow coherence. +- **Nitpick filter** — Both review modes explicitly skip cosmetic/style + findings. Minimum bar: finding must harm correctness, security, performance, + maintainability, or testability. +- **Workflow integration tests** (`test_workflow.py`) — 11 tests for happy + path, prerequisite enforcement, reopen flow, project state, and error cases. +- **Skill validation tests** (`test_skills.py`) — 12 checks for frontmatter, + phase coverage, reference/template existence, cross-skill links, preflight + compliance. +- **CI workflow** — GitHub Action runs tests on every commit. +- **`uninstall.sh`** — full spec-kit removal including MCP config. +- **Auto-install** of `mcp` Python SDK in `~/.hermes-venv/` during setup. + +### Changed + +- **Constitution decoupled from features** — Was per-feature phase 0, is now + project-level bootstrap. Skills no longer BLOCK/HALT/WARN on constitution. + `advance_phase` refuses phase-0 transitions. +- **`init_feature` starts at phase 1** — No more per-feature constitution + requirement. +- **Constitution skill uses `project_set_constitution`** — instead of + `advance_phase(feature="[feature]", from_phase=0)`. +- **Review CRITICAL severity narrowed** — No longer includes constitutional + alignment. Covers security, data integrity, architecture violations, + and uncovered requirements only. +- **Review post-implement checks rewritten** — Focus on architecture + conformance, layer boundaries, error handling chains, security, + concurrency, structural duplication. +- **MCP server rewritten to FastMCP SDK** — replaces hand-rolled + Content-Length framing with `mcp` Python SDK's stdio transport. +- **`install.sh` writes `config.yaml` directly** — avoids `hermes mcp add` + timeout during headless install. +- **Auto-detection of legacy v1 state** — migrates to v2 format on load. + +### Removed + +- **`log_bug`, `set_bug_status`, `set_bug_plan_ref` MCP tools** — bug + tracking is purely file-based (`bugs.md` is single source of truth). + Determined redundant to file operations. +- **Constitution as per-feature prerequisite** — removed from all feature + skills' prerequisite tables, validation blocks, and enforcement sections. +- **Per-skill constitution context sections** — removed from + `spec-kit-specify.md` and `spec-kit-plan.md`. Workflow context injection + handles this once at routing. +- **`spec_kit_` prefix from MCP tool names** — tools use bare names; + Hermes adds `mcp_spec_kit_` at the client layer. + +### Fixed + +- LLM no longer suggests running `spec-kit-constitution` mid-feature in + response to review findings. +- `install.sh` no longer corrupts `config.yaml` with `grep -v`. + +--- + +## [1.0.0] — 2026-06-10 + +Version 1 is the full skill-based spec-driven development system without +MCP integration. 101 commits built the workflow over ~6 weeks. + +### Skills (12) + +| Skill | Phase | Purpose | +|-------|-------|---------| +| `spec-kit-workflow` | — | Orchestrator — routes to phase skills | +| `spec-kit-constitution` | 0 | Project principles (brownfield/free-text/wizard) | +| `spec-kit-specify` | 1 | Feature specification | +| `spec-kit-clarify` | 1.5 | Ambiguity resolution | +| `spec-kit-plan` | 2 | Implementation planning | +| `spec-kit-tasks` | 3 | Task breakdown | +| `spec-kit-review` | 3.5 / 5.5 | Quality gate (pre/post implement) | +| `spec-kit-implement` | 4 | Phase-level TDD execution | +| `spec-kit-test` | 5 | Bug tracking | +| `spec-kit-summarize` | 6 | Close/summary with health score | +| `spec-kit-refresh` | — | Artifact reconciliation | +| Umbrella `spec-kit/SKILL.md` | — | Overview and quick reference | + +### Three Development Modes + +- **Specify** (default): Constitution → Specify → [Clarify] → Plan → + Tasks → [Review] → Implement → Test → Close +- **Bugfix**: Auto-chains Plan → Tasks → Implement → Test → Close + (with separate per-phase commits or opt-in `quickfix` batching) +- **Reopen**: Bugfix branch from closed feature, preserves original close, + additive-only edits, re-close required + +### Constitution Decision Tree + +- 3 modes: brownfield (auto-detect from 60+ patterns), free-text (describe + project in a sentence), guided wizard (3-level interactive) +- 9 purpose types (A-I): User-Facing App, Content Site, Native/Desktop, + Library/SDK, Infra/CLI, Game, Browser Extension, Research/Notebook, + IoT/Embedded +- 25 architecture variants across all purposes +- 12 constitution principles with purpose-weighted defaults and 3 option + levels (Strict/Pragmatic/Permissive) +- Monorepo support with per-sub-project purpose/architecture/tech + +### Key Behaviors + +- **Constitution mandatory** — specify and plan block without it +- **Design phases (0-3) commit individually** — each document change is + checkpointed +- **Phase-level TDD** — all tests RED first, all code GREEN, one commit + per phase (optional bypass) +- **Umbrella regression** — one BF-REGRESSION-001 task, not individual bugs +- **Additive-only editing** — spec artifacts never overwritten; mutations + are append/insert/targeted-patch +- **Phase 6 mandatory** — feature cannot complete without close or summary +- **Spec health score** — computed at close: (resolved + acknowledged) / + total FRs * 100 +- **Branch guardrails** — blocks git operations on main/master +- **Pre-action self-check** (`preflight.md`) — branch, mode, workflow, + history validation before every action +- **`history.md` append-only** — immutable process log per feature +- **Drift detection** — implementation-summary/close artifact state table + flagged on stale artifacts +- **Natural language triggers** — skills respond to `spec-kit` prefix, + `speckit` prefix, and plain NL phrases + +### Templates (13) + +spec, plan, tasks, constitution, bugs, close, implementation-summary, +data-model, research, history, AGENTS, git-conventions, gitignore. + +### References (5) + +preflight, auto-commit, history-tracking, constitution-principles, +constitution-tables. + +### Filesystem State Detection + +Phase determined by artifact presence in `specs/` directory (no MCP): + +| Artifacts | Phase | +|-----------|-------| +| constitution.md | Ready to Specify | +| spec.md | Specified | +| clarify.md | Clarified | +| plan.md | Planned | +| tasks.md | Tasked | +| tasks.md with completions | Implementing | +| bugs.md with open bugs | Testing | +| bugs.md all verified | Must close | +| close.md / implementation-summary.md | Complete | + +--- + +## Legend (skill versions) + +| Skill | v1 | v2 | +|-------|----|----| +| spec-kit-constitution | 1.0.0 | 2.1.0 | +| spec-kit-implement | 1.0.0 | 1.2.0 | +| spec-kit-review | 1.0.0 | 1.2.0 | +| spec-kit-workflow | 1.0.0 | 1.1.0 | +| All other skills | 1.0.0 | 1.1.0 | diff --git a/README.md b/README.md index b7d8a3b..694920a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Hermes Spec-Kit -Spec-driven development for Hermes Agent. 13 skills implementing a structured phase-based workflow with three development modes, a constitution 3-level decision tree (9 purposes × 25 architecture options), mandatory close with spec health scoring, and a reopen flow for fixing closed features. +Spec-driven development for Hermes Agent. 11 skills implementing a structured phase-based workflow with three development modes, a constitution 3-level decision tree (9 purposes × 25 architecture options), mandatory close with spec health scoring, and a reopen flow for fixing closed features. Includes an optional MCP server for deterministic state management. ## Quick Start @@ -8,10 +8,12 @@ Spec-driven development for Hermes Agent. 13 skills implementing a structured ph # 1. Clone (if you haven't already) and install git clone https://github.com/kmarecki/hermes-spec-kit.git cd hermes-spec-kit -./scripts/install.sh # copies skills + templates to ~/.hermes/skills/ +./scripts/install.sh # copies skills + templates + MCP server to ~/.hermes/skills/ +./scripts/install-claude.sh # (optional) the same skills for Claude Code → ~/.claude/skills/ -# 2. Reload skills in your Hermes session +# 2. Reload skills and MCP in your Hermes session /reload-skills # or start a new session +/reload-mcp # if MCP server was auto-configured # 3. Go to your project, create a spec cd /path/to/your-project @@ -43,12 +45,20 @@ Full workflow documentation: **[user-guide.md](user-guide.md)** ```text src/ - skills/ # Skill source files (12 .md + 1 umbrella directory) + skills/ # Skill source files (13 .md + 1 umbrella directory) spec-kit/SKILL.md # Umbrella skill — overview and quick reference - templates/ # Template source files (14 templates, all *-template.md) - references/ # Reference files (4: preflight, auto-commit, history-tracking, + more) + templates/ # Template source files (23 templates, all *-template.md) + references/ # preflight, commits, history-tracking, evidence, sizing, acceptance, constitution-* + skills/ # Full procedure per skill — loaded on demand by the one-screen SKILL.md + skills/ + spec-kit-bugfix/ [removed] — function absorbed into spec-kit-workflow scripts/ - install.sh # Installs to ~/.hermes/skills/ + install.sh # Installs to ~/.hermes/skills/ + MCP config + uninstall.sh # Full clean uninstall (skills, MCP, config) +spec-kit-mcp-server/ + server.py # MCP server — 19 tools, Python + mcp SDK (<2) + README.md # MCP server docs + test_server.py # Smoke test ``` ## Three Development Modes @@ -61,7 +71,10 @@ scripts/ ## Skills -13 skills covering every phase + refresh and workflow routing. +11 skills covering every phase + refresh and workflow routing. +(The former `spec-kit-bugfix` alias skill was removed — its function is absorbed into the +workflow skill's bugfix routing.) + See the [Phase Reference section](user-guide.md#phase-reference) in the user-guide for phases, purposes, and personas. All skills respond to three trigger styles: `spec-kit` prefix, `speckit` prefix, and natural language @@ -117,6 +130,125 @@ monorepo?" If yes, Levels 1-3 run independently per sub-project, and the constit Full walkthrough: see [Constitution Decision Tree](user-guide.md#constitution-decision-tree) in the user-guide. +## MCP Server (Optional) + +An MCP server (`spec-kit-mcp-server/server.py`) is a **derive-and-enforce** service: it +keeps no state, derives every feature's phase from the files under `specs//` on +each call, and does the things an agent does badly — id allocation, artifact lint, real +timestamps, the acceptance matrix, the merge-readiness diff scan, and a ten-line phase card to +re-read after context compaction. 19 tools exposed as `mcp_spec_kit_*` in Hermes (`mcp__spec-kit__*` in +Claude Code). + +**Tools:** + +| Tool | Purpose | +|------|---------| +| `init_feature` | Create `specs//` with a history.md header | +| `get_feature_state` | Derived phase, artifacts, task/bug counts, phase card | +| `get_next_actions` | Available actions + the phase card | +| `advance_phase` | Validate a transition against the files (writes nothing) | +| `project_status` | Constitution present?, feature count, legacy state file? | +| `project_set_constitution` | Confirm `specs/constitution.md` exists | +| `list_features` | Every feature's derived state | +| `reopen_feature` | Check closed, return branch hint | +| `close_feature` | Validate the close (bugs verified with Verified-by; lists claimed-unverified) | +| `update_artifact` | Confirm an artifact is on disk | +| `auto_detect_features` | Derived state of all features | +| `next_id` | Next BUG / T / BF id by scanning the files | +| `lint_artifacts` | Schema lint of bugs.md, tasks.md, spec ACs, acceptance.md, review-final.md (size-aware) | +| `timestamp` | Real UTC time | +| `acceptance_freeze` / `acceptance_status` | Freeze the AC tests after RED; AC → test → result matrix | +| `diff_scan` | Mechanical merge-readiness scan of the branch diff | +| `history_guard` | Fresh history entry since the last commit? | +| `append_history` | Append a fixed-field, time-stamped, word-capped history entry | + +**State file**: none. The files are the state. A legacy `specs/.spec-kit/state.json` is +ignored — delete it and add `specs/.spec-kit/` to `.gitignore` (the gitignore template does). + +**Bug tracking is file-based**: bugs live in `specs/NNN-name/bugs.md` — the single +source of truth. The MCP server intentionally has no bug tools; bugfix routing +parses bugs.md directly. + +**Dependency**: Requires the [mcp Python SDK](https://pypi.org/project/mcp/) pinned +to `<2` (`mcp 2.x` renamed FastMCP → MCPServer and breaks this server). Install +from `spec-kit-mcp-server/requirements.txt`; the install script auto-installs it +in a venv at `~/.hermes-venv/`. + +**Fallback**: When the MCP server is not configured, all skills fall back to +filesystem-based artifact detection — backward compatible, no skill changes needed. + +**Installation**: `install.sh` copies the server and auto-configures via `hermes mcp add`. +Activate in Hermes with `/reload-mcp`. + +**Claude Code**: `install-claude.sh` registers the same server at user scope +(`claude mcp add -s user spec-kit …`); the tools appear as `mcp__spec-kit__`. +Both agents derive the same state from the same files; nothing is persisted. + +Full docs: [spec-kit-mcp-server/README.md](spec-kit-mcp-server/README.md) + +## Claude Code (dual-agent use) + +The same skills install for **Claude Code** from the same sources, so Hermes and +Claude Code can hand phases to each other on one `specs/` tree — e.g. Claude Code +runs `/spec-kit-specify`, `/spec-kit-plan`, `/spec-kit-tasks`, Hermes runs +`spec-kit implement`, Claude Code runs `/spec-kit-summarize`. + +```bash +./scripts/install-claude.sh # → ~/.claude/skills/spec-kit*/SKILL.md + MCP registration +./scripts/install-claude.sh --no-mcp # skills only +./scripts/install-claude.sh --uninstall +``` + +What the installer does: + +1. Transforms each `src/skills/*.md` into a Claude Code `SKILL.md` — frontmatter + reduced to `name` / `description` / `argument-hint`, Hermes tool names translated + (`terminal` → `Bash`, `write_file`/`patch` → `Write`/`Edit`, `read_file` → `Read`, + `search_files` → `Grep`/`Glob`, `skill_view` → `Skill`, `mcp_spec_kit_*` → + `mcp__spec-kit__*`), shared-file paths resolved, and a "Claude Code edition" note + added under the title (arguments, how to load another skill, tool mapping). +2. **Symlinks** `references/`, `templates/` and `mcp-server/` to the installed Hermes + tree (`~/.hermes/skills/spec-kit/…`), including per-skill `references/` folders — + one source of truth, so what Hermes reads is what Claude Code reads. Falls back to + copying from `src/` when Hermes is not installed. +3. Registers the MCP state server for Claude Code at user scope (skipped with `--no-mcp` + or when already registered). + +Invoke in Claude Code as `/spec-kit-specify `, `/spec-kit-plan `, … +(`$ARGUMENTS` carries the feature) or by the same natural phrases as in Hermes. +Restart Claude Code after installing. Re-run the installer after editing any +`src/skills/*.md` — the generated files say so in their header and must not be +edited by hand. + +## Running Tests + +Two test suites validate the project: + +**MCP server workflow tests** (11 tests) — exercises the server state machine +via the `mcp` Python SDK client. No Hermes session needed. + +```bash +cd spec-kit-mcp-server +pip install mcp +python3 test_workflow.py +``` + +**Skill validation tests** (12 checks) — validates all skill markdown files: +frontmatter YAML, reference/template file existence, cross-skill links, +phase coverage, pre-flight compliance, and workflow diagram completeness. + +```bash +pip install pyyaml +python3 test_skills.py +``` + +Run both together: + +```bash +pip install -r spec-kit-mcp-server/requirements.txt +python3 spec-kit-mcp-server/test_workflow.py && python3 spec-kit-mcp-server/test_skills.py +``` + ## Key Design Decisions - Constitution is mandatory for all features — specify and plan block if missing @@ -132,3 +264,5 @@ in the user-guide. - Spec health score computed at close (0-100%) - Branch guardrails block git operations on main/master - Pre-action self-check in every skill (branch, mode, workflow) +- MCP server (optional): deterministic state, compaction-proof, uses `mcp` Python SDK +- Skills fall back to filesystem detection when MCP server is not configured (backward compatible) diff --git a/research/workflow-critical-analysis-2026-10.md b/research/workflow-critical-analysis-2026-10.md new file mode 100644 index 0000000..7402f52 --- /dev/null +++ b/research/workflow-critical-analysis-2026-10.md @@ -0,0 +1,159 @@ +# Spec-kit workflow — critical analysis + +> **Status:** analysis, 2026-10-22. No workflow changes proposed here have been applied. +> Evidence comes from the 12 installed skills (v1.1–2.1), the shared references, the MCP server, and one real deployment: the `oesgpoint` repository (37 spec-kit features, 1 323 history entries, 405 logged bugs) plus the merge review of `370-v2-reader-cross-domain-ops` done the same day. + +## 1. Scope and method + +Three questions: + +1. Where does the workflow deliver, and where does it produce ceremony without control? +2. Which rules assume capabilities that today's LLM agents (Claude, Hermes-hosted models) do not reliably have? +3. What should change, and in which order? + +Method: read every skill and reference; measure the artifacts the workflow produced in a real repository; cross-check with one end-to-end case where the workflow's own gates passed but the code was wrong. + +## 2. What the real deployment shows + +| Measure (oesgpoint, 37 features) | Value | Reading | +|---|---|---| +| `history.md` total | 293 790 words; largest file 215 KB | The "process log" became a narrative archive. Median entry 200 words, p90 404, max 1 651. | +| Spec commits vs code commits on feature 370 | 19 vs 8 | More than two document commits per code commit. | +| MCP `state.json` vs artifacts on disk | 30 of 34 features disagree (e.g. `status: active` while `close.md` exists) | The "deterministic state" is a second source of truth that drifted almost immediately. | +| Commits touching the shared `state.json` | 36, including 4 merge commits that had to resolve it | One JSON file for all features is a merge-conflict generator. It blocked PR 142. | +| Bug statuses | 295 `resolved`, 44 `verified`, 23 `fixed` (not a defined value), 10 empty | The rule "only the user marks verified" is not practised; the schema drifts. | +| Spec health scores | 46 of 68 are 100 %, none below 82 % | Self-graded metric; no discriminating power. | +| Procedural text loaded per phase | 6–10 k tokens (implement ≈ 9 k, review ≈ 10 k) plus 4 k words of templates | Instructions compete with the code context the work actually needs. | +| Features with `clarify.md` / review reports | 23 / 26 of 37 | Optional phases are used; the pipeline is real, not abandoned. | + +The last row matters: the team does follow the workflow. The problems below are therefore design problems, not adoption problems. + +### 2.1 The case that passed every gate and was still wrong + +Feature 370, bug BUG-005: revenue intensity never resolved in production. The bugfix round followed the full chain (bugs.md → plan section → BF-014 task → RED test → GREEN → history entry → commit). Three unit tests passed. The fix did not work against the real exchange-rate function, because the tests used a hand-built single-row fixture while the real TVF returns four rows per stored rate. The defect was found only by a read-only query against DEV data. + +Everything the workflow can check (artifacts exist, tests exist, tests pass, history recorded) was green. The one thing that mattered, contact with reality, is not a gate anywhere in the twelve skills. + +In the same round, tasks.md marked "the parse-message token" done although no code changed, and plan.md's BF-018 section describes a design the implementation deliberately abandoned. Both are self-attestation failures the workflow has no mechanism to catch. + +## 3. What works and should stay + +- **Phase separation with artifacts.** spec → plan → tasks → implement gives an auditable trail and lets two agents hand over work. The Claude/Hermes interchangeability built today exists only because the artifacts are the interface. +- **Log before fix.** Forcing bugs through `bugs.md` before code stops the "fix the symptom I was just told about" reflex. Keep it. +- **Additive-only documents.** Prevents the model from rewriting a spec to match whatever it built. Keep the rule, fix the consequences (see §4.5). +- **Constitution as context, not gate.** The v2 change to inject principles rather than block on them was right. +- **Nitpick filter in review.** The explicit "five harms" bar is one of the few places the workflow fights a known LLM failure mode (volume over substance). + +## 4. Critical findings + +Ranked by impact. Each gives the evidence, the LLM-capability reason it fails, and a direction. + +### 4.1 No external oracle anywhere in the pipeline + +**Evidence.** §2.1. Also: 295 bugs are `resolved` on the agent's word; 46 health scores of 100 % are the agent grading itself. + +**Why LLMs cannot carry this.** A model cannot reliably verify its own claims. "Tests pass" is a statement the same model produced that wrote the tests and the code; its fixtures encode its own misunderstanding. Model-written review of model-written code shares the blind spot (BF-014 survived its own review round). + +**Direction.** Every "Done When" that currently says "tests pass" should require evidence the agent did not author: a CI run id and result, a captured command output file, a query against real data for every external dependency touched, or a review by a *different* agent. Make the dual-agent setup the review policy: whichever agent implemented, the other reviews. Rename the agent-set status to `claimed`; reserve `verified` for user or CI evidence and record the source (`verified-by: ci:816`). + +### 4.2 The MCP state file is a second source of truth that lost + +**Evidence.** 30 of 34 features out of sync; one shared JSON for all features; merge conflicts in 366, 369, 370. + +**Why it fails.** Skills call `advance_phase` optionally ("if MCP is configured, skip otherwise") and from inside long sessions where the call is forgotten after compaction. A persisted state that is updated by voluntary calls from a forgetful actor will drift. Deterministic *derivation* is fine; deterministic *persistence* is not. + +**Direction.** Keep the MCP server, change its job: compute state from the artifacts on every call (`auto_detect_features` already does this), never persist, or persist per feature under `specs//.state.json` and gitignore it. The server is far more valuable as an **enforcement and allocation** service: next BUG/T/BF id, bugs.md schema lint, pre-commit history guard, branch check, timestamping. Those are the things the model does badly (§5) and a script does perfectly. + +### 4.3 Instruction volume exceeds what a model follows + +**Evidence.** 6–10 k tokens of IF/BLOCK/HALT pseudo-code per phase, preflight re-read by all eleven skills, the workflow skill (2 400 words) loaded alongside every phase skill. Observed: the `--no-verify` rule, the "ASK the user" rule, the "date -u" rule for timestamps and the "only user verifies" rule are all routinely not followed. + +**Why it fails.** Instruction-following degrades with instruction count, and after context compaction the loaded skill text is gone while the phase continues. The implement phase can run for hours; the 9 k-token procedure is read once at the start. + +**Direction.** Cut each skill to a one-screen checklist (≈800 tokens) with progressive disclosure to references only when needed. Move every mechanical rule into a script or hook (§4.2). Add a ten-line "phase card" (feature, phase, allowed writes, next gate) that the MCP server returns from `get_next_actions`, designed to be re-read after compaction. + +### 4.4 history.md is written for nobody + +**Evidence.** 294 k words; entries of 1 600 words; timestamps that are round hours and do not match the commit times they describe (`2026-10-22T20:00:00Z` on a round committed at 15:46Z). + +**Why it fails.** The template says "notes: key decisions", but a model asked to "record what was done" produces prose proportional to effort, not to information. Models also cannot know the current time; without a forced `date -u` call they invent plausible stamps. + +**Direction.** Make the entry a fixed-field record (phase, artifacts, tests: command + count, commit) capped at about 60 words, appended by a script that stamps the real time. Narrative belongs in `implementation-summary.md` once, at close. + +### 4.5 Append-only plans become unreadable and contradictory + +**Evidence.** plan.md for 370 modified four times after implementation began; its BF-018 section describes the rejected design while history.md describes the shipped one. bugs.md grows round by round; the reader must know the rounds to know the current truth. + +**Why it fails.** "Never overwrite" protects provenance but gives the model no place to state the current design, so each round appends a new partial truth. Models summarise poorly across long contradictory documents. + +**Direction.** Keep append-only history but add a regenerated "Current design" section at the top of plan.md, rewritten at each close (the one phase allowed to patch plan.md). Treat bugfix-round sections as ADRs: dated, superseding earlier sections explicitly. + +### 4.6 TDD dogma the model cannot honour, so it performs it + +**Evidence.** "If you wrote code before the test, delete it" (Iron Law). In practice the model writes test and code in one pass and reports RED → GREEN. Feature 370 has 17 `[TEST]` tasks for 54 tasks; the RED runs are asserted, not captured. + +**Why it fails.** The value of RED is proof that the test can fail. A model asserting "confirmed RED" is the same self-attestation as §4.1. The rule also produces fixtures shaped by the model's belief rather than by data (the four-row TVF). + +**Direction.** Replace the Iron Law with two enforceable requirements: (a) the RED run's output is saved as a file referenced from tasks.md; (b) any test touching an external seam (database function, HTTP contract, file format) uses a fixture captured from a real probe, with the probe command recorded. Keep test-first for pure logic, allow characterisation tests for legacy code. + +### 4.7 "Ask the user" in an autonomous pipeline + +**Evidence.** Skills contain ASK/WAIT at ~25 points. Documents cite "the owner's ruling" for decisions whose provenance is not recorded. Autonomous runs (Hermes cron, Claude background) either stall at a WAIT or the model answers its own question and calls it a ruling. + +**Why it fails.** A model has no way to distinguish a real user answer from its own continuation once the conversation is compacted or the run is unattended. + +**Direction.** Add a `decisions.md` (or a section in plan.md) where every ASK that was not actually answered by a human is recorded as an **assumption** with the alternative not taken. Real rulings quote the user's words. Reviews check that file first. + +### 4.8 Commit policy fights the project's own guardrails + +**Evidence.** Every spec commit uses `--no-verify`; 19 document commits to 8 code commits on one feature; spec changes are required to precede code even for one-line status flips. + +**Why it fails.** Bypassing hooks to make the workflow pass is a design smell, and the document-commit ratio makes `git log` useless for reading what the code did. + +**Direction.** Drop `--no-verify`; fix the hooks instead. Allow one commit per phase that includes its document updates, and keep the spec-before-code rule only for changes to requirements or design intent (the reference already distinguishes these; the skills do not). + +## 5. What current LLM agents cannot be trusted with, and what to do instead + +| Capability the workflow assumes | Reality in 2026 models | Mechanical substitute | +|---|---|---| +| Self-verification ("tests pass", "RED confirmed", "100 % health") | Unreliable; shares blind spots with the code | CI result, captured output, cross-agent review, real-data probe | +| Knowing the time | Not available; stamps are invented | `date -u` via script, or server-side stamping | +| Following 10 k tokens of procedure across a long phase | Degrades; lost at compaction | Short checklist, phase card re-injected, hooks | +| Sequential id allocation across large files (BUG-NNN, T###) | Error-prone counting | Allocate ids in the MCP server | +| Keeping a persisted state in sync by voluntary calls | Forgotten after compaction | Derive state from files; never persist | +| Distinguishing a user answer from its own continuation | Impossible after compaction or unattended | Record assumptions explicitly; quote real rulings | +| Summarising contradictory append-only documents | Poor | Regenerated "current design" section | +| Proportionate writing | Prose scales with effort, not information | Fixed-field records with word caps | +| Reviewing its own output | Blind-spot preserving | Author/reviewer split across agents (now possible) | + +## 6. Recommended order of change + +1. **External oracle in Done When** (§4.1) and the `claimed`/`verified-by` status split. Highest value, smallest change: edit the Done When lists and the bugs template. +2. **MCP server becomes a derive-and-enforce service** (§4.2): no persisted state, id allocation, schema lint, history guard, timestamps. Removes the merge conflicts and the drift. +3. **Skill diet** (§4.3): one-screen checklists, phase card, references on demand. Cuts per-phase overhead by roughly 80 %. +4. **history.md as a record, not a story** (§4.4), appended by script. +5. **Current-design section and ADR-style rounds** (§4.5). +6. **TDD rules that can be checked** (§4.6): saved RED output, real-shape fixtures. +7. **Assumptions log** (§4.7) and **commit policy** (§4.8). + +Items 1 and 2 address the two failures that actually cost time this month (a wrong fix that passed its gates, and a PR blocked by `state.json`). Items 3 and 4 are where most of the token and reading cost sits. The rest are hygiene. + +## 7. Appendix — how the numbers were produced + +```bash +# process-log volume and entry sizes +cat specs/*/history.md | wc -w +python3 - <<'EOF' +import glob,re +lens=sorted(len(e.split()) for f in glob.glob('specs/*/history.md') + for e in re.split(r'\n(?=## )', open(f).read())) +print(len(lens), lens[len(lens)//2], lens[int(len(lens)*.9)], lens[-1]) +EOF +# state.json vs artifacts +python3 -c "import json,os;d=json.load(open('specs/.spec-kit/state.json'))['features'];print(sum(((os.path.exists(f'specs/{k}/close.md') or os.path.exists(f'specs/{k}/implementation-summary.md'))!=(v.get('status')=='closed')) for k,v in d.items()),'of',len(d))" +# bug statuses and health scores +grep -h -o 'Status\*\*: [a-z-]*' specs/*/bugs.md | sort | uniq -c +grep -h -o 'health[^|]*: *[0-9]*%' specs/*/implementation-summary.md specs/*/close.md | grep -o '[0-9]*%' | sort | uniq -c +# per-phase instruction volume +wc -w ~/.hermes/skills/spec-kit-*/SKILL.md ~/.hermes/skills/spec-kit/references/{preflight,auto-commit}.md +``` diff --git a/scripts/hermes-mcp-config.py b/scripts/hermes-mcp-config.py new file mode 100755 index 0000000..6a78ecb --- /dev/null +++ b/scripts/hermes-mcp-config.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +"""Edit the spec-kit entry under `mcp_servers:` in ~/.hermes/config.yaml — safely. + +The old sed-based edit deleted exactly three lines after ` spec-kit:`; a block +written with `args:` as a YAML list is four lines, so the sed left a dangling +`- …server.py` line and the installer then appended a second `mcp_servers:` key +(a corrupt config — the backups named config.yaml.corrupt.* were this). + +This script works on indentation, not line counts: it removes the whole +` spec-kit:` block (every following line indented deeper than two spaces), +keeps other servers, reuses an existing `mcp_servers:` key, and only appends a +new one when none exists. Text-only — no YAML library, comments preserved. + +Usage: + hermes-mcp-config.py add + hermes-mcp-config.py remove +""" +import re +import sys +from pathlib import Path + +ENTRY_RE = re.compile(r"^ spec-kit:\s*$") +TOP_RE = re.compile(r"^mcp_servers:\s*$") + + +def _split(lines): + """Return (before, servers_body, after) around the top-level mcp_servers: key, or None.""" + for i, line in enumerate(lines): + if TOP_RE.match(line): + j = i + 1 + while j < len(lines) and (lines[j].startswith(" ") or lines[j].strip() == ""): + j += 1 + # trailing blank lines belong to "after", not to the section + k = j + while k > i + 1 and lines[k - 1].strip() == "": + k -= 1 + return lines[:i], lines[i + 1:k], lines[k:] + return None + + +def _without_spec_kit(body): + out, skipping = [], False + for line in body: + if ENTRY_RE.match(line): + skipping = True + continue + if skipping and (line.startswith(" ") or line.strip() == ""): + continue + skipping = False + out.append(line) + return out + + +def main(argv): + if len(argv) < 3 or argv[1] not in ("add", "remove"): + print(__doc__); return 2 + cfg = Path(argv[2]) + text = cfg.read_text() if cfg.exists() else "" + lines = text.split("\n") + parts = _split(lines) + if argv[1] == "remove": + if parts is None: + return 0 + before, body, after = parts + body = _without_spec_kit(body) + new = before + (["mcp_servers:"] + body if any(l.strip() for l in body) else []) + after + else: + if len(argv) != 5: + print(__doc__); return 2 + python, server = argv[3], argv[4] + entry = [" spec-kit:", f' command: "{python}"', f' args: ["{server}"]'] + if parts is None: + base = lines if text.strip() else [] + if base and base[-1].strip(): + base.append("") + new = base + ["mcp_servers:"] + entry + [""] + else: + before, body, after = parts + body = _without_spec_kit(body) + while body and body[-1].strip() == "": + body.pop() + new = before + ["mcp_servers:"] + body + entry + after + out = "\n".join(new) + if not out.endswith("\n"): + out += "\n" + cfg.parent.mkdir(parents=True, exist_ok=True) + cfg.write_text(out) + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/scripts/install-claude.sh b/scripts/install-claude.sh new file mode 100755 index 0000000..71b3b9e --- /dev/null +++ b/scripts/install-claude.sh @@ -0,0 +1,240 @@ +#!/usr/bin/env bash +# spec-kit installation script for Claude Code +# +# Generates the Claude Code edition of every spec-kit skill from the SAME +# src/skills/*.md sources the Hermes edition is installed from, so both agents +# run the identical workflow and can hand phases to each other on one specs/ +# tree (e.g. Claude: specify → plan → tasks, Hermes: implement, Claude: close). +# +# What it does: +# 1. src/skills/.md ──transform──▶ ~/.claude/skills//SKILL.md +# (frontmatter reduced to the fields Claude Code reads; Hermes tool names +# translated to Claude Code tools; shared-file paths resolved). +# 2. Shares references/, templates/ and mcp-server/ with the installed Hermes +# tree by SYMLINK (single source of truth — whatever Hermes reads, Claude +# reads). Falls back to copying from src/ when Hermes is not installed. +# 3. Registers the spec-kit MCP state server for Claude Code at user scope +# (`claude mcp add -s user spec-kit …`) so specs/.spec-kit/state.json is +# derived identically for both agents (no state file). +# +# Usage: +# ./scripts/install-claude.sh # install / refresh +# ./scripts/install-claude.sh --no-mcp # skills only, skip MCP registration +# ./scripts/install-claude.sh --uninstall + +set -euo pipefail + +PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +CLAUDE_SKILLS_DIR="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}" +HERMES_SKILLS_DIR="${HERMES_SKILLS_DIR:-$HOME/.hermes/skills}" +HERMES_SPEC_KIT="$HERMES_SKILLS_DIR/spec-kit" + +DO_MCP=1 +DO_UNINSTALL=0 +for arg in "$@"; do + case "$arg" in + --no-mcp) DO_MCP=0 ;; + --uninstall) DO_UNINSTALL=1 ;; + -h|--help) sed -n '2,24p' "$0"; exit 0 ;; + *) echo "Unknown option: $arg" >&2; exit 2 ;; + esac +done + +# ───────────────────────────── uninstall ───────────────────────────── +if [ "$DO_UNINSTALL" -eq 1 ]; then + echo "Uninstalling spec-kit (Claude Code edition) from $CLAUDE_SKILLS_DIR..." + removed=0 + for dir in "$CLAUDE_SKILLS_DIR"/spec-kit-*/ "$CLAUDE_SKILLS_DIR"/spec-kit/; do + if [ -d "$dir" ] || [ -L "${dir%/}" ]; then + echo " Removing: $(basename "$dir")" + rm -rf "${dir%/}" + removed=$((removed + 1)) + fi + done + echo " -> Removed $removed skill director(y/ies)" + if command -v claude >/dev/null 2>&1 && claude mcp get spec-kit >/dev/null 2>&1; then + claude mcp remove -s user spec-kit >/dev/null 2>&1 && echo " Removed MCP server 'spec-kit' (user scope)" \ + || echo " NOTE: could not remove MCP server 'spec-kit' automatically — run: claude mcp remove -s user spec-kit" + fi + echo "Done. Restart Claude Code for the change to take effect." + exit 0 +fi + +# ───────────────────────────── install ─────────────────────────────── +echo "Installing spec-kit (Claude Code edition) from $PROJECT_DIR to $CLAUDE_SKILLS_DIR..." +mkdir -p "$CLAUDE_SKILLS_DIR" + +# The transform: Hermes skill source → Claude Code SKILL.md. +# Kept in one place so a diff of the two editions is ONLY the translation. +transform() { + local src="$1" dst="$2" skill_name="$3" + python3 - "$src" "$dst" "$skill_name" <<'PY' +import re, sys +src, dst, skill = sys.argv[1], sys.argv[2], sys.argv[3] +text = open(src, encoding="utf-8").read() + +# ── 1. frontmatter: keep only what Claude Code reads ────────────────────── +m = re.match(r"^---\n(.*?)\n---\n", text, re.S) +if not m: + sys.exit(f"{src}: no YAML frontmatter") +fm, body = m.group(1), text[m.end():] + +def field(name): + """Return the raw YAML value of a top-level scalar field (incl. '>' folds).""" + mm = re.search(rf"^{name}:(.*?)(?=^\S|\Z)", fm, re.S | re.M) + return mm.group(1).rstrip("\n") if mm else None + +description = field("description") +if description is None: + sys.exit(f"{src}: frontmatter has no description") +description = description.replace("Hermes Agent", "Claude Code") + +arg_hint = { + "spec-kit": None, + "spec-kit-constitution": "[project description]", + "spec-kit-workflow": "[command] [feature]", + "spec-kit-epic": "[epic]", + "spec-kit-design": "[module]", +}.get(skill, "[feature]") + +out = ["---", f"name: {skill}", f"description:{description}"] +if arg_hint: + out.append(f'argument-hint: "{arg_hint}"') +out.append("---") +frontmatter = "\n".join(out) + "\n" + +# ── 2. body: Hermes → Claude Code translation ──────────────────────────── +subs = [ + # product names / homes + (r"Hermes Agent", "Claude Code"), + (r"~/\.hermes/skills/", "~/.claude/skills/"), + # shared-file paths (the skills say `spec-kit/references/…` — resolve them) + (r"(?` — call them by this full name.)"), + # tool names + (r"skill_view\(name='([^']+)'\)", r'the `Skill` tool with skill "\1"'), + (r"`skill_view`", "`Skill`"), + (r"`read_file`, `search_files`", "`Read`, `Grep`/`Glob`"), + (r"`read_file`", "`Read`"), + (r"`search_files`", "`Grep`/`Glob`"), + (r"`write_file`", "`Write`"), + (r"\bwrite_file\b", "Write"), + (r"`patch`", "`Edit`"), + (r"`terminal`", "`Bash`"), + (r"\bterminal\(", "Bash("), + (r"\bterminal \(build/compile/test\)", "Bash (build/compile/test)"), +] +for pat, rep in subs: + body = re.sub(pat, rep, body) + +# Umbrella-only: the Hermes MCP config snippet → the Claude Code command. +if skill == "spec-kit": + body = re.sub( + r"Enable by adding to `~/\.hermes/config\.yaml`:\n\n```yaml\n.*?\n```\n", + "Enable for Claude Code (user scope — once per machine; `scripts/install-claude.sh` does this for you):\n\n" + "```bash\nclaude mcp add -s user spec-kit -- ~/.claude/skills/spec-kit/mcp-server/server.py\n```\n", + body, flags=re.S) + body = body.replace( + "regardless of Hermes profile or working directory", + "regardless of agent (Hermes or Claude Code) or working directory") + +# ── 3. the Claude Code notes block, right under the H1 ─────────────────── +note = f""" +> Claude Code edition of `src/skills/{skill}.md` (hermes-spec-kit) — generated, do not edit. +> `$ARGUMENTS` = `[feature]` · "load `spec-kit-x`" = the `Skill` tool · ASK / WAIT = `AskUserQuestion` +> · Hermes tool names in references map to `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`; `mcp_spec_kit_x` → `mcp__spec-kit__x` +> · the skills commit their own artifacts (`commits.md`) — standing authorisation; keep the commit attribution rules. +""" +h1 = re.search(r"^# .*\n", body, re.M) +if h1: + body = body[:h1.end()] + note + body[h1.end():] +else: + body = note + body + +open(dst, "w", encoding="utf-8").write(frontmatter + body) +PY +} + +installed=0 +# Phase skills: src/skills/.md → /SKILL.md +for skill in "$PROJECT_DIR"/src/skills/*.md; do + [ -f "$skill" ] || continue + name=$(basename "$skill" .md) + mkdir -p "$CLAUDE_SKILLS_DIR/$name" + transform "$skill" "$CLAUDE_SKILLS_DIR/$name/SKILL.md" "$name" + echo " Installing skill: $name" + installed=$((installed + 1)) +done + +# Umbrella skill +UMBRELLA_SRC="$PROJECT_DIR/src/skills/spec-kit/SKILL.md" +if [ -f "$UMBRELLA_SRC" ]; then + mkdir -p "$CLAUDE_SKILLS_DIR/spec-kit" + transform "$UMBRELLA_SRC" "$CLAUDE_SKILLS_DIR/spec-kit/SKILL.md" "spec-kit" + echo " Installing umbrella skill: spec-kit" + installed=$((installed + 1)) +fi + +# Shared files: symlink to the installed Hermes tree (single source of truth), +# else copy from src/. Per-skill references/ directories that exist only in the +# Hermes tree (project-specific notes added over time) are linked too. +link_or_copy() { + local target="$1" link="$2" fallback_src="$3" label="$4" + if [ -e "$link" ] && [ ! -L "$link" ]; then + rm -rf "$link" # replace an earlier copied directory with the link + fi + if [ -d "$target" ]; then + ln -sfn "$target" "$link" + echo " Linking $label -> $target" + elif [ -n "$fallback_src" ] && [ -d "$fallback_src" ]; then + rm -f "$link"; mkdir -p "$link"; cp -r "$fallback_src"/. "$link"/ + echo " Copying $label from $fallback_src (Hermes tree not found)" + fi +} +link_or_copy "$HERMES_SPEC_KIT/references" "$CLAUDE_SKILLS_DIR/spec-kit/references" "$PROJECT_DIR/src/references" "spec-kit/references" +link_or_copy "$HERMES_SPEC_KIT/templates" "$CLAUDE_SKILLS_DIR/spec-kit/templates" "$PROJECT_DIR/src/templates" "spec-kit/templates" +link_or_copy "$HERMES_SPEC_KIT/mcp-server" "$CLAUDE_SKILLS_DIR/spec-kit/mcp-server" "$PROJECT_DIR/spec-kit-mcp-server" "spec-kit/mcp-server" +link_or_copy "$HERMES_SPEC_KIT/scripts" "$CLAUDE_SKILLS_DIR/spec-kit/scripts" "$PROJECT_DIR/src/scripts" "spec-kit/scripts" +for hdir in "$HERMES_SKILLS_DIR"/spec-kit-*/references; do + [ -d "$hdir" ] || continue + sname=$(basename "$(dirname "$hdir")") + [ -d "$CLAUDE_SKILLS_DIR/$sname" ] || continue + link_or_copy "$hdir" "$CLAUDE_SKILLS_DIR/$sname/references" "" "$sname/references" +done + +# ───────────────────────────── MCP server ──────────────────────────── +if [ "$DO_MCP" -eq 1 ]; then + echo "" + if ! command -v claude >/dev/null 2>&1; then + echo " NOTE: 'claude' CLI not found — skipping MCP registration." + elif claude mcp get spec-kit >/dev/null 2>&1; then + echo " MCP server 'spec-kit' already registered for Claude Code — leaving it as is." + else + MCP_PYTHON="" + for cand in "$HOME/.hermes-venv/bin/python3" "$PROJECT_DIR/.venv/bin/python3" python3; do + if command -v "$cand" >/dev/null 2>&1 && "$cand" -c "import mcp" >/dev/null 2>&1; then + MCP_PYTHON="$(command -v "$cand")"; break + fi + done + SERVER="$CLAUDE_SKILLS_DIR/spec-kit/mcp-server/server.py" + if [ -z "$MCP_PYTHON" ]; then + echo " WARNING: no Python with the 'mcp' SDK found — MCP server not registered." + echo " Install it (see spec-kit-mcp-server/requirements.txt), then run:" + echo " claude mcp add -s user spec-kit -- $SERVER" + elif [ ! -f "$SERVER" ]; then + echo " WARNING: $SERVER not found — MCP server not registered." + else + claude mcp add -s user spec-kit -- "$MCP_PYTHON" "$SERVER" >/dev/null + echo " Registered MCP server 'spec-kit' (user scope): $MCP_PYTHON $SERVER" + echo " -> Claude Code sees its tools as mcp__spec-kit__; the server keeps no state" + fi + fi +fi + +echo "" +echo "Done. Installed $installed skill(s) to $CLAUDE_SKILLS_DIR" +echo "Restart Claude Code (or start a new session) to load them. Invoke as /spec-kit-specify, /spec-kit-plan, …" diff --git a/scripts/install.sh b/scripts/install.sh index 2ddeaa3..bc5cb04 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -75,8 +75,8 @@ TEMPLATES_DIR="$SKILLS_DIR/spec-kit/templates" mkdir -p "$TEMPLATES_DIR" # Remove obsolete template files -rm -f "$TEMPLATES_DIR/checklist-template.md" -rm -f "$TEMPLATES_DIR/comparison-template.md" +rm -f "$TEMPLATES_DIR/checklist-template.md" "$TEMPLATES_DIR/comparison-template.md" "$TEMPLATES_DIR/soul-template.md" +rm -f "$TEMPLATES_DIR/implementation-summary-template.md" for tmpl in "$PROJECT_DIR"/src/templates/*-template.md; do if [ -f "$tmpl" ]; then @@ -97,6 +97,41 @@ for ref in "$PROJECT_DIR"/src/references/*.md; do cp "$ref" "$REFERENCES_DIR/$ref_name" fi done +# Top-level references that spec-kit no longer ships (superseded, or notes an agent added by +# hand) are moved aside, not deleted: nothing in the skills loads them, so they only cost +# attention. They stay readable under references/local/. +mkdir -p "$REFERENCES_DIR/local" +for installed in "$REFERENCES_DIR"/*.md; do + [ -f "$installed" ] || continue + if [ ! -f "$PROJECT_DIR/src/references/$(basename "$installed")" ]; then + echo " Moving unshipped reference aside: $(basename "$installed") -> references/local/" + mv -f "$installed" "$REFERENCES_DIR/local/" + fi +done +rmdir "$REFERENCES_DIR/local" 2>/dev/null || true +# Shell helpers (spec-kit-log.sh — the no-MCP history appender; spec-kit-history.sh — the git timeline when history is off) +if [ -d "$PROJECT_DIR/src/scripts" ]; then + mkdir -p "$SKILLS_DIR/spec-kit/scripts" + for sh in "$PROJECT_DIR"/src/scripts/*.sh; do + [ -f "$sh" ] || continue + echo " Installing script: $(basename "$sh")" + cp "$sh" "$SKILLS_DIR/spec-kit/scripts/$(basename "$sh")" + chmod +x "$SKILLS_DIR/spec-kit/scripts/$(basename "$sh")" + done +fi +# Full per-skill procedures (loaded on demand by the one-screen SKILL.md files) +if [ -d "$PROJECT_DIR/src/references/skills" ]; then + mkdir -p "$REFERENCES_DIR/skills" + for ref in "$PROJECT_DIR"/src/references/skills/*.md; do + [ -f "$ref" ] || continue + echo " Installing full procedure: skills/$(basename "$ref")" + cp "$ref" "$REFERENCES_DIR/skills/$(basename "$ref")" + done + for installed in "$REFERENCES_DIR"/skills/*.md; do + [ -f "$installed" ] || continue + [ -f "$PROJECT_DIR/src/references/skills/$(basename "$installed")" ] || { echo " Removing superseded full procedure: skills/$(basename "$installed")"; rm -f "$installed"; } + done +fi # --- SOUL.md prompt --- SOUL_TEMPLATE="$TEMPLATES_DIR/soul-template.md" @@ -134,6 +169,67 @@ if [ -f "$SOUL_TEMPLATE" ]; then esac fi +echo "" + +# --- MCP Server --- +MCP_SERVER_DIR="$PROJECT_DIR/spec-kit-mcp-server" +MCP_SERVER_DST="$SKILLS_DIR/spec-kit/mcp-server" +if [ -f "$MCP_SERVER_DIR/server.py" ]; then + mkdir -p "$MCP_SERVER_DST" + cp "$MCP_SERVER_DIR/server.py" "$MCP_SERVER_DST/server.py" + cp "$MCP_SERVER_DIR/README.md" "$MCP_SERVER_DST/README.md" 2>/dev/null || true + chmod +x "$MCP_SERVER_DST/server.py" + echo " Installing MCP server: spec-kit-mcp-server/server.py" + + # Determine Python for MCP — prefer venv with mcp SDK, fallback to system + MCP_PYTHON="" + if python3 -c "import mcp" 2>/dev/null; then + MCP_PYTHON="python3" + echo " -> mcp SDK found (system python)" + else + # Try creating a venv with mcp installed + MCP_VENV="$HOME/.hermes-venv" + if [ ! -f "$MCP_VENV/bin/python3" ]; then + echo " -> Creating venv at $MCP_VENV..." + python3 -m venv "$MCP_VENV" + echo " -> Installing mcp SDK (from requirements.txt, mcp pinned <2)..." + "$MCP_VENV/bin/pip" install -r "$MCP_SERVER_DIR/requirements.txt" + fi + if "$MCP_VENV/bin/python3" -c "import mcp" 2>/dev/null; then + MCP_PYTHON="$MCP_VENV/bin/python3" + echo " -> mcp SDK installed in venv" + else + echo " -> WARNING: Failed to install mcp SDK in venv." + echo " Try: $MCP_VENV/bin/pip install mcp" + fi + fi + + # Configure MCP server in config.yaml + # + # NOTE: We write config.yaml directly instead of using 'hermes mcp add'. + # 'hermes mcp add' tries to hot-reload into a running Hermes process, which + # times out when no session is active (typical during installation). + # + CONFIG_FILE="$HOME/.hermes/config.yaml" + if [ -n "$MCP_PYTHON" ]; then + echo " -> Configuring MCP server in $CONFIG_FILE..." + mkdir -p "$(dirname "$CONFIG_FILE")" + [ -f "$CONFIG_FILE" ] || touch "$CONFIG_FILE" + + # Replace the spec-kit entry by indentation (never by line count — a block + # written with a YAML list for args is 4 lines, not 3), keep other servers, + # reuse an existing mcp_servers: key. See scripts/hermes-mcp-config.py. + cp "$CONFIG_FILE" "$CONFIG_FILE.spec-kit-backup" + python3 "$PROJECT_DIR/scripts/hermes-mcp-config.py" add "$CONFIG_FILE" "$MCP_PYTHON" "$MCP_SERVER_DST/server.py" + echo " -> spec-kit MCP server entry written (backup: $CONFIG_FILE.spec-kit-backup)" + echo " -> Activate in Hermes with: /reload-mcp" + else + echo " -> WARNING: mcp Python package not available." + echo " Hermes needs it for MCP support. Install manually:" + echo " python3 -m venv ~/.hermes-venv && ~/.hermes-venv/bin/pip install -r $MCP_SERVER_DIR/requirements.txt" + fi +fi + echo "" echo "Done. Installed to $SKILLS_DIR" echo "" diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..000261e --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# spec-kit uninstall script for Hermes Agent +# Removes all skills, templates, references, MCP server, and config entries. + +set -e + +SKILLS_DIR="$HOME/.hermes/skills" +CONFIG_FILE="$HOME/.hermes/config.yaml" + +echo "Uninstalling spec-kit from $SKILLS_DIR..." +echo "" + +# --- Remove skill directories --- +REMOVED_SKILLS=0 +for dir in "$SKILLS_DIR"/spec-kit-*/; do + if [ -d "$dir" ]; then + name=$(basename "$dir") + echo " Removing skill: $name" + rm -rf "$dir" + REMOVED_SKILLS=$((REMOVED_SKILLS + 1)) + fi +done + +# Remove umbrella skill directory +if [ -d "$SKILLS_DIR/spec-kit" ]; then + echo " Removing umbrella: spec-kit" + rm -rf "$SKILLS_DIR/spec-kit" + REMOVED_SKILLS=$((REMOVED_SKILLS + 1)) +fi + +echo " -> Removed $REMOVED_SKILLS skill(s)" + +# --- Remove stale flat spec-kit-*.md files (old format) --- +STALE_COUNT=0 +for stale in "$SKILLS_DIR"/spec-kit-*.md; do + if [ -f "$stale" ]; then + echo " Removing stale flat file: $(basename "$stale")" + rm -f "$stale" + STALE_COUNT=$((STALE_COUNT + 1)) + fi +done +if [ "$STALE_COUNT" -gt 0 ]; then + echo " -> Removed $STALE_COUNT stale flat file(s)" +fi + +# --- Remove old speckit-* directories (pre-rename format) --- +OLD_COUNT=0 +for old_dir in "$SKILLS_DIR"/speckit-*/; do + if [ -d "$old_dir" ]; then + echo " Removing old format: $(basename "$old_dir")" + rm -rf "$old_dir" + OLD_COUNT=$((OLD_COUNT + 1)) + fi +done +if [ "$OLD_COUNT" -gt 0 ]; then + echo " -> Removed $OLD_COUNT old format skill(s)" +fi + +# --- Remove MCP server --- +if [ -d "$SKILLS_DIR/spec-kit/mcp-server" ]; then + echo " Removing MCP server: spec-kit/mcp-server" + rm -rf "$SKILLS_DIR/spec-kit/mcp-server" +fi + +# --- Remove spec-kit MCP config from config.yaml --- +if [ -f "$CONFIG_FILE" ]; then + if grep -q "spec-kit:" "$CONFIG_FILE" 2>/dev/null; then + cp "$CONFIG_FILE" "$CONFIG_FILE.spec-kit-backup" + echo " Backed up config to: $CONFIG_FILE.spec-kit-backup" + + # Remove the spec-kit block by indentation; drops mcp_servers: only when empty + python3 "$(cd "$(dirname "$0")" && pwd)/hermes-mcp-config.py" remove "$CONFIG_FILE" + + echo " Removed spec-kit entry from ~/.hermes/config.yaml" + fi +fi + +echo "" +echo "Done. spec-kit has been fully uninstalled." +echo "Restart Hermes Agent for changes to take effect." diff --git a/spec-kit-mcp-server/README.md b/spec-kit-mcp-server/README.md new file mode 100644 index 0000000..57e6b28 --- /dev/null +++ b/spec-kit-mcp-server/README.md @@ -0,0 +1,99 @@ +# spec-kit MCP Server (v3 — derive and enforce) + +A stateless MCP server for the spec-kit workflow, built on the official `mcp` Python SDK (FastMCP, stdio). +It keeps **no state of its own**: every call derives a feature's phase from the files under +`specs//` at that moment and validates against them. + +## Why no state file + +v2 persisted `specs/.spec-kit/state.json`. In a real deployment 30 of 34 features had a stored +state that disagreed with the artifacts on disk, and the single shared JSON conflicted on every +merge. A state updated by voluntary calls from an agent that forgets after context compaction will +drift. The files are the only truth; the server reads them. + +## What it is for + +The things an LLM agent does badly and a script does perfectly: + +| Need | Tool | +|------|------| +| Which phase am I in, what may I write, what is the next gate (also after compaction) | `get_next_actions` → ten-line **phase card** | +| Is this transition valid given the files on disk | `advance_phase`, `close_feature`, `update_artifact` | +| Next BUG-NNN / T### / BF-### / project ADR number | `next_id` | +| Is the branch mechanically mergeable (conflicts, secrets, forbidden files, focused tests, TODOs, unplanned files) | `diff_scan` | +| Has the final review said READY on the current code | `get_feature_state.final_review`, `close_feature` | +| Which acceptance criteria pass, fail, are missing or deferred — from JUnit/TRX results | `acceptance_status` | +| Have the acceptance tests been weakened since their RED run | `acceptance_freeze`, `acceptance_status.frozen_changed`, `lint_artifacts` | +| Are bugs.md / tasks.md / history.md / ACs / rounds well-formed (statuses, Verified-by, ids, probes, RED files) | `lint_artifacts` | +| Is there a fresh history entry for this phase since the last commit | `history_guard` | +| Append the history record with the real time and a word cap | `append_history` | +| What time is it (never type a timestamp from memory) | `history_guard` | A history.md entry mentioning `phase` exists and is newer than the last commit touching the feature | ok / reason | +| `append_history` | Append one fixed-field entry (timestamp \| phase \| skill \| agent; Artifacts, Tests, Evidence, Commit, Note ≤ 25 words) with the real UTC time | entry | +| `timestamp` | + +## Quick Start + +```bash +./scripts/install.sh # Hermes: copies the server to ~/.hermes/skills/spec-kit/mcp-server/ and configures config.yaml +./scripts/install-claude.sh # Claude Code: claude mcp add -s user spec-kit … (same server file) +``` + +Hermes: `/reload-mcp`, then `/toolsets` should list `mcp_spec_kit_*`. +Claude Code: restart; tools appear as `mcp__spec-kit__*`. + +## MCP Tools (16) + +| Tool | Purpose | Writes | +|------|---------|--------| +| `init_feature` | Create `specs//` with a history.md header; error if it exists | dir + history.md header | +| `get_feature_state` | Derived phase, status, size tier (S/M/L from spec.md), artifacts, task/bug counts, final review (verdict, reviewed commit, stale), phase card | — | +| `get_next_actions` | Available actions + phase card | — | +| `advance_phase` | Validate leaving `from_phase`: derived phase is `from_phase` or already `from_phase+1`, named artifacts and next prerequisites exist; 5→6 also needs a fresh READY final review | — | +| `project_status` | Constitution / git-conventions / merge-checklist present, ADR directory, feature count, legacy state file present? | — | +| `project_set_constitution` | Confirm `specs/constitution.md` matches the claimed status | — | +| `list_features` | Every feature's derived state | — | +| `reopen_feature` | Feature is closed on disk → branch hint; reopening is materialised by an open bug in bugs.md | — | +| `close_feature` | Close doc exists with `## Architecture Decisions`; latest `acceptance.md` round PASS and fresh (when spec.md has ACs); latest `review-final.md` round is READY / READY-WITH-FOLLOWUPS and no code commit follows its Reviewed-commit; no open/in-progress bug; verified bugs carry Verified-by; returns claimed-unverified list | — | +| `update_artifact` | Named artifact exists (present/verified) or does not (absent) | — | +| `auto_detect_features` | Derived state of all features; flags legacy `state.json` | — | +| `next_id` | Scan files, return next id for kind BUG / T / BF / AC; ADR → next 4-digit number in the project's ADR directory (`adr_dir` in git-conventions, else docs/adr, docs/decisions, …) | — | +| `acceptance_freeze` | SHA-256 of every file named on a `[TEST] [AC-###]` task → `evidence/acceptance-freeze.json`; additive; a changed frozen file is an error unless `refreeze=true` with the user's reason | evidence/acceptance-freeze.json | +| `acceptance_status` | AC matrix from spec.md (`**AC-###** … Verify: `), tasks.md tags and JUnit/TRX result files (test names carry the id): pass / fail / missing / deferred (e2e) / manual, regressions (failing untagged tests), frozen tests changed → Result PASS / FAIL / STOPPED | — | +| `diff_scan` | Branch diff vs base (`branch_source`): merge conflicts (`git merge-tree`), conflict markers, private keys, secret assignments, AWS keys, focused tests, debugger, TODO/FIXME, forbidden files (.pfx/.pem/.key/.bacpac/.env), files > 1 MB, changed files not named in spec/plan/tasks; specs/ excluded | — | +| `lint_artifacts` | Schema lint: status vocabulary (open/in-progress/claimed/verified/superseded; legacy resolved/fixed = warning), Verified-by on verified, Evidence on claimed, ascending ids, summary rows and totals, history header, review-final.md rounds (Verdict + Reviewed-commit, numbering), spec.md Size line, close doc Architecture Decisions section | — | +| `timestamp` | UTC now, ISO 8601 | — | + +> Hermes prefixes tools with `mcp_spec_kit_`; Claude Code with `mcp__spec-kit__`. + +## Phase derivation + +| Files under `specs//` | Derived phase / status | +|---|---| +| no `spec.md` | 1 specify / `new` | +| `spec.md`, no `plan.md` | 2 plan | +| `plan.md`, no `tasks.md` | 3 tasks | +| `tasks.md` with pending tasks, no `bugs.md`, no close doc | 4 implement | +| all tasks `[X]` or `bugs.md` present, no close doc | 5 test | +| `close.md` (+ `change-record.md`), no open bug | 6 / `closed` | +| close doc + `bugs.md` with open or in-progress bug | 5 / `reopened` | + +## Bug tracking + +File-based, deliberately. `bugs.md` is the single source of truth; only `spec-kit-test` writes it. +The server never edits bugs.md — it reads it for derivation, `next_id`, `lint_artifacts` and +`close_feature`. Status vocabulary and the oracle rule: `src/references/evidence.md`. + +## Legacy state.json + +Ignored. `project_status` and `auto_detect_features` report `legacy_state_file: true` when one +exists — delete it and add `specs/.spec-kit/` to `.gitignore` (the gitignore template does). + +## Tests + +```bash +cd spec-kit-mcp-server +python3 test_workflow.py # derivation, validation, close/reopen, next_id, lint, timestamp, history_guard, acceptance — in temp projects with real files +python3 test_skills.py # skill/template/reference consistency, tool-name drift +``` + +Requires a Python with `mcp<2` and `pyyaml` (the repo's `.venv`). diff --git a/spec-kit-mcp-server/requirements.txt b/spec-kit-mcp-server/requirements.txt new file mode 100644 index 0000000..6dcfa21 --- /dev/null +++ b/spec-kit-mcp-server/requirements.txt @@ -0,0 +1,4 @@ +# Pin <2: mcp 2.x renamed FastMCP to MCPServer and broke server.py's import. +# See https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver +mcp<2 +pyyaml diff --git a/spec-kit-mcp-server/server.py b/spec-kit-mcp-server/server.py new file mode 100644 index 0000000..b27164c --- /dev/null +++ b/spec-kit-mcp-server/server.py @@ -0,0 +1,1334 @@ +#!/usr/bin/env python3 +"""spec-kit MCP server — derive-and-enforce workflow service. + +DESIGN (v3): the server keeps NO state of its own. Every call derives the +feature's phase and artifact status from the files under specs// at +that moment. A persisted state file (v2's specs/.spec-kit/state.json) proved +to be a second source of truth that drifted from the artifacts (30 of 34 +features out of sync in one deployment) and collided on every merge. Files on +disk are the single source of truth; this server reads them and enforces. + +What the server is for — the things an LLM agent does badly and a script does +perfectly: + * phase derivation and prerequisite validation (advance_phase, get_feature_state) + * sequential id allocation (next_id: BUG / T / BF) + * artifact schema lint (lint_artifacts: bugs.md, tasks.md, history.md, spec.md ACs, acceptance.md, review-final.md) + * the history-before-commit guard (history_guard) + * real timestamps (timestamp) + * a ten-line phase card to re-read after context compaction (get_next_actions) + * the merge gate: the final review's verdict and freshness (close_feature) and a + mechanical scan of the branch diff (diff_scan) + * the size tier (S/M/L) read from spec.md, and ADR number allocation (next_id ADR) + * acceptance criteria: the AC → test → result matrix from spec.md, tasks.md and JUnit/TRX + results (acceptance_status), and the freeze of acceptance tests (acceptance_freeze) + +Bug tracking stays file-based — bugs.md is the single source of truth and this +server never edits it; it only reads and lints. + +Dependency: pip install "mcp<2" (auto-installed by install.sh venv) +""" + +import datetime +import hashlib +import json +import re +import subprocess +import xml.etree.ElementTree as ET +from pathlib import Path + +from mcp.server.fastmcp import FastMCP + +SPECS_DIR = Path("specs") +LEGACY_STATE_FILE = SPECS_DIR / ".spec-kit" / "state.json" + +PHASES = { + 0: {"name": "constitution", "artifacts": ["constitution.md"]}, + 1: {"name": "specify", "artifacts": ["spec.md"]}, + 2: {"name": "plan", "artifacts": ["plan.md"]}, + 3: {"name": "tasks", "artifacts": ["tasks.md"]}, + 4: {"name": "implement", "artifacts": []}, + 5: {"name": "test", "artifacts": ["bugs.md"]}, + 6: {"name": "close", "artifacts": ["close.md"]}, +} + +# Artifact required ON DISK before a feature may stand in the given phase. +PREREQUISITES = { + 2: ["spec.md"], + 3: ["spec.md", "plan.md"], + 4: ["spec.md", "plan.md", "tasks.md"], + 5: ["tasks.md"], + 6: ["tasks.md"], +} + +CLOSE_DOCS = ("close.md", "implementation-summary.md") +FINAL_REVIEW = "review-final.md" +ACCEPTANCE = "acceptance.md" +FREEZE_FILE = "evidence/acceptance-freeze.json" +AC_LEVELS = ("unit", "integration", "component", "e2e", "command", "probe", "manual") +AC_TEST_LEVELS = ("unit", "integration", "component", "e2e") # proven by a test result file +AC_REASON_LEVELS = ("e2e", "manual") # need a written reason in spec.md +TRACKED_ARTIFACTS = [ + "spec.md", "clarify.md", "plan.md", "research.md", "data-model.md", + "quickstart.md", "tasks.md", "bugs.md", "decisions.md", "history.md", + ACCEPTANCE, FINAL_REVIEW, "close.md", "implementation-summary.md", "change-record.md", +] +SIZES = ("S", "M", "L") +VERDICTS = ("READY", "READY-WITH-FOLLOWUPS", "AWAITING-OWNER", "NOT READY") +PASSING_VERDICTS = ("READY", "READY-WITH-FOLLOWUPS") +ADR_DIR_CANDIDATES = ("docs/adr", "docs/decisions", "doc/adr", "adr", "docs/architecture/decisions") + +BUG_STATUSES = {"open", "in-progress", "claimed", "verified", "superseded"} +LEGACY_BUG_STATUSES = {"resolved": "claimed", "fixed": "claimed"} +VERIFIED_BY_RE = re.compile(r"^(user|ci:\S+|review:\S+)$") + +_BUG_HEADER_RE = re.compile(r"^### (BUG-(\d+)):", re.M) +# "- [X] T001 …" (template) and "- T001 [X] …" (id first) are both task lines. +_TASK_RE = re.compile(r"^- (?:\[(?P
[ xX])\] )?(?P(?:T|BF-?)(?P\d+))\b(?: \[(?P[ xX])\])?", re.M)
+_HISTORY_ENTRY_RE = re.compile(r"^## \[?([0-9T:\-+.Z]+)\]? *\| *(.*)$", re.M)
+_SIZE_RE = re.compile(r"^\*\*Size\*\*:\s*\[?([SML])\b", re.M)
+_HISTORY_RE = re.compile(r"^\*\*History\*\*:\s*\[?(on|off)\b", re.M | re.I)
+_EPIC_RE = re.compile(r"^\*\*Epic\*\*:\s*\[?([A-Za-z0-9][\w.-]*)", re.M)
+_MODULES_RE = re.compile(r"^\*\*Modules\*\*:\s*(.+)$", re.M)
+_ROUND_RE = re.compile(r"^## Round (\d+)\b[^\n]*$", re.M)
+_VERDICT_RE = re.compile(r"\*\*Verdict\*\*:\s*(READY-WITH-FOLLOWUPS|AWAITING-OWNER|NOT READY|READY)\b")
+_REVIEWED_COMMIT_RE = re.compile(r"\*\*Reviewed-commit\*\*:\s*([0-9a-f]{7,40})\b")
+# spec.md: "- **AC-003** (FR-002) Given … When … Then … — Verify: integration"
+_AC_LINE_RE = re.compile(r"^.*\*\*AC-(\d{3})\*\*.*$", re.M)
+_AC_VERIFY_RE = re.compile(r"Verify:\s*`?([a-z0-9]+)`?(?:\s*\(([^)]*)\))?", re.I)
+# a test name carries the AC id: "AC-003 …", "AC003_…", "test_ac003_…"
+_AC_IN_NAME_RE = re.compile(r"(?//features.md (legacy: /.md); None when neither exists."""
+    for cand in (Path(epics_dir) / epic / "features.md", Path(epics_dir) / f"{epic}.md"):
+        if cand.exists():
+            return cand
+    return None
+
+
+def _modules_of(fd):
+    """Module names from plan.md `**Modules**: a, b`; [] when absent or a template placeholder."""
+    f = fd / "plan.md"
+    if not f.exists():
+        return []
+    m = _MODULES_RE.search(f.read_text(errors="replace"))
+    if not m or m.group(1).lstrip().startswith("["):
+        return []
+    return [x.strip().strip("`") for x in m.group(1).split(",") if x.strip()]
+
+
+def _parse_size(fd):
+    """S | M | L from the spec.md header line `**Size**: X`; None when absent (legacy specs = M)."""
+    spec = fd / "spec.md"
+    if not spec.exists():
+        return None
+    m = _SIZE_RE.search(spec.read_text(errors="replace"))
+    return m.group(1) if m else None
+
+
+def _code_changed_since(commit):
+    """True when a commit after `commit` touches code outside specs/ (or `commit` is unknown);
+    None outside a git repository."""
+    if _git("rev-parse", "--git-dir")[0] != 0:
+        return None
+    rc, out = _git("log", "--format=%h", f"{commit}..HEAD", "--", ".", ":(exclude)specs")
+    if rc == 0:
+        return bool(out.strip())
+    return True  # the commit is gone (rebased/amended) — it no longer names this code
+
+
+def _parse_acs(fd):
+    """Acceptance criteria from spec.md: [{id, num, frs, level, reason}] in file order."""
+    spec = fd / "spec.md"
+    if not spec.exists():
+        return []
+    acs = []
+    for m in _AC_LINE_RE.finditer(spec.read_text(errors="replace")):
+        line = m.group(0)
+        vm = _AC_VERIFY_RE.search(line)
+        acs.append({"id": f"AC-{m.group(1)}", "num": int(m.group(1)),
+                    "frs": sorted(set(re.findall(r"FR-\d{3}", line))),
+                    "level": vm.group(1).lower() if vm else None,
+                    "reason": (vm.group(2) or "").strip() if vm else ""})
+    return acs
+
+
+def _ac_test_tasks(fd):
+    """{AC id: [task line, …]} for tasks.md lines carrying [TEST] and [AC-###]."""
+    tasks = fd / "tasks.md"
+    found = {}
+    if not tasks.exists():
+        return found
+    for line in tasks.read_text(errors="replace").splitlines():
+        if "[TEST]" in line:
+            for n in _AC_TAG_RE.findall(line):
+                found.setdefault(f"AC-{n}", []).append(line)
+    return found
+
+
+def _parse_results(paths):
+    """Test cases from JUnit XML and TRX files: [{name, outcome: pass|fail|skip, file}]."""
+    cases = []
+    for path in paths:
+        try:
+            root = ET.parse(path).getroot()
+        except (ET.ParseError, OSError):
+            continue
+        for el in root.iter():
+            tag = el.tag.rsplit("}", 1)[-1]
+            if tag == "testcase":                                 # JUnit (Vitest, Cypress, jest, pytest)
+                name = " ".join(filter(None, [el.get("classname"), el.get("name")]))
+                kids = {c.tag.rsplit("}", 1)[-1] for c in el}
+                outcome = "fail" if kids & {"failure", "error"} else "skip" if "skipped" in kids else "pass"
+                cases.append({"name": name, "outcome": outcome, "file": str(path)})
+            elif tag == "UnitTestResult":                         # TRX (dotnet test --logger trx)
+                o = (el.get("outcome") or "").lower()
+                outcome = "pass" if o == "passed" else "fail" if o in ("failed", "error", "timeout", "aborted") else "skip"
+                cases.append({"name": el.get("testName") or "", "outcome": outcome, "file": str(path)})
+    return cases
+
+
+def _freeze(fd):
+    f = fd / FREEZE_FILE
+    if not f.exists():
+        return None
+    try:
+        return json.loads(f.read_text())
+    except json.JSONDecodeError:
+        return None
+
+
+def _sha(path):
+    return hashlib.sha256(Path(path).read_bytes()).hexdigest()
+
+
+def _frozen_changed(fd):
+    """Frozen acceptance-test files whose content differs from the freeze (or that vanished)."""
+    fr = _freeze(fd)
+    if not fr:
+        return []
+    changed = []
+    for path, digest in fr.get("files", {}).items():
+        if not Path(path).exists() or _sha(path) != digest:
+            changed.append(path)
+    return changed
+
+
+def _acceptance_round(fd):
+    """The latest round of acceptance.md: result, commit, staleness."""
+    f = fd / ACCEPTANCE
+    if not f.exists():
+        return {"present": False, "rounds": 0, "result": None, "commit": None, "stale": None}
+    text = f.read_text(errors="replace")
+    rounds = list(_ROUND_RE.finditer(text))
+    last = text[rounds[-1].start():] if rounds else text
+    rm, cm = _ACC_RESULT_RE.search(last), _ACC_COMMIT_RE.search(last)
+    commit = cm.group(1) if cm else None
+    return {"present": True, "rounds": len(rounds), "result": rm.group(1) if rm else None,
+            "commit": commit, "stale": _code_changed_since(commit) if commit else None}
+
+
+def _acceptance_problem(fd):
+    """Why acceptance does not open the gate; None when it does or the spec has no ACs."""
+    if not _parse_acs(fd):
+        return None
+    ar = _acceptance_round(fd)
+    if not ar["present"]:
+        return f"no {ACCEPTANCE} — run the acceptance loop ('accept [feature]') first"
+    if ar["result"] != "PASS":
+        return f"{ACCEPTANCE}: latest round is {ar['result'] or 'without a **Result**'} — every automated AC must pass"
+    if ar["commit"] is None:
+        return f"{ACCEPTANCE}: latest round has no '**Commit**:' sha"
+    if ar["stale"]:
+        return f"{ACCEPTANCE}: code changed after the passing round's commit {ar['commit']} — re-run 'accept [feature]'"
+    return None
+
+
+def _final_review(fd):
+    """The latest round of review-final.md: verdict, reviewed commit, and whether code changed since."""
+    f = fd / FINAL_REVIEW
+    if not f.exists():
+        return {"present": False, "rounds": 0, "verdict": None, "reviewed_commit": None, "stale": None}
+    text = f.read_text(errors="replace")
+    rounds = list(_ROUND_RE.finditer(text))
+    last = text[rounds[-1].start():] if rounds else text
+    vm = _VERDICT_RE.search(last)
+    cm = _REVIEWED_COMMIT_RE.search(last)
+    commit = cm.group(1) if cm else None
+    stale = _code_changed_since(commit) if commit else None
+    return {"present": True, "rounds": len(rounds), "verdict": vm.group(1) if vm else None,
+            "reviewed_commit": commit, "stale": stale}
+
+
+def _final_review_problem(fr):
+    """Why the final review does not open the merge gate; None when it does."""
+    if not fr["present"]:
+        return f"no {FINAL_REVIEW} — run the final review (spec-kit-review, final mode) first"
+    if fr["verdict"] is None:
+        return f"{FINAL_REVIEW}: latest round has no '**Verdict**:' line"
+    if fr["verdict"] == "AWAITING-OWNER":
+        return f"{FINAL_REVIEW}: latest verdict is AWAITING-OWNER — get the owner's answers and append a specs-only Round N+1"
+    if fr["verdict"] not in PASSING_VERDICTS:
+        return f"{FINAL_REVIEW}: latest verdict is {fr['verdict']} — fix the findings (bugfix loop) and re-review"
+    if fr["reviewed_commit"] is None:
+        return f"{FINAL_REVIEW}: latest round has no '**Reviewed-commit**:' sha"
+    if fr["stale"]:
+        return f"{FINAL_REVIEW}: code changed after the reviewed commit {fr['reviewed_commit']} — re-run the final review"
+    return None
+
+
+def _derive(feature):
+    """Derive the feature's state from its files. None when the directory is absent."""
+    fd = _feature_dir(feature)
+    if not fd.is_dir():
+        return None
+    present = {a for a in TRACKED_ARTIFACTS if (fd / a).exists()}
+    contracts = sorted(p.name for p in (fd / "contracts").glob("*")) if (fd / "contracts").is_dir() else []
+
+    bugs = _parse_bugs((fd / "bugs.md").read_text(errors="replace")) if "bugs.md" in present else []
+    tasks = _parse_tasks((fd / "tasks.md").read_text(errors="replace")) if "tasks.md" in present else []
+    open_bugs = [b for b in bugs if b["status"] in ("open", "in-progress")]
+    claimed = [b for b in bugs if b["status"] == "claimed"]
+    closed_on_disk = any(c in present for c in CLOSE_DOCS)
+    size = _parse_size(fd)
+
+    if not {"spec.md"} <= present:
+        phase, status = 1, "new"
+    elif "plan.md" not in present:
+        phase, status = 2, "active"
+    elif "tasks.md" not in present:
+        phase, status = 3, "active"
+    elif closed_on_disk:
+        if open_bugs:
+            phase, status = 5, "reopened"
+        else:
+            phase, status = 6, "closed"
+    elif tasks and all(t["done"] for t in tasks) or "bugs.md" in present:
+        phase, status = 5, "active"
+    else:
+        phase, status = 4, "active"
+
+    return {
+        "feature": feature,
+        "current_phase": phase,
+        "phase_name": PHASES[phase]["name"],
+        "status": status,
+        "artifacts": {a: ("present" if a in present else "absent") for a in TRACKED_ARTIFACTS},
+        "contracts": contracts,
+        "size": size or "M",
+        "size_declared": size is not None,
+        "history": dict(zip(("on", "source"), _history_setting(fd, size))),
+        "final_review": _final_review(fd) if phase >= 5 else None,
+        "acceptance": ({"criteria": len(acs), "round": _acceptance_round(fd) if phase >= 5 else None}
+                       if (acs := _parse_acs(fd)) else None),
+        "tasks": {"total": len(tasks), "done": sum(t["done"] for t in tasks),
+                  "bugfix": sum(t["kind"] == "BF" for t in tasks)},
+        "bugs": {"total": len(bugs), "open": len(open_bugs), "claimed": len(claimed),
+                 "verified": sum(b["status"] == "verified" for b in bugs),
+                 "superseded": sum(b["status"] == "superseded" for b in bugs)},
+        "derived_at": _now(),
+    }
+
+
+def _phase_card(state):
+    """Ten lines to re-read after context compaction."""
+    f = state["feature"]
+    phase = state["current_phase"]
+    allowed = {
+        1: "spec.md only — no code",
+        2: "plan.md, research.md, data-model.md, contracts/*, quickstart.md — no code",
+        3: "tasks.md only — no code",
+        4: "source code, tasks.md [X] marks, bugs.md status→claimed with Evidence",
+        5: "bugs.md only — log before fix; verified needs an oracle",
+        6: "close.md + change-record.md, plan.md Current Design, spec/plan deviation patches, ADRs, AGENTS.md",
+    }[phase]
+    gate = {
+        1: "spec.md written → commit spec(phase-1)",
+        2: "plan artifacts written → commit spec(phase-2)",
+        3: "tasks.md written, TDD question asked → commit spec(phase-3)",
+        4: "phase RED/GREEN evidence saved, probes per [SEAM], tasks [X], history entry with Implemented-by → one commit per phase; then accept",
+        5: f"{state['bugs']['open']} open, {state['bugs']['claimed']} claimed-unverified → verify with user/ci/other-agent or run 'bugfix {f}'; then the final review ({FINAL_REVIEW}) must say READY",
+        6: "final review READY and fresh, every bug verified/superseded, close.md (Architecture Decisions) + change-record.md → one commit spec(phase-6)",
+    }[phase]
+    fr = state.get("final_review") or {}
+    review_line = (f"final review: {fr.get('verdict') or 'missing verdict'} @ {fr.get('reviewed_commit') or '?'}"
+                   f"{' — STALE, re-review' if fr.get('stale') else ''}" if fr.get("present")
+                   else "final review: not run" if phase >= 5 else None)
+    acc = state.get("acceptance") or {}
+    if acc.get("round"):
+        r = acc["round"]
+        acc_line = (f"acceptance: {acc['criteria']} ACs · round {r['rounds']} {r['result'] or '?'} @ {r['commit'] or '?'}"
+                    f"{' — STALE, re-run accept' if r['stale'] else ''}" if r["present"]
+                    else f"acceptance: {acc['criteria']} ACs · not run — 'accept {f}' before the final review")
+    else:
+        acc_line = None
+    lines = [
+        f"PHASE CARD — {f}",
+        f"phase: {phase} ({state['phase_name']})  status: {state['status']}  size: {state['size']}{'' if state['size_declared'] else ' (undeclared — treated as M)'}",
+        f"allowed writes: {allowed}",
+        f"next gate: {gate}",
+        f"tasks: {state['tasks']['done']}/{state['tasks']['total']} done ({state['tasks']['bugfix']} BF)",
+        f"bugs: {state['bugs']['open']} open · {state['bugs']['claimed']} claimed · {state['bugs']['verified']} verified",
+        f"rules: history.md {'ON — entry before every commit' if state['history']['on'] else 'OFF — timeline from git at close'} ({state['history']['source']}) · additive-only · evidence before claims",
+        acc_line or "ids: call next_id before adding a BUG/T/BF · lint_artifacts before every commit",
+        review_line or "ask: an ASK you cannot put to a human is an ASSUMPTION — record it in decisions.md",
+        f"derived from files at {state['derived_at']} — the files are the truth, not this card",
+    ]
+    return "\n".join(lines)
+
+
+def _json(obj):
+    return json.dumps(obj, ensure_ascii=False)
+
+
+def _not_found(feature):
+    available = sorted(d.name for d in SPECS_DIR.iterdir() if d.is_dir() and not d.name.startswith(".")) if SPECS_DIR.is_dir() else []
+    return _json({"error": f"Feature '{feature}' not found", "available_features": available})
+
+
+mcp = FastMCP("spec-kit-workflow")
+
+
+# ── Project-level tools ────────────────────────────────────────────────────
+
+
+@mcp.tool(name="project_status")
+def project_status() -> str:
+    """Project-level status derived from files: constitution present?, feature count,
+    whether a legacy specs/.spec-kit/state.json still exists (it is ignored — delete it).
+    """
+    features = sorted(d.name for d in SPECS_DIR.iterdir() if d.is_dir() and not d.name.startswith(".")) if SPECS_DIR.is_dir() else []
+    conv = _conventions()
+    hints = []
+    if conv.get("epics_dir") and (conv.get("epics_index") or "on").lower() == "on" and Path(conv["epics_dir"]).is_dir() \
+            and not (Path(conv["epics_dir"]) / "README.md").exists() and any(Path(conv["epics_dir"]).glob("*/epic.md")):
+        hints.append(f"epics_index is on but {conv['epics_dir']}/README.md is missing — create it from epics-index-template.md (spec-kit epic status)")
+    if not conv.get("epics_dir"):
+        by_epic = {}
+        for f in features:
+            e = _epic_of(SPECS_DIR / f)
+            if e:
+                by_epic.setdefault(e, []).append(f)
+        for e, fs in by_epic.items():
+            if len(fs) >= 3:
+                hints.append(f"{len(fs)} specs name epic '{e}' but no epics_dir is set — consider an epic plan (spec-kit epic {e})")
+    if not conv.get("design_dir"):
+        by_module = {}
+        for f in features:
+            fd = SPECS_DIR / f
+            if any((fd / c).exists() for c in CLOSE_DOCS):
+                for m in _modules_of(fd):
+                    by_module.setdefault(m, []).append(f)
+        for m, fs in by_module.items():
+            if len(fs) >= 3:
+                hints.append(f"{len(fs)} closed features name module '{m}' but no design_dir is set — consider a module design doc (spec-kit design {m})")
+    return _json({
+        "version": 3,
+        "epics_dir": conv.get("epics_dir"),
+        "design_dir": conv.get("design_dir"),
+        "hints": hints,
+        "constitution": "present" if (SPECS_DIR / "constitution.md").exists() else "absent",
+        "git_conventions": "present" if (SPECS_DIR / "git-conventions.md").exists() else "absent",
+        "merge_checklist": "present" if (SPECS_DIR / "merge-checklist.md").exists() else "absent",
+        "adr_dir": str(_adr_dir()) if _adr_dir() else None,
+        "features": len(features),
+        "legacy_state_file": LEGACY_STATE_FILE.exists(),
+        "note": "state is derived from files on every call; nothing is persisted by this server",
+    })
+
+
+@mcp.tool(name="project_set_constitution")
+def project_set_constitution(status: str = "present", principles: str = "") -> str:
+    """Confirm the constitution after writing it. Nothing is stored: the call checks that
+    specs/constitution.md exists (status 'present') or does not ('absent') and reports.
+
+    Args:
+        status: 'present' or 'absent' — must match the file on disk
+        principles: Optional JSON object of parsed principles (validated, echoed back)
+    """
+    exists = (SPECS_DIR / "constitution.md").exists()
+    actual = "present" if exists else "absent"
+    parsed = {}
+    if principles:
+        try:
+            parsed = json.loads(principles)
+        except json.JSONDecodeError:
+            return _json({"error": "principles must be valid JSON object", "constitution": actual})
+    if status != actual:
+        return _json({"error": f"specs/constitution.md is {actual} on disk, not '{status}' — write the file first", "constitution": actual})
+    return _json({"success": True, "constitution": actual, "principles": parsed})
+
+
+# ── Feature tools ──────────────────────────────────────────────────────────
+
+
+@mcp.tool(name="init_feature")
+def init_feature(feature: str, name: str = None, mode: str = "specify") -> str:
+    """Create specs//. history.md is written only when the project default is
+    `history: always`; otherwise specify creates it once the size is known (large → L only).
+    Fails if the directory exists.
+
+    Args:
+        feature: Feature ID (e.g., 003-user-auth)
+        name: Human-readable name (defaults to feature ID)
+        mode: specify, bugfix, or reopen (recorded in the history header only)
+    """
+    fd = _feature_dir(feature)
+    if fd.exists():
+        return _json({"error": f"Feature '{feature}' already exists", "state": _derive(feature)})
+    fd.mkdir(parents=True)
+    if (_conventions().get("history") or "large").lower() == "always":
+        (fd / "history.md").write_text(f"# Process History: {name or feature}\n\n> mode: {mode} · created {_now()}\n")
+    else:
+        (fd / ".gitkeep").write_text("")
+    return _json({"success": True, "state": _derive(feature)})
+
+
+@mcp.tool(name="get_feature_state")
+def get_feature_state(feature: str) -> str:
+    """Derive the feature's phase, status, artifacts, task and bug counts from its files.
+
+    Args:
+        feature: Feature ID
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    return _json({"state": state, "phase_card": _phase_card(state)})
+
+
+@mcp.tool(name="get_next_actions")
+def get_next_actions(feature: str) -> str:
+    """Available actions from the derived phase, plus the ten-line PHASE CARD. Call this
+    after context compaction and before any write.
+
+    Args:
+        feature: Feature ID
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    phase, status = state["current_phase"], state["status"]
+    actions = []
+    if status == "closed":
+        actions.append({"action": "reopen_feature", "description": "Reopen for bugfixing (log bugs via spec-kit-test first)"})
+    elif phase < 6:
+        nxt = phase + 1
+        ok, reason = _validate_phase(state, nxt)
+        a = {"action": f"advance_to_{PHASES[nxt]['name']}", "phase": nxt,
+             "description": f"Advance to phase {nxt} ({PHASES[nxt]['name']})"}
+        if not ok:
+            a.update({"blocked": True, "reason": reason})
+        actions.append(a)
+    if state["bugs"]["open"]:
+        actions.append({"action": "bugfix", "description": f"'bugfix {feature}' — {state['bugs']['open']} open bug(s)"})
+    if state["bugs"]["claimed"]:
+        actions.append({"action": "verify", "description": f"{state['bugs']['claimed']} claimed bug(s) need an oracle (user / ci / review:)"})
+    acc_problem = _acceptance_problem(_feature_dir(feature)) if phase == 5 else None
+    if acc_problem:
+        actions.append({"action": "accept", "description": f"Run the acceptance loop — {acc_problem}"})
+    if phase == 5 and not state["bugs"]["open"] and not acc_problem:
+        problem = _final_review_problem(state["final_review"])
+        if problem:
+            actions.append({"action": "final_review", "description": f"Run the final (merge-readiness) review — {problem}"})
+    if phase == 6 and status != "closed":
+        actions.append({"action": "close_feature", "description": "Write close.md / implementation-summary.md"})
+    return _json({"current_phase": phase, "phase_name": state["phase_name"], "status": status,
+                  "available_actions": actions, "phase_card": _phase_card(state)})
+
+
+def _validate_phase(state, to_phase):
+    fd = _feature_dir(state["feature"])
+    for art in PREREQUISITES.get(to_phase, []):
+        if not (fd / art).exists():
+            return False, f"Prerequisite not met: {art} must exist"
+    if to_phase == 6:
+        bugs_file = fd / "bugs.md"
+        if bugs_file.exists():
+            bugs = _parse_bugs(bugs_file.read_text(errors="replace"))
+            blocking = [b["id"] for b in bugs if b["status"] in ("open", "in-progress")]
+            if blocking:
+                return False, f"Prerequisite not met: open bugs {blocking} — run bugfix first"
+        problem = _acceptance_problem(fd) or _final_review_problem(_final_review(fd))
+        if problem:
+            return False, f"Prerequisite not met: {problem}"
+    return True, None
+
+
+@mcp.tool(name="advance_phase")
+def advance_phase(feature: str, from_phase: int, artifacts_created: list[str] = None) -> str:
+    """Validate that the feature may leave `from_phase`: the derived phase must be
+    from_phase (or already from_phase + 1, since the artifacts were just written) and
+    every artifact named in artifacts_created plus the next phase's prerequisites must
+    exist on disk. Nothing is written — the artifacts ARE the state.
+
+    Args:
+        feature: Feature ID
+        from_phase: The phase the skill believes it is completing
+        artifacts_created: Artifact files the skill wrote (verified to exist)
+    """
+    artifacts_created = artifacts_created or []
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    if from_phase == 0:
+        return _json({"error": "Phase 0 (constitution) is project-level — use project_set_constitution"})
+    if state["status"] == "closed":
+        return _json({"error": f"Feature '{feature}' is closed — use reopen"})
+    # The skill calls this AFTER writing its artifacts, so the files may already
+    # place the feature in from_phase + 1. Anything else is a mismatch.
+    if state["current_phase"] not in (from_phase, from_phase + 1):
+        return _json({"error": f"Phase mismatch: expected {from_phase}, derived phase is {state['current_phase']} ({state['phase_name']}) from the files on disk"})
+    fd = _feature_dir(feature)
+    missing = [a for a in artifacts_created if not (fd / a).exists()]
+    if missing:
+        return _json({"error": f"artifacts_created not on disk: {missing} — write the file before syncing"})
+    to_phase = from_phase + 1
+    ok, reason = _validate_phase(state, to_phase)
+    if not ok:
+        return _json({"error": reason})
+    # Re-derive: the written artifacts may already move the feature forward.
+    after = _derive(feature)
+    return _json({"success": True, "from_phase": from_phase, "to_phase": to_phase,
+                  "phase_name": PHASES[to_phase]["name"], "artifacts_verified": artifacts_created,
+                  "state": after, "phase_card": _phase_card(after)})
+
+
+@mcp.tool(name="list_features")
+def list_features() -> str:
+    """List every specs// directory with derived phase, status and bug counts."""
+    if not SPECS_DIR.is_dir():
+        return _json({"error": "specs/ directory not found"})
+    result = []
+    for d in sorted(SPECS_DIR.iterdir()):
+        if d.is_dir() and not d.name.startswith("."):
+            s = _derive(d.name)
+            result.append({"feature": d.name, "phase": s["current_phase"], "phase_name": s["phase_name"],
+                           "status": s["status"], "open_bugs": s["bugs"]["open"], "claimed_bugs": s["bugs"]["claimed"]})
+    return _json({"features": result})
+
+
+@mcp.tool(name="reopen_feature")
+def reopen_feature(feature: str) -> str:
+    """Check that a feature can be reopened (it must be closed on disk) and return the
+    reopen branch pattern. Reopening is materialised by logging an open bug in bugs.md
+    via spec-kit-test — this call writes nothing.
+
+    Args:
+        feature: Feature ID
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    if state["status"] not in ("closed", "reopened"):
+        return _json({"error": f"Feature '{feature}' is not closed (status: {state['status']})"})
+    return _json({"success": True, "feature": feature, "status": state["status"],
+                  "next": "Log the bug(s) in bugs.md via spec-kit-test (Status: open), then run 'bugfix [feature]'",
+                  "branch_hint": "{original_prefix}/" + feature + "{reopen_suffix}"})
+
+
+@mcp.tool(name="close_feature")
+def close_feature(feature: str) -> str:
+    """Validate the close: a close document exists with an `## Architecture Decisions`
+    section and change-record.md is present, the latest acceptance round PASSes on the current code (when spec.md has ACs), the final review's latest verdict is READY / READY-WITH-FOLLOWUPS and no code
+    changed after its reviewed commit, no bug is open/in-progress, and every verified bug
+    carries a Verified-by oracle. Reports claimed-unverified bugs. Writes nothing.
+
+    Args:
+        feature: Feature ID
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    fd = _feature_dir(feature)
+    if not any((fd / c).exists() for c in CLOSE_DOCS):
+        return _json({"error": f"Feature '{feature}' has no close.md / implementation-summary.md — write it first (phase {state['current_phase']})"})
+    problems = []
+    unverified = []
+    close_text = "".join((fd / c).read_text(errors="replace") for c in CLOSE_DOCS if (fd / c).exists())
+    if "## Architecture Decisions" not in close_text:
+        problems.append("close document has no '## Architecture Decisions' section (write 'none met the ADR bar' if so)")
+    if not (fd / "change-record.md").exists():
+        problems.append("change-record.md missing — the auditor's page (change-record-template.md)")
+    for problem in (_acceptance_problem(fd), _final_review_problem(_final_review(fd))):
+        if problem:
+            problems.append(problem)
+    if (fd / "bugs.md").exists():
+        for b in _parse_bugs((fd / "bugs.md").read_text(errors="replace")):
+            if b["status"] in ("open", "in-progress"):
+                problems.append(f"{b['id']} is {b['status']}")
+            elif b["status"] == "claimed":
+                unverified.append(b["id"])
+            elif b["status"] == "verified" and not VERIFIED_BY_RE.match(b["verified_by"]):
+                problems.append(f"{b['id']} is verified without a Verified-by oracle")
+    if problems:
+        return _json({"error": "Cannot close: " + "; ".join(problems)})
+    return _json({"success": True, "feature": feature, "status": "closed",
+                  "claimed_unverified": unverified,
+                  "note": "list claimed_unverified bugs in the close document" if unverified else "all bugs verified or superseded"})
+
+
+@mcp.tool(name="update_artifact")
+def update_artifact(feature: str, artifact: str, status: str = "present") -> str:
+    """Confirm an artifact's status against disk after writing it. 'present'/'verified'
+    require the file to exist; 'absent' requires it not to. Nothing is stored.
+
+    Args:
+        feature: Feature ID
+        artifact: Artifact filename (e.g., spec.md, plan.md)
+        status: present, absent, or verified
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    exists = (_feature_dir(feature) / artifact).exists()
+    if status in ("present", "verified") and not exists:
+        return _json({"error": f"{artifact} is not on disk — write it before syncing"})
+    if status == "absent" and exists:
+        return _json({"error": f"{artifact} exists on disk — it is not absent"})
+    return _json({"success": True, "feature": feature, "artifact": artifact, "status": status})
+
+
+@mcp.tool(name="auto_detect_features")
+def auto_detect_features(feature: str = None) -> str:
+    """Scan specs/ and report every feature's derived state. Also reports whether a legacy
+    specs/.spec-kit/state.json is present (ignored; delete it and gitignore the directory).
+
+    Args:
+        feature: Optional feature ID to scan (scans all if omitted)
+    """
+    if not SPECS_DIR.is_dir():
+        return _json({"error": "specs/ directory not found"})
+    found = {}
+    for d in sorted(SPECS_DIR.iterdir()):
+        if d.is_dir() and not d.name.startswith(".") and (feature is None or d.name == feature):
+            found[d.name] = _derive(d.name)
+    return _json({
+        "success": True,
+        "features_detected": len(found),
+        "features": list(found.keys()),
+        "states": found,
+        "project": {"constitution": "present" if (SPECS_DIR / "constitution.md").exists() else "absent"},
+        "legacy_state_file": LEGACY_STATE_FILE.exists(),
+    })
+
+
+# ── Enforcement tools ──────────────────────────────────────────────────────
+
+
+@mcp.tool(name="next_id")
+def next_id(feature: str, kind: str) -> str:
+    """Allocate the next sequential id by scanning the files: kind 'BUG' (bugs.md),
+    'T' (tasks.md T###) or 'BF' (tasks.md BF-###). Call before adding an entry.
+
+    Args:
+        feature: Feature ID
+        kind: BUG | T | BF | AC | ADR | EPIC (ADR scans the ADR directory, EPIC the epics_dir — neither reads the feature)
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    fd = _feature_dir(feature)
+    kind = kind.upper()
+    if kind == "BUG":
+        nums = [b["num"] for b in _parse_bugs((fd / "bugs.md").read_text(errors="replace"))] if (fd / "bugs.md").exists() else []
+        fmt = "BUG-{:03d}"
+    elif kind == "AC":
+        nums = [a["num"] for a in _parse_acs(fd)]
+        fmt = "AC-{:03d}"
+    elif kind == "ADR":
+        adr_dir = _adr_dir()
+        if adr_dir is None:
+            return _json({"error": f"no ADR directory — set adr_dir in specs/git-conventions.md or create one of {list(ADR_DIR_CANDIDATES)}"})
+        nums = [int(m.group(1)) for p in adr_dir.glob("*.md") for m in [re.match(r"(\d{3,4})-", p.name)] if m]
+        n = (max(nums) + 1) if nums else 1
+        return _json({"success": True, "kind": kind, "next_id": f"{n:04d}", "adr_dir": str(adr_dir), "existing": len(nums)})
+    elif kind == "EPIC":
+        epics_dir = _conventions().get("epics_dir")
+        if not epics_dir:
+            return _json({"error": "git-conventions.md sets no epics_dir — epics are not kept in this project"})
+        nums = [int(m.group(1)) for p in Path(epics_dir).glob("*") for m in [re.match(r"(\d{2,6})-", p.name)] if m]
+        n = (max(nums) + 1) if nums else 1
+        return _json({"success": True, "kind": kind, "next_id": f"{n:03d}", "epics_dir": epics_dir, "existing": len(nums),
+                      "note": "prefer the tracker's epic number (ADO / Jira) when one exists"})
+    elif kind in ("T", "BF"):
+        tasks = _parse_tasks((fd / "tasks.md").read_text(errors="replace")) if (fd / "tasks.md").exists() else []
+        nums = [t["num"] for t in tasks if t["kind"] == kind]
+        fmt = "T{:03d}" if kind == "T" else "BF-{:03d}"
+    else:
+        return _json({"error": "kind must be BUG, T, BF, AC, ADR or EPIC"})
+    n = (max(nums) + 1) if nums else 1
+    return _json({"success": True, "kind": kind, "next_id": fmt.format(n), "existing": len(nums)})
+
+
+@mcp.tool(name="lint_artifacts")
+def lint_artifacts(feature: str) -> str:
+    """Lint bugs.md, tasks.md, history.md, spec.md ACs, acceptance.md and review-final.md
+    against the spec-kit schema: status vocabulary, Verified-by on verified bugs, Evidence on claimed bugs,
+    ascending ids, summary-table counts, probes per [SEAM], RED files per done [TEST],
+    round headers, history header present. Returns findings; call before every commit.
+
+    Args:
+        feature: Feature ID
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    fd = _feature_dir(feature)
+    findings = []
+
+    if (fd / "bugs.md").exists():
+        text = (fd / "bugs.md").read_text(errors="replace")
+        bugs = _parse_bugs(text)
+        nums = [b["num"] for b in bugs]
+        if nums != sorted(nums) or len(set(nums)) != len(nums):
+            findings.append({"file": "bugs.md", "severity": "error", "msg": f"BUG ids not strictly ascending: {nums}"})
+        for b in bugs:
+            if b["raw_status"] not in BUG_STATUSES:
+                sev = "warning" if b["raw_status"] in LEGACY_BUG_STATUSES else "error"
+                findings.append({"file": "bugs.md", "severity": sev, "msg": f"{b['id']}: status '{b['raw_status'] or '(empty)'}' not in {sorted(BUG_STATUSES)}"})
+            if b["status"] == "verified" and not VERIFIED_BY_RE.match(b["verified_by"]):
+                findings.append({"file": "bugs.md", "severity": "error", "msg": f"{b['id']}: verified without Verified-by (user | ci: | review:)"})
+            if b["status"] == "claimed":
+                blk = text.split(f"### {b['id']}:", 1)[1].split("\n### ", 1)[0]
+                if not re.search(r"\*\*Evidence\*\*:\s*(?!\[)(output:|probe:)", blk):
+                    findings.append({"file": "bugs.md", "severity": "warning", "msg": f"{b['id']}: claimed without Evidence (output:/probe:)"})
+        if "## Summary" in text:
+            summary = text.split("## Summary", 1)[1]
+            rows = set(re.findall(r"^\| (BUG-\d+) ", summary, re.M))
+            missing = [b["id"] for b in bugs if b["id"] not in rows]
+            if missing:
+                findings.append({"file": "bugs.md", "severity": "error", "msg": f"Summary table missing rows for {missing}"})
+            tm = re.search(r"\*\*Total Bugs\*\*:\s*(\d+)", summary)
+            if tm and int(tm.group(1)) != len(bugs):
+                findings.append({"file": "bugs.md", "severity": "error", "msg": f"Total Bugs says {tm.group(1)}, found {len(bugs)}"})
+
+    if (fd / "tasks.md").exists():
+        tasks_text = (fd / "tasks.md").read_text(errors="replace")
+        tasks = _parse_tasks(tasks_text)
+        evidence = [p.name for p in (fd / "evidence").glob("*")] if (fd / "evidence").is_dir() else []
+        for line in tasks_text.splitlines():
+            m = _TASK_RE.match(line)
+            if not m or (_task_mark(m) or " ") not in "xX":
+                continue
+            tid = m.group("id")
+            if "[SEAM]" in line and not any(e.startswith(f"{tid}-probe") for e in evidence):
+                findings.append({"file": "tasks.md", "severity": "warning", "msg": f"{tid} [SEAM] marked done without evidence/{tid}-probe-*.txt"})
+            if "[TEST]" in line and not any("-red" in e for e in evidence):
+                findings.append({"file": "tasks.md", "severity": "warning", "msg": f"{tid} [TEST] marked done but no *-red* file in evidence/"})
+        for kind in ("T", "BF"):
+            nums = [t["num"] for t in tasks if t["kind"] == kind]
+            if nums != sorted(nums):
+                findings.append({"file": "tasks.md", "severity": "error", "msg": f"{kind} ids not ascending: {nums}"})
+            dup = {n for n in nums if nums.count(n) > 1}
+            if dup:
+                findings.append({"file": "tasks.md", "severity": "error", "msg": f"duplicate {kind} ids: {sorted(dup)}"})
+
+    if (fd / "plan.md").exists() and any((fd / c).exists() for c in CLOSE_DOCS):
+        if "## Current Design" not in (fd / "plan.md").read_text(errors="replace"):
+            findings.append({"file": "plan.md", "severity": "warning", "msg": "closed feature without a '## Current Design' section — regenerate it at close"})
+
+    if (fd / FINAL_REVIEW).exists():
+        text = (fd / FINAL_REVIEW).read_text(errors="replace")
+        rounds = list(_ROUND_RE.finditer(text))
+        if not rounds:
+            findings.append({"file": FINAL_REVIEW, "severity": "error", "msg": "no '## Round N — ' section"})
+        for i, m in enumerate(rounds):
+            body = text[m.start():rounds[i + 1].start() if i + 1 < len(rounds) else len(text)]
+            if not _VERDICT_RE.search(body):
+                findings.append({"file": FINAL_REVIEW, "severity": "error", "msg": f"Round {m.group(1)}: no '**Verdict**: READY | READY-WITH-FOLLOWUPS | AWAITING-OWNER | NOT READY'"})
+            if not _REVIEWED_COMMIT_RE.search(body):
+                findings.append({"file": FINAL_REVIEW, "severity": "error", "msg": f"Round {m.group(1)}: no '**Reviewed-commit**: '"})
+        nums = [int(m.group(1)) for m in rounds]
+        if nums != list(range(1, len(nums) + 1)):
+            findings.append({"file": FINAL_REVIEW, "severity": "error", "msg": f"rounds not numbered 1..N: {nums}"})
+
+    acs = _parse_acs(fd)
+    if acs:
+        nums = [a["num"] for a in acs]
+        if nums != sorted(nums) or len(set(nums)) != len(nums):
+            findings.append({"file": "spec.md", "severity": "error", "msg": f"AC ids not strictly ascending: {nums}"})
+        for a in acs:
+            if a["level"] not in AC_LEVELS:
+                findings.append({"file": "spec.md", "severity": "error", "msg": f"{a['id']}: 'Verify: <{'|'.join(AC_LEVELS)}>' missing or unknown ({a['level']})"})
+            elif a["level"] in AC_REASON_LEVELS and not a["reason"]:
+                findings.append({"file": "spec.md", "severity": "error", "msg": f"{a['id']}: Verify: {a['level']} needs a reason — 'Verify: {a['level']} (why no lower level can prove it)'"})
+        spec_text = (fd / "spec.md").read_text(errors="replace")
+        frs = sorted(set(re.findall(r"\*\*(FR-\d{3})\*\*", spec_text)))
+        covered = {fr for a in acs for fr in a["frs"]}
+        uncovered = [fr for fr in frs if fr not in covered]
+        if uncovered:
+            findings.append({"file": "spec.md", "severity": "warning", "msg": f"FRs no acceptance criterion names: {uncovered}"})
+        if (fd / "tasks.md").exists():
+            tagged = _ac_test_tasks(fd)
+            known = {a["id"] for a in acs}
+            for ac in sorted(set(tagged) - known):
+                findings.append({"file": "tasks.md", "severity": "error", "msg": f"[{ac}] tagged on a task but not defined in spec.md"})
+            for a in acs:
+                if a["level"] in AC_TEST_LEVELS and a["id"] not in tagged:
+                    findings.append({"file": "tasks.md", "severity": "error", "msg": f"{a['id']} (Verify: {a['level']}) has no '[TEST] [{a['id']}]' task"})
+        changed = _frozen_changed(fd)
+        if changed:
+            findings.append({"file": FREEZE_FILE, "severity": "error", "msg": f"frozen acceptance tests changed: {changed} — revert, or re-freeze with the user's approval (acceptance_freeze refreeze=true)"})
+
+    if (fd / ACCEPTANCE).exists():
+        text = (fd / ACCEPTANCE).read_text(errors="replace")
+        rounds = list(_ROUND_RE.finditer(text))
+        for i, m in enumerate(rounds):
+            body = text[m.start():rounds[i + 1].start() if i + 1 < len(rounds) else len(text)]
+            if not _ACC_RESULT_RE.search(body):
+                findings.append({"file": ACCEPTANCE, "severity": "error", "msg": f"Round {m.group(1)}: no '**Result**: PASS | FAIL | STOPPED'"})
+            if not _ACC_COMMIT_RE.search(body):
+                findings.append({"file": ACCEPTANCE, "severity": "error", "msg": f"Round {m.group(1)}: no '**Commit**: '"})
+
+    if "spec.md" in state["artifacts"] and state["artifacts"]["spec.md"] == "present" and not state["size_declared"]:
+        findings.append({"file": "spec.md", "severity": "warning", "msg": "no '**Size**: S | M | L' header line — treated as M"})
+
+    conv = _conventions()
+    epic = _epic_of(fd)
+    if epic:
+        epics_dir = conv.get("epics_dir")
+        if not epics_dir:
+            findings.append({"file": "spec.md", "severity": "warning", "msg": f"**Epic**: {epic} but git-conventions.md sets no epics_dir — add it or drop the line"})
+        elif (ef := _epic_features_file(epics_dir, epic)) is None:
+            findings.append({"file": "spec.md", "severity": "warning", "msg": f"**Epic**: {epic} names {epics_dir}/{epic}/features.md which does not exist — run 'spec-kit epic {epic}' (E1–E3)"})
+        elif feature not in ef.read_text(errors="replace"):
+            findings.append({"file": str(ef), "severity": "warning", "msg": f"epic {epic} has no row for {feature} — add it (spec-kit-epic status)"})
+    for module in _modules_of(fd):
+        design_dir = conv.get("design_dir")
+        if not design_dir:
+            findings.append({"file": "plan.md", "severity": "warning", "msg": f"**Modules**: {module} but git-conventions.md sets no design_dir — add it or drop the line"})
+            break
+        if not (Path(design_dir) / f"{module}.md").exists():
+            findings.append({"file": "plan.md", "severity": "warning", "msg": f"module {module} has no {design_dir}/{module}.md — the close cannot patch it (spec-kit design {module})"})
+
+    if any((fd / c).exists() for c in CLOSE_DOCS):
+        close_text = "".join((fd / c).read_text(errors="replace") for c in CLOSE_DOCS if (fd / c).exists())
+        if "## Architecture Decisions" not in close_text:
+            findings.append({"file": "close.md", "severity": "warning", "msg": "close document has no '## Architecture Decisions' section"})
+        if not (fd / "change-record.md").exists():
+            findings.append({"file": "change-record.md", "severity": "warning", "msg": "closed feature without change-record.md — write it from change-record-template.md"})
+
+    if (fd / "history.md").exists():
+        if not (fd / "history.md").read_text(errors="replace").lstrip().startswith("#"):
+            findings.append({"file": "history.md", "severity": "warning", "msg": "missing title header"})
+    elif state["history"]["on"] and (state["current_phase"] > 1 or state["status"] != "new"):
+        findings.append({"file": "history.md", "severity": "error", "msg": f"history.md missing — history is on for this feature ({state['history']['source']})"})
+    if not state["history"]["on"] and (fd / "tasks.md").exists() and state["tasks"]["done"] and "**Implemented-by**:" not in (fd / "tasks.md").read_text(errors="replace"):
+        findings.append({"file": "tasks.md", "severity": "warning", "msg": "history is off — add '**Implemented-by**: ' to the tasks.md header (the review's author check reads it)"})
+
+    errors = sum(f["severity"] == "error" for f in findings)
+    return _json({"success": errors == 0, "errors": errors, "warnings": len(findings) - errors, "findings": findings})
+
+
+@mcp.tool(name="acceptance_freeze")
+def acceptance_freeze(feature: str, refreeze: bool = False, reason: str = "") -> str:
+    """Record SHA-256 checksums of the acceptance-test files — the files named on tasks.md
+    lines that carry [TEST] and [AC-###] — in specs//evidence/acceptance-freeze.json.
+    Call after each implement phase's RED run. Additive: files already frozen keep their
+    checksum; new ones are added. A frozen file that changed is an error unless
+    refreeze=true with the user's reason (record the ruling in decisions.md).
+
+    Args:
+        feature: Feature ID
+        refreeze: Re-hash changed frozen files (only with the user's approval)
+        reason: Why the frozen tests changed (required with refreeze)
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    fd = _feature_dir(feature)
+    tagged = _ac_test_tasks(fd)
+    if not tagged:
+        return _json({"error": "no tasks.md line carries both [TEST] and [AC-###] — tag the acceptance tests first"})
+    paths = sorted({tok for lines in tagged.values() for line in lines
+                    for tok in _PATH_TOKEN_RE.findall(line) if Path(tok).is_file()})
+    if not paths:
+        return _json({"error": "the [AC-###] test tasks name no existing file — write the tests (RED) first",
+                      "acs": sorted(tagged)})
+    fr = _freeze(fd) or {"files": {}, "history": []}
+    changed = [p for p in _frozen_changed(fd)]
+    if changed and not refreeze:
+        return _json({"error": f"frozen acceptance tests changed: {changed} — revert them, or refreeze with the user's approval",
+                      "changed": changed})
+    if refreeze and not reason.strip():
+        return _json({"error": "refreeze needs the user's reason"})
+    added = [p for p in paths if p not in fr["files"]]
+    for p in added + (changed if refreeze else []):
+        if Path(p).exists():
+            fr["files"][p] = _sha(p)
+        else:
+            fr["files"].pop(p, None)
+    _, head = _git("rev-parse", "--short", "HEAD")
+    fr["history"].append({"at": _now(), "commit": head.strip() or None, "added": added,
+                          "refrozen": changed if refreeze else [], "reason": reason.strip() or None})
+    out = fd / FREEZE_FILE
+    out.parent.mkdir(parents=True, exist_ok=True)
+    out.write_text(json.dumps(fr, indent=2) + "\n")
+    return _json({"success": True, "frozen": len(fr["files"]), "added": added,
+                  "refrozen": changed if refreeze else [], "file": str(out)})
+
+
+@mcp.tool(name="acceptance_status")
+def acceptance_status(feature: str, results: str = "", round: int = 0) -> str:
+    """The acceptance matrix: every AC in spec.md → its verify level, its [TEST] [AC-###] tasks,
+    and its outcome from test result files (JUnit XML or TRX; a test belongs to an AC when its
+    name carries the id — 'AC-003 …', 'AC003_…', 'test_ac003_…'). command/probe ACs read
+    evidence/acceptance-r-AC-###.txt whose first line is 'RESULT: PASS' or 'RESULT: FAIL'.
+    Outcomes: pass · fail · missing (automated, no result) · deferred (e2e not run) · manual.
+    Also reports frozen tests that changed. Read-only; the accept loop writes acceptance.md.
+
+    Args:
+        feature: Feature ID
+        results: Comma-separated result files or globs, relative to the project root
+        round: Acceptance round number (for the command/probe evidence files)
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    fd = _feature_dir(feature)
+    acs = _parse_acs(fd)
+    if not acs:
+        return _json({"error": "spec.md defines no '**AC-###**' acceptance criteria"})
+    files = []
+    for pattern in [r.strip() for r in results.split(",") if r.strip()]:
+        matches = sorted(Path(".").glob(pattern)) if any(ch in pattern for ch in "*?[") else [Path(pattern)]
+        files.extend(m for m in matches if m.is_file())
+    cases = _parse_results(files)
+    by_ac = {}
+    for c in cases:
+        for n in _AC_IN_NAME_RE.findall(c["name"]):
+            by_ac.setdefault(f"AC-{n}", []).append(c)
+    tagged = _ac_test_tasks(fd)
+    matrix = []
+    for a in acs:
+        tests = by_ac.get(a["id"], [])
+        if a["level"] == "manual":
+            outcome = "manual"
+        elif a["level"] in ("command", "probe"):
+            ev = fd / "evidence" / f"acceptance-r{round}-{a['id']}.txt"
+            first = ev.read_text(errors="replace").splitlines()[0].strip().upper() if ev.exists() and ev.stat().st_size else ""
+            outcome = "pass" if first == "RESULT: PASS" else "fail" if first == "RESULT: FAIL" else "missing"
+        elif any(t["outcome"] == "fail" for t in tests):
+            outcome = "fail"
+        elif any(t["outcome"] == "pass" for t in tests):
+            outcome = "pass"
+        elif a["level"] == "e2e":
+            outcome = "deferred"
+        else:
+            outcome = "missing"
+        matrix.append({"ac": a["id"], "frs": a["frs"], "level": a["level"], "outcome": outcome,
+                       "tasks": len(tagged.get(a["id"], [])),
+                       "tests": [{"name": t["name"][:160], "outcome": t["outcome"]} for t in tests[:10]]})
+    counts = {k: sum(m["outcome"] == k for m in matrix) for k in ("pass", "fail", "missing", "deferred", "manual")}
+    changed = _frozen_changed(fd)
+    # the acceptance run is also the full regression: a failing test outside any AC fails the round
+    regressions = [c["name"][:160] for c in cases if c["outcome"] == "fail" and not _AC_IN_NAME_RE.search(c["name"])]
+    blocking = counts["fail"] + counts["missing"] + len(regressions)
+    result = "STOPPED" if changed else "PASS" if blocking == 0 else "FAIL"
+    _, head = _git("rev-parse", "--short", "HEAD")
+    return _json({"success": True, "result": result, "commit": head.strip() or None, "counts": counts,
+                  "matrix": matrix, "regressions": regressions[:30], "regression_count": len(regressions),
+                  "frozen_changed": changed, "result_files": [str(f) for f in files], "test_cases": len(cases),
+                  "note": "PASS = no automated AC failing or missing and no regression; deferred e2e and manual ACs go to the final review"})
+
+
+# Added lines matching these are reported by diff_scan. Kept to high-signal patterns: every
+# hit is something a reviewer must look at, not a style opinion.
+_SCAN_LINE_PATTERNS = [
+    ("conflict-marker", "error", re.compile(r"^(<{7}|>{7}|={7})( |$)")),
+    ("private-key", "error", re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----")),
+    ("secret-assignment", "warning", re.compile(r"(?i)\b(password|pwd|secret|api[_-]?key|accountkey|client[_-]?secret)\s*[=:]\s*['\"]?[^\s'\";{}<>$]{8,}")),
+    ("aws-access-key", "error", re.compile(r"\bAKIA[0-9A-Z]{16}\b")),
+    ("focused-test", "error", re.compile(r"\b(fdescribe|fit|describe\.only|it\.only|test\.only)\s*\(")),
+    ("debugger", "warning", re.compile(r"^\s*debugger;?\s*$")),
+    ("todo", "warning", re.compile(r"\b(TODO|FIXME|HACK|XXX)\b")),
+]
+_SCAN_FORBIDDEN_FILES = re.compile(r"(?i)\.(pfx|p12|pem|key|keystore|jks|bacpac)$|(^|/)\.env(\.[^/]*)?$")
+_SCAN_LARGE_BYTES = 1_000_000
+
+
+@mcp.tool(name="diff_scan")
+def diff_scan(feature: str, base: str = None) -> str:
+    """Mechanical merge-readiness scan of the branch diff (merge-base(base, HEAD)..HEAD,
+    code outside specs/ only): merge conflicts against base, conflict markers, secrets and
+    private keys, focused tests, debugger statements, new TODO/FIXME, forbidden files
+    (.pfx/.pem/.bacpac/.env…), files over 1 MB, and changed files that tasks.md/plan.md never
+    name (unplanned changes). Read-only. The final review saves this output as evidence.
+
+    Args:
+        feature: Feature ID
+        base: Base branch (default: branch_source from specs/git-conventions.md, else main)
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    base = base or _conventions().get("branch_source") or "main"
+    if "/" not in base and _git("rev-parse", "--verify", "--quiet", f"origin/{base}")[0] == 0:
+        base = f"origin/{base}"  # the remote-tracking branch is what the PR merges into; a local one goes stale
+    rc, mb = _git("merge-base", base, "HEAD")
+    if rc != 0:
+        return _json({"error": f"cannot find merge-base of '{base}' and HEAD — fetch the base branch or pass base="})
+    mb = mb.strip()
+    findings = []
+
+    rc, out = _git("merge-tree", "--write-tree", "--name-only", "--no-messages", base, "HEAD")
+    if rc == 1:
+        conflicted = [l for l in out.splitlines()[1:] if l.strip()]
+        findings.append({"check": "merge-conflict", "severity": "error", "file": None,
+                         "msg": f"merging into {base} conflicts in {len(conflicted)} file(s): {conflicted[:10]}"})
+    elif rc not in (0, 1):
+        findings.append({"check": "merge-conflict", "severity": "warning", "file": None,
+                         "msg": "git merge-tree --write-tree unavailable (git < 2.38) — check conflicts by hand"})
+
+    _, names = _git("diff", "--name-status", "--no-renames", f"{mb}..HEAD", "--", ".", ":(exclude)specs")
+    changed = []
+    for line in names.splitlines():
+        parts = line.split("\t")
+        if len(parts) == 2:
+            changed.append((parts[0], parts[1]))
+    for status, path in changed:
+        if status == "D":
+            continue
+        if _SCAN_FORBIDDEN_FILES.search(path):
+            findings.append({"check": "forbidden-file", "severity": "error", "file": path, "msg": "certificate/key/backup/env file in the diff"})
+        try:
+            if Path(path).stat().st_size > _SCAN_LARGE_BYTES:
+                findings.append({"check": "large-file", "severity": "warning", "file": path, "msg": f"{Path(path).stat().st_size // 1024} KB"})
+        except OSError:
+            pass
+
+    _, diff = _git("diff", "-U0", "--no-color", f"{mb}..HEAD", "--", ".", ":(exclude)specs")
+    current, lineno = None, 0
+    for line in diff.splitlines():
+        if line.startswith("+++ "):
+            current = line[6:] if line.startswith("+++ b/") else None
+            continue
+        if line.startswith("@@"):
+            m = re.search(r"\+(\d+)", line)
+            lineno = int(m.group(1)) if m else 0
+            continue
+        if line.startswith("+") and current:
+            text = line[1:]
+            for check, sev, rx in _SCAN_LINE_PATTERNS:
+                if rx.search(text):
+                    findings.append({"check": check, "severity": sev, "file": f"{current}:{lineno}", "msg": text.strip()[:120]})
+            lineno += 1
+
+    fd = _feature_dir(feature)
+    planned_text = "".join((fd / a).read_text(errors="replace") for a in ("tasks.md", "plan.md", "spec.md") if (fd / a).exists())
+    unplanned = [p for st, p in changed if st != "D" and p not in planned_text and Path(p).name not in planned_text]
+    if unplanned:
+        findings.append({"check": "unplanned-change", "severity": "info", "file": None,
+                         "msg": f"{len(unplanned)} changed file(s) not named in spec/plan/tasks — confirm each is in scope",
+                         "files": unplanned[:50]})
+
+    errors = sum(f["severity"] == "error" for f in findings)
+    return _json({"success": errors == 0, "base": base, "merge_base": mb[:12], "files_changed": len(changed),
+                  "errors": errors, "warnings": sum(f["severity"] == "warning" for f in findings),
+                  "findings": findings, "scanned_at": _now()})
+
+
+@mcp.tool(name="timestamp")
+def timestamp() -> str:
+    """The real current UTC time (ISO 8601, seconds). Use it for every history entry,
+    evidence file header and date field — never type a timestamp from memory.
+    """
+    return _json({"utc": _now()})
+
+
+
+@mcp.tool(name="append_history")
+def append_history(feature: str, phase: str, skill: str, agent: str, artifacts: str = "none",
+                   tests: str = "none", evidence: str = "none — unverified", commit: str = "n/a",
+                   note: str = "-") -> str:
+    """Append one fixed-field entry to specs//history.md with the REAL UTC time.
+    The entry is the record, not the story: note ≤ 25 words, whole entry ≤ 60 words.
+
+    Args:
+        feature: Feature ID
+        phase: Phase label (e.g. 'Phase 2', 'Phase 4 — Core', 'BF-014', 'Regression', 'Phase 6')
+        skill: The skill that completed (e.g. spec-kit-plan)
+        agent: hermes | claude |  — read later as Implemented-by
+        artifacts: Comma-separated files created or modified
+        tests: ' → N passed, M failed' or 'none'
+        evidence: 'output:…; probe:…; ci:…; review:…' or 'none — unverified'
+        commit: The commit message that follows this entry
+        note: ≤ 25 words — the one fact a reader needs
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    if len(note.split()) > 25:
+        return _json({"error": f"note has {len(note.split())} words — max 25; narrative belongs in implementation-summary.md"})
+    body = (f"- Artifacts: {artifacts or 'none'}\n- Tests: {tests or 'none'}\n- Evidence: {evidence or 'none — unverified'}\n"
+            f"- Commit: {commit or 'n/a'}\n- Note: {note or '-'}\n")
+    words = len(body.split())
+    if words > 60:
+        return _json({"error": f"entry body has {words} words — max 60; shorten artifacts/tests/evidence/note"})
+    ts = _now()
+    hist = _feature_dir(feature) / "history.md"
+    if not hist.exists():
+        hist.write_text(f"# Process History: {feature}\n")
+    with hist.open("a", encoding="utf-8") as fh:
+        fh.write(f"\n## {ts} | {phase} | {skill} | {agent}\n{body}")
+    return _json({"success": True, "timestamp": ts, "file": str(hist), "words": words})
+
+
+@mcp.tool(name="history_guard")
+def history_guard(feature: str, phase: str) -> str:
+    """Pre-commit guard: is there a history.md entry mentioning `phase` that is newer than
+    the last commit touching specs//? Returns ok=false with the reason otherwise.
+
+    Args:
+        feature: Feature ID
+        phase: Text that must appear in the entry header (e.g. 'Phase 2', 'BF-014', 'Regression')
+    """
+    state = _derive(feature)
+    if state is None:
+        return _not_found(feature)
+    if not state["history"]["on"]:
+        return _json({"ok": True, "history": "off", "source": state["history"]["source"], "note": "no entry required; the close builds the timeline from git"})
+    hist = _feature_dir(feature) / "history.md"
+    if not hist.exists():
+        return _json({"ok": False, "reason": "history.md missing"})
+    entries = [(m.group(1), m.group(2)) for m in _HISTORY_ENTRY_RE.finditer(hist.read_text(errors="replace"))]
+    matching = [(ts, hdr) for ts, hdr in entries if phase.lower() in hdr.lower()]
+    if not matching:
+        return _json({"ok": False, "reason": f"no history entry mentions '{phase}'", "entries": len(entries)})
+    try:
+        last_commit = subprocess.run(["git", "log", "-1", "--format=%cI", "--", str(_feature_dir(feature))],
+                                     capture_output=True, text=True, check=False).stdout.strip()
+    except OSError:
+        last_commit = ""
+    newest_ts = max(ts for ts, _ in matching)
+    if last_commit:
+        try:
+            lc = datetime.datetime.fromisoformat(last_commit.replace("Z", "+00:00"))
+            et = datetime.datetime.fromisoformat(newest_ts.replace("Z", "+00:00"))
+            if et.tzinfo is None:
+                et = et.replace(tzinfo=datetime.timezone.utc)
+            if et < lc:
+                return _json({"ok": False, "reason": f"newest '{phase}' entry ({newest_ts}) predates the last commit ({last_commit}) — append a new entry",
+                              "matching_entries": len(matching)})
+        except ValueError:
+            pass
+    return _json({"ok": True, "matching_entries": len(matching), "newest": newest_ts, "last_commit": last_commit or None})
+
+
+# ── Entry point ────────────────────────────────────────────────────────────
+
+if __name__ == "__main__":
+    mcp.run(transport="stdio")
diff --git a/spec-kit-mcp-server/test_server.py b/spec-kit-mcp-server/test_server.py
new file mode 100644
index 0000000..b63d447
--- /dev/null
+++ b/spec-kit-mcp-server/test_server.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+"""Run all MCP server integration tests.
+
+Usage:
+    python3 spec-kit-mcp-server/test_server.py
+    python3 spec-kit-mcp-server/test_workflow.py
+"""
+import subprocess, sys, os
+script = os.path.join(os.path.dirname(__file__), "test_workflow.py")
+sys.exit(subprocess.call([sys.executable, script] + sys.argv[1:]))
diff --git a/spec-kit-mcp-server/test_skills.py b/spec-kit-mcp-server/test_skills.py
new file mode 100644
index 0000000..47cead4
--- /dev/null
+++ b/spec-kit-mcp-server/test_skills.py
@@ -0,0 +1,503 @@
+#!/usr/bin/env python3
+"""Validate all spec-kit skill files for consistency and correctness.
+
+Tests:
+  1. Every skill has valid YAML frontmatter with required fields
+  2. All 7 phases (0-6) have corresponding skills
+  3. Every `spec-kit/references/*` reference in skill content points to an existing file
+  4. Every template reference points to an existing template
+  5. All cross-skill references point to existing skills
+  6. Skills follow correct naming convention
+  7. Each skill lists correct trigger phrases
+  8. Every phase skill (except workflow) references preflight.md
+  9. Phase numbers in skills match expected phases
+ 10. No orphan references and no missing phases
+"""
+
+import re, sys, yaml, json
+from pathlib import Path
+
+REPO = Path(__file__).resolve().parent.parent
+SKILLS_DIR = REPO / "src" / "skills"
+REFERENCES_DIR = REPO / "src" / "references"
+TEMPLATES_DIR = REPO / "src" / "templates"
+
+failures = 0
+
+def check(label, ok, detail=""):
+    global failures
+    if ok:
+        print(f"  ✓ {label}")
+    else:
+        print(f"  ✗ {label}  {detail}")
+        failures += 1
+
+# ── Expected skill inventory ──────────────────────────────────────────────
+
+# Phase -> skill name, expected phase number
+PHASE_SKILLS = {
+    0:   "spec-kit-constitution",
+    1:   "spec-kit-specify",
+    1.5: "spec-kit-clarify",
+    2:   "spec-kit-plan",
+    3:   "spec-kit-tasks",
+    3.5: "spec-kit-review",
+    4:   "spec-kit-implement",
+    5:   "spec-kit-test",
+    6:   "spec-kit-summarize",
+}
+
+NON_PHASE_SKILLS = {"spec-kit-refresh", "spec-kit-workflow", "spec-kit-epic", "spec-kit-design"}
+UMBRELLA_DIR = "spec-kit"  # umbrella SKILL.md inside spec-kit/ directory
+ALL_SKILLS = set(PHASE_SKILLS.values()) | NON_PHASE_SKILLS | {UMBRELLA_DIR}
+
+EXPECTED_TEMPLATES = {
+    "AGENTS-template.md",
+    "acceptance-template.md",
+    "adr-template.md",
+    "merge-checklist-template.md",
+    "review-final-template.md",
+    "bugs-template.md",
+    "close-template.md",
+    "constitution-template.md",
+    "data-model-template.md",
+    "decisions-template.md",
+    "git-conventions-template.md",
+    "gitignore-template.md",
+    "change-record-template.md",
+    "design-doc-template.md",
+    "epic-template.md",
+    "epics-index-template.md",
+    "epic-plan-template.md",
+    "epic-features-template.md",
+    "epic-review-template.md",
+    "history-template.md",
+    "plan-template.md",
+    "research-template.md",
+    "spec-template.md",
+    "tasks-template.md",
+}
+
+EXPECTED_REFERENCES = {
+    "acceptance.md",
+    "commits.md",
+    "constitution-principles.md",
+    "constitution-tables.md",
+    "evidence.md",
+    "history-tracking.md",
+    "preflight.md",
+    "sizing.md",
+}
+
+# Skills whose one-screen SKILL.md is the whole procedure (no references/skills/ file).
+SELF_CONTAINED_SKILLS = {"spec-kit-clarify", "spec-kit-refresh", "spec-kit-epic", "spec-kit-design"}
+
+# ── Helpers ────────────────────────────────────────────────────────────────
+
+def parse_frontmatter(path):
+    """Parse YAML frontmatter from a markdown file."""
+    content = path.read_text()
+    m = re.match(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
+    if not m:
+        return None, content
+    try:
+        return yaml.safe_load(m.group(1)), content
+    except yaml.YAMLError:
+        return None, content
+
+
+def collect_skill_names():
+    """Return set of all skill names (both flat .md files and umbrella dirs)."""
+    names = set()
+    for p in SKILLS_DIR.rglob("SKILL.md"):
+        # umbrella: spec-kit/SKILL.md -> spec-kit
+        names.add(p.parent.name)
+    for p in SKILLS_DIR.glob("spec-kit-*.md"):
+        names.add(p.stem)
+    return names
+
+
+def collect_refs_in_text(text):
+    """Find all `spec-kit/references/*` references in text (placeholders like .md skipped)."""
+    return {r for r in re.findall(r'`(?:spec-kit/)?references/([^`]+)`', text) if '<' not in r}
+
+
+def collect_templates_in_text(text):
+    """Find all `spec-kit/templates/*` references in text."""
+    # Exclude placeholder patterns like .md
+    refs = set()
+    for m in re.finditer(r'`(?:spec-kit/)?templates/([^`]+)`', text):
+        name = m.group(1)
+        if '<' not in name and '>' not in name:  # skip placeholders like .md
+            refs.add(name)
+    return refs
+
+
+def collect_skill_refs_in_text(text):
+    """Find all `spec-kit-*` skill references in text."""
+    refs = set()
+    for m in re.finditer(r'`(spec-kit-[a-z-]+)`', text):
+        refs.add(m.group(1))
+    return refs
+
+
+# ── Tests ──────────────────────────────────────────────────────────────────
+
+
+def test_all_skills_present():
+    """Every expected skill has a file."""
+    print("\n═══ Skill inventory ═══")
+    existing = collect_skill_names()
+
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        check(f"skill exists: {name}", path.exists(), f"missing: {path}")
+
+    # No unexpected skills
+    expected_files = set()
+    for name in ALL_SKILLS:
+        if name == UMBRELLA_DIR:
+            expected_files.add(name)
+        else:
+            expected_files.add(f"{name}.md")
+    unexpected = set()
+    for p in SKILLS_DIR.glob("spec-kit-*.md"):
+        if p.stem not in ALL_SKILLS:
+            unexpected.add(p.stem)
+    # Also check for unexpected umbrella dirs
+    for d in SKILLS_DIR.iterdir():
+        if d.is_dir() and (d / "SKILL.md").exists() and d.name not in ALL_SKILLS:
+            unexpected.add(d.name)
+    check("no unexpected skills", len(unexpected) == 0, f"unexpected: {unexpected}")
+
+
+def test_frontmatter():
+    """Every skill file has valid YAML frontmatter with required fields."""
+    print("\n═══ Frontmatter validation ═══")
+    required = {"name", "description"}
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+
+        fm, _ = parse_frontmatter(path)
+        check(f"{name}: frontmatter parses", fm is not None)
+        if fm:
+            for field in required:
+                check(f"{name}: has field '{field}'", field in fm, f"missing: {field}")
+            check(f"{name}: has description", bool(fm.get("description", "").strip()))
+
+
+def test_phase_coverage():
+    """All 7 phases have a skill, and phase numbers match."""
+    print("\n═══ Phase coverage ═══")
+    for phase, name in sorted(PHASE_SKILLS.items()):
+        path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            check(f"phase {phase} ({name}): file missing", False)
+            continue
+        fm, content = parse_frontmatter(path)
+        if not fm:
+            continue
+
+        # Check phase mention in content
+        phase_refs = re.findall(r'\*\*Phase\*\*:?\s*([0-9.]+)', content)
+        phase_match = False
+        for pr in phase_refs:
+            expected = str(phase).rstrip('0').rstrip('.')
+            actual = str(pr).rstrip('0').rstrip('.')
+            if actual == expected:
+                phase_match = True
+        check(f"phase {phase} ({name}): mentions correct phase", phase_match,
+              f"expected Phase {phase}, found: {phase_refs}")
+
+
+def test_reference_files_exist():
+    """Every reference mentioned in skill content exists in references/."""
+    print("\n═══ Reference files ═══")
+    existing_refs = {str(p.relative_to(REFERENCES_DIR)) for p in REFERENCES_DIR.rglob("*.md")}
+
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        _, content = parse_frontmatter(path)
+        if content is None:
+            continue
+        refs = collect_refs_in_text(content)
+        for ref in refs:
+            check(f"{name}: reference '{ref}' exists", ref in existing_refs,
+                  f"not found in references/ ({ref})")
+
+
+def test_templates_exist():
+    """Every template mentioned in skill content exists in templates/."""
+    print("\n═══ Template files ═══")
+    existing_templates = {p.name for p in TEMPLATES_DIR.glob("*.md")}
+    check("all expected templates present",
+          existing_templates == EXPECTED_TEMPLATES,
+          f"missing: {EXPECTED_TEMPLATES - existing_templates}, "
+          f"extra: {existing_templates - EXPECTED_TEMPLATES}")
+
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        _, content = parse_frontmatter(path)
+        if content is None:
+            continue
+        refs = collect_templates_in_text(content)
+        for ref in refs:
+            check(f"{name}: template '{ref}' exists", ref in existing_templates,
+                  f"not found in templates/ ({ref})")
+
+
+def test_cross_skill_references_exist():
+    """Every cross-skill reference points to an existing skill."""
+    print("\n═══ Cross-skill references ═══")
+    existing = collect_skill_names()
+
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        _, content = parse_frontmatter(path)
+        if content is None:
+            continue
+        refs = collect_skill_refs_in_text(content)
+        for ref in refs:
+            check(f"{name}: references '{ref}'", ref in existing,
+                  f"not an existing skill")
+
+
+def test_preflight_reference():
+    """Every phase skill references preflight.md for its pre-action checks."""
+    print("\n═══ Pre-flight reference ═══")
+    skip = {"spec-kit-workflow", "spec-kit-refresh", "spec-kit-review", "spec-kit-epic", "spec-kit-design", UMBRELLA_DIR}
+    for name in sorted(ALL_SKILLS):
+        if name in skip:
+            continue
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        _, content = parse_frontmatter(path)
+        if content is None:
+            continue
+        has_preflight = "spec-kit/references/preflight.md" in content or "references/preflight.md" in content
+        check(f"{name}: references preflight.md", has_preflight)
+
+
+def test_trigger_descriptions():
+    """Skill description mentions correct trigger phrases."""
+    print("\n═══ Trigger descriptions ═══")
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        fm, _ = parse_frontmatter(path)
+        if not fm:
+            continue
+        desc = fm.get("description", "")
+        # Each skill should mention its own name in the trigger description
+        if name.startswith("spec-kit-"):
+            short_name = name.replace("spec-kit-", "")
+            # Workflow is a router, not a direct-trigger skill
+            if short_name == "workflow":
+                continue
+            check(f"{name}: mentions 'speckit {short_name}' in triggers",
+                  f"speckit {short_name}" in desc.lower())
+
+
+def test_umbrella_coverage():
+    """Umbrella SKILL.md mentions all phase skills."""
+    print("\n═══ Umbrella coverage ═══")
+    path = SKILLS_DIR / UMBRELLA_DIR / "SKILL.md"
+    if not path.exists():
+        check("umbrella SKILL.md exists", False)
+        return
+    content = path.read_text()
+    for phase, name in sorted(PHASE_SKILLS.items()):
+        check(f"umbrella references phase {phase} ({name})", name in content,
+              f"missing reference to {name}")
+    for name in NON_PHASE_SKILLS:
+        check(f"umbrella references {name}", name in content,
+              f"missing reference to {name}")
+
+
+def test_no_loose_reference_files():
+    """No extra/missing files in references/ (top level); references/skills/ mirrors the skill set."""
+    print("\n═══ Reference inventory ═══")
+    existing = {p.name for p in REFERENCES_DIR.glob("*.md")}
+    check("no unexpected reference files", existing == EXPECTED_REFERENCES,
+          f"extra: {existing - EXPECTED_REFERENCES}, "
+          f"missing: {EXPECTED_REFERENCES - existing}")
+    full = {p.stem for p in (REFERENCES_DIR / "skills").glob("spec-kit-*.md")}
+    expected_full = ALL_SKILLS - {UMBRELLA_DIR} - SELF_CONTAINED_SKILLS
+    check("references/skills/ has one full procedure per non-self-contained skill", full == expected_full,
+          f"extra: {full - expected_full}, missing: {expected_full - full}")
+    for name in sorted(ALL_SKILLS - {UMBRELLA_DIR}):
+        skill_text = (SKILLS_DIR / f"{name}.md").read_text()
+        if name in expected_full:
+            check(f"{name}: SKILL.md points at its full procedure", f"spec-kit/references/skills/{name}.md" in skill_text)
+        lines = skill_text.count("\n")
+        check(f"{name}: SKILL.md is one screen (<= 60 lines)", lines <= 60, f"{lines} lines")
+    budget = sum(p.stat().st_size for p in SKILLS_DIR.rglob("*.md")) + sum(p.stat().st_size for p in REFERENCES_DIR.rglob("*.md")) + sum(p.stat().st_size for p in TEMPLATES_DIR.glob("*.md"))
+    check("skills + references + templates stay under ~62k tokens (250 KB)", budget <= 250_000, f"{budget // 1024} KB")
+
+
+def test_workflow_diagram_phases():
+    """Workflow skill mentions all phase numbers in its diagram."""
+    print("\n═══ Workflow diagram phases ═══")
+    path = SKILLS_DIR / "spec-kit-workflow.md"
+    if not path.exists():
+        return
+    content = path.read_text()
+    for phase, name in sorted(PHASE_SKILLS.items()):
+        check(f"workflow mentions phase {phase} ({name})", name.replace("spec-kit-", "") in content,
+              f"missing phase {name} in workflow")
+
+
+def _server_tool_names():
+    """Extract @mcp.tool(name=...) names from server.py via regex (no mcp import needed)."""
+    server = REPO / "spec-kit-mcp-server" / "server.py"
+    if not server.exists():
+        return None
+    return set(re.findall(r'@mcp\.tool\(name="([^"]+)"\)', server.read_text()))
+
+
+def test_mcp_tool_names_match_server():
+    """Every mcp_spec_kit_* tool named in a skill/doc must exist in server.py — and vice versa.
+
+    Guards against skill files referencing removed/renamed tools (happened with
+    log_bug after adc6b79) and against the server gaining tools the docs never
+    mention. The known-removed tools are asserted absent everywhere.
+    """
+    print("\n═══ MCP tool-name drift ═══")
+    server_tools = _server_tool_names()
+    if server_tools is None:
+        check("server.py found", False, "spec-kit-mcp-server/server.py missing")
+        return
+
+    REMOVED_TOOLS = {"log_bug", "set_bug_status", "set_bug_plan_ref"}
+
+    # 1. Removed tools must not exist in the server
+    for t in sorted(REMOVED_TOOLS):
+        check(f"server has no '{t}' tool (removed)", t not in server_tools)
+
+    # 2. Every mcp_spec_kit_* mention in skills/ + docs maps to a real server tool
+    doc_dirs = [
+        SKILLS_DIR,
+        REPO / "spec-kit-mcp-server",   # README.md, *.py docstrings excluded below
+    ]
+    doc_files = []
+    for d in doc_dirs:
+        doc_files.extend(d.rglob("*.md"))
+    doc_files.extend([REPO / "README.md", REPO / "AGENT.md", REPO / "user-guide.md"])
+
+    pattern = re.compile(r'mcp_spec_kit_([a-z_]+)')
+    bad = []
+    for f in doc_files:
+        content = f.read_text()
+        for m in pattern.finditer(content):
+            tool = m.group(1)
+            if tool not in server_tools:
+                bad.append(f"{f.relative_to(REPO)}: mcp_spec_kit_{tool}")
+    check("all mcp_spec_kit_* doc mentions exist in server", not bad,
+          "; ".join(bad[:8]))
+
+    # 3. Every server tool is mentioned somewhere in the docs
+    mentioned = set()
+    for f in doc_files:
+        mentioned.update(pattern.findall(f.read_text()))
+    unmentioned = server_tools - mentioned
+    check("every server tool is documented", not unmentioned,
+          f"undocumented tools: {sorted(unmentioned)}")
+
+
+def test_skills_yaml_parse():
+    """All frontmatter YAML parses correctly (no syntax errors)."""
+    print("\n═══ YAML parse check ═══")
+    for name in sorted(ALL_SKILLS):
+        if name == UMBRELLA_DIR:
+            path = SKILLS_DIR / name / "SKILL.md"
+        else:
+            path = SKILLS_DIR / f"{name}.md"
+        if not path.exists():
+            continue
+        content = path.read_text()
+        # Extract all frontmatter blocks
+        blocks = re.findall(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
+        for i, block in enumerate(blocks):
+            try:
+                parsed = yaml.safe_load(block)
+                check(f"{name}: YAML block {i} parses", parsed is not None or block.strip() == "")
+            except yaml.YAMLError as e:
+                check(f"{name}: YAML block {i} valid", False, str(e))
+
+
+# ── Main ───────────────────────────────────────────────────────────────────
+
+
+def main():
+    print("═" * 55)
+    print("  spec-kit Skills — Validation Tests")
+    print("═" * 55)
+
+    tests = [
+        test_all_skills_present,
+        test_frontmatter,
+        test_skills_yaml_parse,
+        test_phase_coverage,
+        test_trigger_descriptions,
+        test_reference_files_exist,
+        test_templates_exist,
+        test_cross_skill_references_exist,
+        test_preflight_reference,
+        test_umbrella_coverage,
+        test_no_loose_reference_files,
+        test_workflow_diagram_phases,
+        test_mcp_tool_names_match_server,
+    ]
+
+    for t in tests:
+        try:
+            t()
+        except Exception as e:
+            print(f"  ✗ {t.__name__} crashed: {e}")
+            import traceback
+            traceback.print_exc()
+            global failures
+            failures += 1
+
+    print(f"\n{'═' * 55}")
+    if failures:
+        print(f"  FAILURES: {failures} check(s) failed")
+    else:
+        print(f"  All checks passed!")
+    print(f"{'═' * 55}")
+    return 0 if failures == 0 else 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/spec-kit-mcp-server/test_workflow.py b/spec-kit-mcp-server/test_workflow.py
new file mode 100644
index 0000000..bf45563
--- /dev/null
+++ b/spec-kit-mcp-server/test_workflow.py
@@ -0,0 +1,572 @@
+#!/usr/bin/env python3
+"""Workflow integration tests for the derive-and-enforce MCP server.
+
+Every test runs in a fresh temporary project directory with real files under
+specs// — the server derives state from them and persists nothing.
+
+Run:  python3 spec-kit-mcp-server/test_workflow.py
+"""
+
+import anyio, json, os, sys, tempfile, shutil, subprocess
+from pathlib import Path
+
+from mcp import StdioServerParameters
+from mcp.client.stdio import stdio_client
+from mcp.client.session import ClientSession
+
+SERVER_SCRIPT = Path(__file__).resolve().parent / "server.py"
+failures = 0
+
+
+def check(label, ok, detail=""):
+    global failures
+    if ok:
+        print(f"  ✓ {label}")
+    else:
+        print(f"  ✗ {label}  {detail}")
+        failures += 1
+
+
+async def call(s, tool, args=None):
+    r = await s.call_tool(tool, args or {})
+    return json.loads(r.content[0].text)
+
+
+FINAL = """
+## Round {n} — 2026-10-26 — review:hermes
+
+**Verdict**: {v}
+**Reviewed-commit**: {c}
+"""
+
+
+def git(root, *args):
+    subprocess.run(["git", "-c", "user.email=t@t", "-c", "user.name=t", *args], cwd=root, check=True,
+                   capture_output=True)
+
+
+def write(root, feature, name, text="# x\n"):
+    p = Path(root) / "specs" / feature / name
+    p.parent.mkdir(parents=True, exist_ok=True)
+    p.write_text(text)
+
+
+BUGS = """# Bug Report
+
+## Bug Log
+
+### BUG-001: first
+- **Status**: {s1}
+- **Evidence**: {e1}
+- **Verified-by**: {v1}
+
+### BUG-002: second
+- **Status**: {s2}
+- **Evidence**: [output:/probe: files]
+- **Verified-by**: [user / ci: / review:]
+
+---
+
+## Summary
+
+| Bug ID | Severity | Area | Status | Needs Clarification |
+|--------|----------|------|--------|---------------------|
+| BUG-001 | minor | x | {s1} | no |
+| BUG-002 | minor | x | {s2} | no |
+
+**Total Bugs**: 2
+"""
+
+TASKS = """# Tasks
+- [{a}] T001 first task — src/a.py
+- [{b}] T002 second task — src/b.py
+- [ ] BF-001 fix — src/c.py
+"""
+
+
+# ── Tests ──────────────────────────────────────────────────────────────────
+
+
+async def test_derivation(s, root):
+    print("\n═══ Phase derivation from files ═══")
+    d = await call(s, "get_feature_state", {"feature": "nope"})
+    check("missing feature → error", "error" in d)
+
+    d = await call(s, "init_feature", {"feature": "f1", "name": "Feature one"})
+    check("init_feature creates the directory (no history.md: default large)", d["success"] and (Path(root) / "specs/f1").is_dir() and not (Path(root) / "specs/f1/history.md").exists())
+    check("  new feature is phase 1 / new", d["state"]["current_phase"] == 1 and d["state"]["status"] == "new")
+    d = await call(s, "init_feature", {"feature": "f1"})
+    check("duplicate init → already exists", "already exists" in d.get("error", ""))
+
+    write(root, "f1", "spec.md");                      d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("spec.md → phase 2 (plan)", d["state"]["current_phase"] == 2)
+    write(root, "f1", "plan.md");                      d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("plan.md → phase 3 (tasks)", d["state"]["current_phase"] == 3)
+    write(root, "f1", "tasks.md", TASKS.format(a=" ", b=" ")); d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("tasks.md pending → phase 4 (implement)", d["state"]["current_phase"] == 4)
+    check("  task counts derived", d["state"]["tasks"] == {"total": 3, "done": 0, "bugfix": 1})
+    check("  phase card present (10 lines)", d["phase_card"].count("\n") == 9 and "PHASE CARD" in d["phase_card"])
+    write(root, "f1", "bugs.md", BUGS.format(s1="open", e1="x", v1="x", s2="claimed")); d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("bugs.md → phase 5 (test)", d["state"]["current_phase"] == 5)
+    check("  bug counts: 1 open, 1 claimed", d["state"]["bugs"]["open"] == 1 and d["state"]["bugs"]["claimed"] == 1)
+    write(root, "f1", "close.md");                     d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("close.md + open bug → reopened at phase 5", d["state"]["status"] == "reopened" and d["state"]["current_phase"] == 5)
+    write(root, "f1", "bugs.md", BUGS.format(s1="verified", e1="output:e/a.txt", v1="ci:816", s2="superseded")); d = await call(s, "get_feature_state", {"feature": "f1"})
+    check("close.md + no open bugs → closed at phase 6", d["state"]["status"] == "closed" and d["state"]["current_phase"] == 6)
+
+    check("no state file was written", not (Path(root) / "specs/.spec-kit").exists())
+
+
+async def test_advance_validation(s, root):
+    print("\n═══ advance_phase validates, never writes ═══")
+    write(root, "f2", "spec.md")
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 1, "artifacts_created": ["spec.md"]})
+    check("advance 1→2 with spec.md on disk", d["success"] and d["to_phase"] == 2)
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 1, "artifacts_created": ["plan.md"]})
+    check("artifact claimed but not on disk → error", "not on disk" in d.get("error", ""))
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 3})
+    check("wrong from_phase → Phase mismatch", "Phase mismatch" in d.get("error", ""))
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 0})
+    check("phase 0 → project-level error", "project-level" in d.get("error", ""))
+    write(root, "f2", "plan.md"); write(root, "f2", "tasks.md", TASKS.format(a="x", b="x"))
+    write(root, "f2", "bugs.md", BUGS.format(s1="open", e1="x", v1="x", s2="open"))
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 5})
+    check("5→6 blocked by open bugs", "open bugs" in d.get("error", ""))
+    d = await call(s, "get_next_actions", {"feature": "f2"})
+    acts = [a["action"] for a in d["available_actions"]]
+    check("next actions: bugfix offered, close blocked", "bugfix" in acts and any(a.get("blocked") for a in d["available_actions"] if a["action"] == "advance_to_close"))
+    write(root, "f2", "close.md")
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 5})
+    check("reopened feature (close doc + open bugs) still blocked by open bugs", "open bugs" in d.get("error", ""))
+    write(root, "f2", "bugs.md", BUGS.format(s1="verified", e1="output:x", v1="user", s2="superseded"))
+    d = await call(s, "advance_phase", {"feature": "f2", "from_phase": 5})
+    check("closed feature → use reopen", "closed" in d.get("error", ""))
+
+
+async def test_close_and_reopen(s, root):
+    print("\n═══ close_feature / reopen_feature ═══")
+    write(root, "f3", "spec.md"); write(root, "f3", "plan.md"); write(root, "f3", "tasks.md", TASKS.format(a="x", b="x"))
+    d = await call(s, "reopen_feature", {"feature": "f3"})
+    check("reopen non-closed → error", "not closed" in d.get("error", ""))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close without close doc → error", "no close.md" in d.get("error", ""))
+    write(root, "f3", "close.md")
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close without ADR section / final review → error",
+          "Architecture Decisions" in d.get("error", "") and "review-final.md" in d.get("error", ""))
+    write(root, "f3", "close.md", "# Close\n\n## Architecture Decisions\n\nnone met the ADR bar\n")
+    write(root, "f3", "review-final.md", FINAL.format(n=1, v="NOT READY", c="abc1234"))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close with NOT READY verdict → error", "NOT READY" in d.get("error", ""))
+    write(root, "f3", "review-final.md", FINAL.format(n=1, v="NOT READY", c="abc1234") + FINAL.format(n=2, v="AWAITING-OWNER", c="abc1234"))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close with AWAITING-OWNER → error naming the owner", "AWAITING-OWNER" in d.get("error", ""))
+    write(root, "f3", "review-final.md", FINAL.format(n=1, v="NOT READY", c="abc1234") + FINAL.format(n=2, v="READY", c="abc1234"))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close without change-record.md → error", "change-record.md" in d.get("error", ""))
+    write(root, "f3", "change-record.md", "# Change Record\n")
+    write(root, "f3", "bugs.md", BUGS.format(s1="verified", e1="output:x", v1="", s2="claimed"))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("verified without Verified-by → error", "without a Verified-by" in d.get("error", ""))
+    write(root, "f3", "bugs.md", BUGS.format(s1="verified", e1="output:x", v1="review:claude", s2="claimed"))
+    d = await call(s, "close_feature", {"feature": "f3"})
+    check("close ok, claimed bug reported as unverified", d.get("success") and d["claimed_unverified"] == ["BUG-002"])
+    d = await call(s, "reopen_feature", {"feature": "f3"})
+    check("reopen closed feature ok, writes nothing", d.get("success") and "bugs.md" in d["next"])
+    d = await call(s, "list_features")
+    f3 = [f for f in d["features"] if f["feature"] == "f3"][0]
+    check("list_features derives closed/phase 6", f3["status"] == "closed" and f3["phase"] == 6 and f3["claimed_bugs"] == 1)
+
+
+async def test_update_artifact(s, root):
+    print("\n═══ update_artifact checks disk ═══")
+    write(root, "f4", "spec.md")
+    d = await call(s, "update_artifact", {"feature": "f4", "artifact": "spec.md", "status": "present"})
+    check("present + on disk → ok", d.get("success"))
+    d = await call(s, "update_artifact", {"feature": "f4", "artifact": "plan.md", "status": "present"})
+    check("present + missing → error", "not on disk" in d.get("error", ""))
+    d = await call(s, "update_artifact", {"feature": "f4", "artifact": "spec.md", "status": "absent"})
+    check("absent + on disk → error", "exists on disk" in d.get("error", ""))
+
+
+async def test_project_tools(s, root):
+    print("\n═══ project_status / project_set_constitution ═══")
+    d = await call(s, "project_status")
+    check("version 3, constitution absent, no legacy state", d["version"] == 3 and d["constitution"] == "absent" and d["legacy_state_file"] is False)
+    d = await call(s, "project_set_constitution", {"status": "present"})
+    check("set present without file → error", "write the file first" in d.get("error", ""))
+    (Path(root) / "specs/constitution.md").write_text("# C")
+    d = await call(s, "project_set_constitution", {"status": "present", "principles": '{"testing": "A"}'})
+    check("set present with file → ok, principles echoed", d.get("success") and d["principles"]["testing"] == "A")
+    (Path(root) / "specs/.spec-kit").mkdir(); (Path(root) / "specs/.spec-kit/state.json").write_text("{}")
+    d = await call(s, "auto_detect_features")
+    check("auto_detect reports legacy state file", d["legacy_state_file"] is True and d["success"])
+
+
+async def test_next_id_and_lint(s, root):
+    print("\n═══ next_id / lint_artifacts ═══")
+    write(root, "f5", "spec.md"); write(root, "f5", "plan.md")
+    write(root, "f5", "tasks.md", TASKS.format(a="x", b=" "))
+    write(root, "f5", "bugs.md", BUGS.format(s1="resolved", e1="x", v1="x", s2="verified"))
+    d = await call(s, "next_id", {"feature": "f5", "kind": "BUG"})
+    check("next BUG id is BUG-003", d["next_id"] == "BUG-003")
+    d = await call(s, "next_id", {"feature": "f5", "kind": "T"})
+    check("next T id is T003", d["next_id"] == "T003")
+    d = await call(s, "next_id", {"feature": "f5", "kind": "BF"})
+    check("next BF id is BF-002", d["next_id"] == "BF-002")
+    d = await call(s, "next_id", {"feature": "f5", "kind": "X"})
+    check("unknown kind → error", "error" in d)
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("lint flags legacy 'resolved' as warning", any(f["severity"] == "warning" and "resolved" in f["msg"] for f in d["findings"]))
+    check("lint flags verified without Verified-by", "without Verified-by" in msgs)
+    check("lint does not require history.md for size M (default large)", "history.md missing" not in msgs)
+    write(root, "f5", "spec.md", "# Spec\n\n**Size**: L — big\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"}); msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("lint requires history.md for size L", "history.md missing" in msgs)
+    write(root, "f5", "spec.md", "# Spec\n\n**Size**: L — big\n**History**: off\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"}); msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("  spec override History: off → not required", "history.md missing" not in msgs)
+    (Path(root) / "specs/git-conventions.md").write_text("history: always\n")
+    write(root, "f5", "spec.md")
+    d = await call(s, "lint_artifacts", {"feature": "f5"}); msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("  project history: always → required", "history.md missing" in msgs)
+    check("lint result not success (errors present)", d["success"] is False and d["errors"] >= 2)
+    write(root, "f5", "history.md", "# Process History: f5\n")
+    write(root, "f5", "bugs.md", BUGS.format(s1="claimed", e1="output:evidence/BF-001-green.txt", v1="", s2="verified").replace(
+        "- **Verified-by**: [user / ci: / review:]", "- **Verified-by**: user"))
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    check("clean artifacts lint ok", d["success"] is True, json.dumps(d["findings"]))
+    write(root, "f5", "close.md")
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    check("closed feature without Current Design → warning", any("Current Design" in f["msg"] for f in d["findings"]) and d["success"] is True)
+    write(root, "f5", "plan.md", "# plan\n\n## Current Design\n\nbuilt\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    check("  with Current Design → no warning", not any("Current Design" in f["msg"] for f in d["findings"]))
+    write(root, "f5", "tasks.md", "# Tasks\n- [x] T001 [TEST] tests — t.py\n- [x] T002 [SEAM] rates — src/r.py\n- [ ] T003 later — src/l.py\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("[SEAM] done without probe → warning", "T002 [SEAM]" in msgs)
+    check("[TEST] done without red file → warning", "T001 [TEST]" in msgs)
+    write(root, "f5", "spec.md", "# Spec\n\n**Size**: S — tiny\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    check("  size S → RED file still required", "T001 [TEST]" in " | ".join(f["msg"] for f in d["findings"]))
+    write(root, "f5", "spec.md")
+    write(root, "f9", "spec.md"); write(root, "f9", "plan.md")
+    write(root, "f9", "tasks.md", "# Tasks\n- T001 [X] [TEST] t — t.py\n- T002 [ ] code — c.py\n- BF-001 [X] fix — c.py\n")
+    d = await call(s, "get_feature_state", {"feature": "f9"})
+    check("id-first task lines ('- T001 [X] …') are parsed", d["state"]["tasks"] == {"total": 3, "done": 2, "bugfix": 1}, json.dumps(d["state"]["tasks"]))
+    write(root, "f5", "evidence/T002-probe-rates.txt", "cmd\nresult\n")
+    write(root, "f5", "evidence/core-red.txt", "cmd\nFAILED\n")
+    d = await call(s, "lint_artifacts", {"feature": "f5"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("  with probe + red files → no warnings", "[SEAM]" not in msgs and "[TEST]" not in msgs, msgs)
+
+
+async def test_timestamp_and_history_guard(s, root):
+    print("\n═══ timestamp / history_guard ═══")
+    d = await call(s, "timestamp")
+    check("timestamp is UTC ISO", d["utc"].endswith("+00:00") and "T" in d["utc"])
+    write(root, "f6", "spec.md")
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 1"})
+    check("history off (size M, default large) → guard ok with note", d["ok"] is True and d.get("history") == "off")
+    (Path(root) / "specs/git-conventions.md").write_text("history: always\n")
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 1"})
+    check("history on, no history.md → not ok", d["ok"] is False)
+    write(root, "f6", "history.md", "# Process History: f6\n\n## 2020-01-01T00:00:00+00:00 | Phase 1 | spec-kit-specify | claude\n- Artifacts: spec.md\n")
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 2"})
+    check("entry for other phase → not ok", d["ok"] is False and "no history entry" in d["reason"])
+    subprocess.run(["git", "init", "-q"], cwd=root, check=True)
+    subprocess.run(["git", "-c", "user.email=t@t", "-c", "user.name=t", "add", "-A"], cwd=root, check=True)
+    subprocess.run(["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-q", "-m", "init"], cwd=root, check=True)
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 1"})
+    check("entry older than last commit → not ok", d["ok"] is False and "predates" in d["reason"])
+    with open(Path(root) / "specs/f6/history.md", "a") as fh:
+        fh.write("\n## 2999-01-01T00:00:00+00:00 | Phase 1 | spec-kit-specify | claude\n- Artifacts: spec.md\n")
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 1"})
+    check("fresh entry → ok", d["ok"] is True)
+
+    print("\n═══ append_history ═══")
+    d = await call(s, "append_history", {"feature": "f6", "phase": "Phase 2", "skill": "spec-kit-plan", "agent": "claude",
+                                         "artifacts": "plan.md", "commit": "spec(phase-2): f6 plan", "note": "short note"})
+    check("append_history writes a stamped entry", d.get("success") and d["timestamp"].endswith("+00:00"))
+    text = (Path(root) / "specs/f6/history.md").read_text()
+    check("  entry has the fixed fields", "| Phase 2 | spec-kit-plan | claude" in text and "- Evidence: none — unverified" in text)
+    d = await call(s, "history_guard", {"feature": "f6", "phase": "Phase 2"})
+    check("  guard sees the new entry", d["ok"] is True)
+    d = await call(s, "append_history", {"feature": "f6", "phase": "Phase 3", "skill": "s", "agent": "a", "note": " ".join(["w"] * 26)})
+    check("note over 25 words → error", "max 25" in d.get("error", ""))
+    d = await call(s, "append_history", {"feature": "f6", "phase": "Phase 3", "skill": "s", "agent": "a", "artifacts": " ".join(["f"] * 70)})
+    check("entry over 60 words → error", "max 60" in d.get("error", ""))
+
+
+async def test_size_final_review_adr_and_diff_scan(s, root):
+    print("\n═══ size tier / final review gate / next_id ADR / diff_scan ═══")
+    write(root, "f7", "spec.md", "# Spec\n\n**Size**: S\n")
+    d = await call(s, "get_feature_state", {"feature": "f7"})
+    check("size read from spec.md header", d["state"]["size"] == "S" and d["state"]["size_declared"] is True)
+    check("phase card shows the size", "size: S" in d["phase_card"])
+    write(root, "f8", "spec.md")
+    d = await call(s, "get_feature_state", {"feature": "f8"})
+    check("undeclared size → M, flagged", d["state"]["size"] == "M" and "undeclared" in d["phase_card"])
+    d = await call(s, "lint_artifacts", {"feature": "f8"})
+    check("lint warns on missing Size line", any("Size" in f["msg"] for f in d["findings"]))
+
+    # a git repo with a base branch and a feature branch
+    git(root, "init", "-q", "-b", "main")
+    (Path(root) / "src").mkdir()
+    (Path(root) / "src/app.py").write_text("x = 1\n")
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "base")
+    git(root, "checkout", "-q", "-b", "feat/007")
+    write(root, "f7", "plan.md", "# plan\n- src/app.py\n")
+    write(root, "f7", "tasks.md", "# Tasks\n- [x] T001 change — src/app.py\n")
+    (Path(root) / "src/app.py").write_text("x = 2  # TODO tidy\npassword = 'hunter2hunter2'\n")
+    (Path(root) / "src/extra.py").write_text("<<<<<<< HEAD\n")
+    (Path(root) / "cert.pfx").write_text("binary")
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "feat")
+    head = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=root, capture_output=True, text=True).stdout.strip()
+
+    d = await call(s, "diff_scan", {"feature": "f7"})
+    checks = {f["check"] for f in d["findings"]}
+    check("diff_scan finds conflict marker, secret, todo, forbidden file",
+          {"conflict-marker", "secret-assignment", "todo", "forbidden-file"} <= checks, str(checks))
+    unplanned = [f for f in d["findings"] if f["check"] == "unplanned-change"]
+    check("diff_scan lists unplanned files, not planned ones",
+          unplanned and "src/extra.py" in unplanned[0]["files"] and "src/app.py" not in unplanned[0]["files"])
+    check("diff_scan not success with errors", d["success"] is False and d["base"] == "main")
+    d = await call(s, "diff_scan", {"feature": "f7", "base": "nope"})
+    check("diff_scan unknown base → error", "merge-base" in d.get("error", ""))
+
+    d = await call(s, "advance_phase", {"feature": "f7", "from_phase": 5})
+    check("5→6 blocked without a final review", "review-final.md" in d.get("error", ""))
+    d = await call(s, "get_next_actions", {"feature": "f7"})
+    check("next actions offer the final review", any(a["action"] == "final_review" for a in d["available_actions"]))
+    write(root, "f7", "review-final.md", FINAL.format(n=1, v="READY", c=head))
+    d = await call(s, "advance_phase", {"feature": "f7", "from_phase": 5})
+    check("5→6 ok with a fresh READY review", d.get("success"), json.dumps(d))
+    d = await call(s, "get_feature_state", {"feature": "f7"})
+    check("phase card shows the verdict", f"final review: READY @ {head}" in d["phase_card"])
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "spec only")
+    d = await call(s, "advance_phase", {"feature": "f7", "from_phase": 5})
+    check("  a specs/-only commit keeps the review fresh", d.get("success"), json.dumps(d))
+    (Path(root) / "src/app.py").write_text("x = 3\n")
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "code after review")
+    d = await call(s, "advance_phase", {"feature": "f7", "from_phase": 5})
+    check("  a code commit after the review → stale", "re-run the final review" in d.get("error", ""))
+    write(root, "f7", "review-final.md", "# Final review\n\n## Round 1 — x\n\nno verdict\n")
+    d = await call(s, "lint_artifacts", {"feature": "f7"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("lint: round without verdict / commit → errors", "Verdict" in msgs and "Reviewed-commit" in msgs and d["success"] is False)
+
+    d = await call(s, "next_id", {"feature": "f7", "kind": "ADR"})
+    check("next_id ADR without an ADR dir → error", "ADR directory" in d.get("error", ""))
+    (Path(root) / "docs/adr").mkdir(parents=True)
+    (Path(root) / "docs/adr/0001-first.md").write_text("# 0001")
+    (Path(root) / "docs/adr/0014-later.md").write_text("# 0014")
+    d = await call(s, "next_id", {"feature": "f7", "kind": "ADR"})
+    check("next_id ADR → 0015 in docs/adr", d.get("next_id") == "0015" and d["adr_dir"] == "docs/adr")
+    (Path(root) / "specs/git-conventions.md").write_text("adr_dir: records\nbranch_source: main\n\n## Examples\nbranch_source: develop\nadr_dir: elsewhere\n")
+    (Path(root) / "records").mkdir()
+    d = await call(s, "next_id", {"feature": "f7", "kind": "ADR"})
+    check("adr_dir from git-conventions wins", d.get("next_id") == "0001" and d["adr_dir"] == "records")
+    d = await call(s, "diff_scan", {"feature": "f7"})
+    check("branch_source: first occurrence wins over the Examples block", d.get("base") == "main", json.dumps(d)[:200])
+    d = await call(s, "project_status")
+    check("project_status reports adr_dir and merge checklist", d["adr_dir"] == "records" and d["merge_checklist"] == "absent")
+
+
+ACC_SPEC = """# Spec
+
+**Size**: M
+
+- **FR-001**: System MUST save rules
+- **FR-002**: System MUST flag overdue tasks
+- **FR-003**: System MUST export
+
+### User Story 1
+- **AC-001** (FR-001) Given rules, When saved, Then stored — Verify: integration
+- **AC-002** (FR-002) Given a late task, When listed, Then flagged — Verify: unit
+- **AC-003** (FR-001, FR-002) Given the settings page, When saved, Then the grid updates — Verify: e2e (spans SPA + BFF + auth)
+- **AC-004** (FR-002) Given the migration, When applied to an empty DB, Then it succeeds — Verify: command
+- **AC-005** (FR-001) Given the card, When viewed, Then it matches the design — Verify: manual (visual)
+"""
+
+ACC_TASKS = """# Tasks
+- [x] T001 [TEST] [AC-001] rules integration test — tests/RulesTests.cs
+- [x] T002 [TEST] [AC-002] overdue unit test — tests/OverdueTests.cs
+- [x] T003 [TEST] [AC-003] e2e — cypress/e2e/overdue.cy.ts
+- [x] T004 rules handler — src/Rules.cs
+"""
+
+JUNIT = """
+
+  
+  
+
+"""
+
+TRX = """
+
+  
+
+"""
+
+
+async def test_epics_and_design(s, root):
+    print("\n═══ epics / design docs (optional dirs) ═══")
+    for f in ("e1", "e2", "e3"):
+        write(root, f, "spec.md", "# Spec\n\n**Size**: S — x\n**Epic**: rs-m\n")
+        write(root, f, "history.md", "# Process History\n")
+    d = await call(s, "project_status")
+    check("3 specs naming an epic without epics_dir → hint", any("epic 'rs-m'" in h for h in d["hints"]), json.dumps(d["hints"]))
+    d = await call(s, "lint_artifacts", {"feature": "e1"})
+    check("lint: Epic line without epics_dir → warning", any("no epics_dir" in f["msg"] for f in d["findings"]) and d["success"])
+    (Path(root) / "specs/git-conventions.md").write_text("epics_dir: specs/epics\ndesign_dir: docs/design\n")
+    d = await call(s, "lint_artifacts", {"feature": "e1"})
+    check("lint: epic file missing → warning", any("does not exist" in f["msg"] for f in d["findings"]))
+    (Path(root) / "specs/epics/rs-m").mkdir(parents=True); (Path(root) / "specs/epics/rs-m/features.md").write_text("# Features\n| 1 | e2 | S | closed |\n")
+    d = await call(s, "lint_artifacts", {"feature": "e1"})
+    check("lint: epic file without the feature's row → warning", any("no row for e1" in f["msg"] for f in d["findings"]))
+    d = await call(s, "lint_artifacts", {"feature": "e2"})
+    check("  feature with a row → no epic warning", not any("epic" in f["msg"].lower() for f in d["findings"]))
+    write(root, "e2", "plan.md", "# Plan\n\n**Modules**: reader, bff\n")
+    d = await call(s, "lint_artifacts", {"feature": "e2"})
+    check("lint: module without design doc → warning", sum("no docs/design/" in f["msg"] for f in d["findings"]) == 2)
+    d = await call(s, "project_status")
+    check("project_status reports the dirs, no hints once set", d["epics_dir"] == "specs/epics" and d["hints"] == [])
+    (Path(root) / "specs/epics/rs-m/epic.md").write_text("# Epic\n")
+    d = await call(s, "project_status")
+    check("epics_index on (default) + epic without README.md → hint", any("README.md is missing" in h for h in d["hints"]))
+    (Path(root) / "specs/git-conventions.md").write_text("epics_dir: specs/epics\ndesign_dir: docs/design\nepics_index: off\n")
+    d = await call(s, "project_status")
+    check("  epics_index off → no hint", d["hints"] == [])
+    (Path(root) / "specs/git-conventions.md").write_text("epics_dir: specs/epics\ndesign_dir: docs/design\n")
+    (Path(root) / "specs/epics/297-security").mkdir()
+    d = await call(s, "next_id", {"feature": "e1", "kind": "EPIC"})
+    check("next EPIC id scans epics_dir (298 after 297-…)", d.get("next_id") == "298", json.dumps(d))
+
+
+async def test_acceptance(s, root):
+    print("\n═══ acceptance criteria: lint / next_id / freeze / status / gates ═══")
+    git(root, "init", "-q", "-b", "main")
+    write(root, "f10", "history.md", "# Process History: f10\n")
+    write(root, "f10", "spec.md", ACC_SPEC.replace(" — Verify: e2e (spans SPA + BFF + auth)", " — Verify: e2e"))
+    write(root, "f10", "plan.md")
+    write(root, "f10", "tasks.md", ACC_TASKS.replace("- [x] T001 [TEST] [AC-001] rules integration test — tests/RulesTests.cs\n", "- [x] T001 [TEST] [AC-009] stray — tests/RulesTests.cs\n"))
+    d = await call(s, "lint_artifacts", {"feature": "f10"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("lint: e2e without a reason → error", "AC-003: Verify: e2e needs a reason" in msgs, msgs)
+    check("lint: automated AC without a [TEST] task → error", "AC-001 (Verify: integration) has no" in msgs)
+    check("lint: task tagged with an unknown AC → error", "[AC-009] tagged on a task but not defined" in msgs)
+    check("lint: FR without an AC → warning", "FR-003" in msgs)
+    write(root, "f10", "spec.md", ACC_SPEC)
+    write(root, "f10", "tasks.md", ACC_TASKS)
+    d = await call(s, "next_id", {"feature": "f10", "kind": "AC"})
+    check("next_id AC → AC-006", d.get("next_id") == "AC-006")
+
+    d = await call(s, "acceptance_freeze", {"feature": "f10"})
+    check("freeze before the tests exist → error", "write the tests" in d.get("error", ""))
+    for f in ("tests/RulesTests.cs", "tests/OverdueTests.cs"):
+        (Path(root) / f).parent.mkdir(parents=True, exist_ok=True)
+        (Path(root) / f).write_text("// " + f + "\n")
+    d = await call(s, "acceptance_freeze", {"feature": "f10"})
+    check("freeze hashes the AC test files", d.get("success") and d["frozen"] == 2, json.dumps(d))
+    (Path(root) / "cypress/e2e").mkdir(parents=True)
+    (Path(root) / "cypress/e2e/overdue.cy.ts").write_text("it('AC-003')\n")
+    d = await call(s, "acceptance_freeze", {"feature": "f10"})
+    check("  later phase: freeze is additive", d.get("success") and d["added"] == ["cypress/e2e/overdue.cy.ts"] and d["frozen"] == 3)
+
+    (Path(root) / "results").mkdir()
+    (Path(root) / "results/unit.xml").write_text(JUNIT.format(reg=">"))
+    (Path(root) / "results/int.trx").write_text(TRX.format(o="Failed"))
+    d = await call(s, "acceptance_status", {"feature": "f10", "results": "results/*.xml,results/int.trx", "round": 1})
+    m = {r["ac"]: r["outcome"] for r in d["matrix"]}
+    check("status: TRX failure → fail, JUnit pass → pass", m["AC-001"] == "fail" and m["AC-002"] == "pass", json.dumps(m))
+    check("status: e2e not run → deferred, manual → manual, command without evidence → missing",
+          m["AC-003"] == "deferred" and m["AC-005"] == "manual" and m["AC-004"] == "missing")
+    check("status: result FAIL", d["result"] == "FAIL")
+    (Path(root) / "results/int.trx").write_text(TRX.format(o="Passed"))
+    write(root, "f10", "evidence/acceptance-r1-AC-004.txt", "RESULT: PASS\ncmd: dotnet ef database update\n")
+    d = await call(s, "acceptance_status", {"feature": "f10", "results": "results/*.xml,results/int.trx", "round": 1})
+    check("status: all automated pass → PASS", d["result"] == "PASS" and d["counts"]["pass"] == 3, json.dumps(d["counts"]))
+    (Path(root) / "results/unit.xml").write_text(JUNIT.format(reg=">"))
+    d = await call(s, "acceptance_status", {"feature": "f10", "results": "results/*.xml,results/int.trx", "round": 1})
+    check("status: an untagged failing test is a regression → FAIL", d["result"] == "FAIL" and d["regression_count"] == 1)
+    (Path(root) / "results/unit.xml").write_text(JUNIT.format(reg=">"))
+
+    (Path(root) / "tests/OverdueTests.cs").write_text("// weakened\n")
+    d = await call(s, "acceptance_status", {"feature": "f10", "results": "results/*.xml,results/int.trx", "round": 1})
+    check("status: a frozen test changed → STOPPED", d["result"] == "STOPPED" and d["frozen_changed"] == ["tests/OverdueTests.cs"])
+    d = await call(s, "lint_artifacts", {"feature": "f10"})
+    check("lint: frozen test changed → error", any("frozen acceptance tests changed" in f["msg"] for f in d["findings"]))
+    d = await call(s, "acceptance_freeze", {"feature": "f10"})
+    check("freeze refuses a changed file without refreeze", "changed" in d.get("error", ""))
+    d = await call(s, "acceptance_freeze", {"feature": "f10", "refreeze": True})
+    check("  refreeze without a reason → error", "reason" in d.get("error", ""))
+    d = await call(s, "acceptance_freeze", {"feature": "f10", "refreeze": True, "reason": "user: rename of the API, ruling 4"})
+    check("  refreeze with the user's reason → ok", d.get("success") and d["refrozen"] == ["tests/OverdueTests.cs"])
+
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "impl")
+    head = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=root, capture_output=True, text=True).stdout.strip()
+    write(root, "f10", "review-final.md", FINAL.format(n=1, v="READY", c=head))
+    d = await call(s, "advance_phase", {"feature": "f10", "from_phase": 5})
+    check("5→6 blocked without an acceptance round", "acceptance.md" in d.get("error", ""), json.dumps(d))
+    d = await call(s, "get_next_actions", {"feature": "f10"})
+    check("next actions offer 'accept'", any(a["action"] == "accept" for a in d["available_actions"]))
+    check("phase card shows the AC count", "acceptance: 5 ACs · not run" in d["phase_card"])
+    write(root, "f10", "acceptance.md", f"# Acceptance\n\n## Round 1 — x\n\n**Result**: FAIL\n**Commit**: {head}\n")
+    d = await call(s, "advance_phase", {"feature": "f10", "from_phase": 5})
+    check("5→6 blocked by a FAIL round", "every automated AC must pass" in d.get("error", ""))
+    with open(Path(root) / "specs/f10/acceptance.md", "a") as fh:
+        fh.write(f"\n## Round 2 — y\n\n**Result**: PASS\n**Commit**: {head}\n")
+    d = await call(s, "advance_phase", {"feature": "f10", "from_phase": 5})
+    check("5→6 ok with a fresh PASS round + READY review", d.get("success"), json.dumps(d))
+    (Path(root) / "src").mkdir(); (Path(root) / "src/Rules.cs").write_text("// change\n")
+    git(root, "add", "-A"); git(root, "commit", "-q", "-m", "code after acceptance")
+    write(root, "f10", "close.md", "# Close\n\n## Architecture Decisions\n\nnone\n")
+    d = await call(s, "close_feature", {"feature": "f10"})
+    check("close refuses a stale acceptance round", "re-run 'accept" in d.get("error", ""), json.dumps(d))
+    write(root, "f10", "acceptance.md", "# Acceptance\n\n## Round 1 — x\n\nnothing\n")
+    d = await call(s, "lint_artifacts", {"feature": "f10"})
+    msgs = " | ".join(f["msg"] for f in d["findings"])
+    check("lint: acceptance round without Result / Commit → errors", "**Result**" in msgs and "**Commit**" in msgs)
+
+
+# ── Runner ─────────────────────────────────────────────────────────────────
+
+
+async def run_in_tmp(test_fn):
+    root = tempfile.mkdtemp(prefix="spec-kit-test-")
+    try:
+        (Path(root) / "specs").mkdir()
+        params = StdioServerParameters(command=sys.executable, args=[str(SERVER_SCRIPT)], cwd=root)
+        async with stdio_client(params) as (read, write_):
+            async with ClientSession(read, write_) as s:
+                await s.initialize()
+                await test_fn(s, root)
+    finally:
+        shutil.rmtree(root, ignore_errors=True)
+
+
+async def main():
+    print("═" * 55)
+    print("  spec-kit MCP Server — Workflow Integration Tests (v3 derive-only)")
+    print("═" * 55)
+    for t in [test_derivation, test_advance_validation, test_close_and_reopen, test_update_artifact,
+              test_project_tools, test_next_id_and_lint, test_timestamp_and_history_guard,
+              test_size_final_review_adr_and_diff_scan, test_epics_and_design, test_acceptance]:
+        try:
+            await run_in_tmp(t)
+        except Exception as e:
+            print(f"  ✗ {t.__name__} crashed: {e}")
+            import traceback; traceback.print_exc()
+            global failures
+            failures += 1
+    print(f"\n{'═' * 55}")
+    print(f"  FAILURES: {failures} check(s) failed" if failures else "  All tests passed!")
+    print(f"{'═' * 55}")
+    return 0 if failures == 0 else 1
+
+
+if __name__ == "__main__":
+    sys.exit(anyio.run(main))
diff --git a/specs/bug-life/bugs.md b/specs/bug-life/bugs.md
new file mode 100644
index 0000000..6f59bcb
--- /dev/null
+++ b/specs/bug-life/bugs.md
@@ -0,0 +1,4 @@
+# Bugs
+
+### BUG-001: Placeholder
+- **Status**: open
diff --git a/specs/reopen-test/bugs.md b/specs/reopen-test/bugs.md
new file mode 100644
index 0000000..6f59bcb
--- /dev/null
+++ b/specs/reopen-test/bugs.md
@@ -0,0 +1,4 @@
+# Bugs
+
+### BUG-001: Placeholder
+- **Status**: open
diff --git a/src/references/acceptance.md b/src/references/acceptance.md
new file mode 100644
index 0000000..c49acac
--- /dev/null
+++ b/src/references/acceptance.md
@@ -0,0 +1,130 @@
+# Acceptance Criteria and the Acceptance Loop
+
+Acceptance-test-driven development on top of the phase-level TDD: the spec's acceptance
+criteria get ids and a verify level, their tests are ordinary `[TEST]` tasks tagged with
+the id, and after implement an automatic loop runs them, logs failures as bugs, runs the
+bugfix chain and runs them again — until every automated criterion passes or the loop stops.
+
+## 1. Acceptance criteria (spec.md)
+
+```
+- **AC-003** (FR-002) Given a task due 4 days ago and grace 3, When the grid loads, Then it is flagged overdue — Verify: unit
+```
+
+- Ids are `AC-###`, ascending, never renumbered (`next_id kind="AC"`). Every FR is named by at
+  least one AC (`lint_artifacts` warns otherwise). Edge cases that matter are ACs too.
+- One observable outcome per AC, written as Given / When / Then.
+- **Verify** names the LOWEST level that can prove it:
+
+| Level | Proves | Typical harness | Speed |
+|-------|--------|-----------------|-------|
+| `unit` | a rule, a calculation, a validator, a handler with fakes | xUnit / NUnit, Vitest / Jest, pytest | seconds |
+| `integration` | API contract, persistence, migrations applied, auth policy, tenant filter — real DB / HTTP in-process | WebApplicationFactory + Testcontainers, supertest | ~1 min |
+| `component` | UI behaviour of one component/page with its services mocked | Vitest/Jest + Testing Library, Angular TestBed | seconds |
+| `e2e` | a journey that needs the real UI + API + identity + DB together | Cypress, Playwright | minutes, needs the stack |
+| `command` | build / infra / pipeline / config outcome | `terraform plan` no drift, `dotnet ef migrations script`, a pipeline dry-run | varies |
+| `probe` | data or configuration in a real environment (read-only) | a SQL query, an HTTP GET | seconds |
+| `manual` | what no tool can judge (visual fidelity, copy, UX feel) | the user | — |
+
+- `e2e` and `manual` need a reason in parentheses: `Verify: e2e (needs the Keycloak redirect)`.
+  Rule of thumb: ≤ 2 e2e ACs per feature; prefer an integration test of the API plus a component
+  test of the UI over one e2e test of both.
+
+## 2. Plan: the acceptance test strategy
+
+`plan.md` → `## Acceptance Test Strategy`: one row per AC — level, harness, test file, the
+environment it needs (none / Testcontainers / the running stack) and how its result is
+produced (JUnit XML / TRX path, or the command). The plan decides where each test lives;
+implement does not.
+
+## 3. Tasks: tag the tests
+
+Every AC whose level is `unit`, `integration`, `component` or `e2e` has at least one
+`[TEST] [AC-###]` task with the test file path (`lint_artifacts`: error otherwise). `command`
+and `probe` ACs get a task that writes the check (script or query) — tagged the same way.
+
+**Test names carry the id** so a result file maps back to the AC:
+
+| Stack | Name |
+|-------|------|
+| xUnit / NUnit / MSTest | method `AC003_Late_task_is_flagged` or `[Fact(DisplayName = "AC-003 late task is flagged")]` |
+| Vitest / Jest / Cypress / Playwright | `it('AC-003 late task is flagged', …)` |
+| pytest | `def test_ac003_late_task_is_flagged()` |
+
+Matching: `AC-003`, `AC003`, `AC_003`, `ac003` (case-insensitive, not inside a longer word or number).
+
+## 4. Implement: RED, then freeze
+
+Per implement phase, as today: the phase's `[TEST]` tasks (acceptance tests included) are
+written and run RED (`evidence/-red.txt`), then the code goes GREEN. Right after the RED
+run, call `acceptance_freeze(feature)` — it records the SHA-256 of every file named on a
+`[TEST] [AC-###]` task in `evidence/acceptance-freeze.json` (additive: later phases add their
+files). From then on a frozen test may only change with the user's approval
+(`acceptance_freeze refreeze=true reason=""` + a decisions.md ruling) — this is
+what stops a loop from "passing" by weakening the tests.
+
+TDD bypassed: the acceptance tests are written after the code; freeze at the first
+acceptance round; the final review notes the weaker guarantee.
+
+## 5. The acceptance run (replaces implement's full-regression step)
+
+Commands come from `specs/merge-checklist.md`:
+
+```
+acceptance_fast:          dotnet test --logger "trx;LogFileName=acc.trx" && npm test -- --reporter=junit --outputFile=test-results/acc.xml
+acceptance_fast_results:  **/TestResults/acc.trx, test-results/acc.xml
+acceptance_e2e:           npx cypress run --spec {specs} --reporter junit --reporter-options mochaFile=test-results/e2e-[hash].xml
+acceptance_e2e_results:   test-results/e2e-*.xml
+acceptance_e2e_ready:     curl -sf http://localhost:4200 >/dev/null     # exit 0 = the stack is up
+acceptance_max_rounds:    5
+```
+
+1. **Fast** — the FULL unit + integration + component suites (this is also the regression run).
+2. **e2e** — only this feature's specs (`{specs}` = the files named on its `[TEST] [AC-###]`
+   e2e tasks), only when `acceptance_e2e_ready` exits 0. Never the full e2e suite. Stack down →
+   those ACs are `deferred`, not failing; the final review lists them for a targeted run or the user.
+3. **command / probe** — run each, save `evidence/acceptance-r-AC-###.txt` whose first
+   line is `RESULT: PASS` or `RESULT: FAIL`, then the command and its output.
+4. `acceptance_status(feature, results="", round=N)` → the matrix:
+   `pass` · `fail` · `missing` (automated, no result) · `deferred` (e2e not run) · `manual`,
+   plus `regressions` (failing tests that carry no AC id) and `frozen_changed`.
+   Result: `STOPPED` if a frozen test changed, `PASS` if nothing fails, is missing or regressed, else `FAIL`.
+5. Append `## Round N` to `specs/[feature]/acceptance.md` (template
+   `spec-kit/templates/acceptance-template.md`) with `**Result**:` and `**Commit**:` (HEAD
+   when the run started) and the matrix. Save the console output as `evidence/acceptance-r.txt`.
+
+## 6. The loop
+
+```
+round = 1
+LOOP:
+  acceptance run (§5) → round N in acceptance.md
+  PASS                     → STOP: route the final review
+  STOPPED (frozen change)  → STOP: ASK the user (revert, or approve a refreeze)
+  FAIL:
+    FOR each fail / missing AC and each regression:
+      an open or claimed bug already names it → set it back to open ("failed again in
+        acceptance round N"), else log a new bug (spec-kit-test entry format) with
+        Area: AC-### · Steps: its Given/When/Then · Actual: the failing assertion ·
+        Source: acceptance round N — no per-bug confirmation inside the loop (the failing
+        test is the evidence); the round lists every bug it logged
+    STOP and ASK instead of fixing when:
+      - round == acceptance_max_rounds (default 5)
+      - the SAME ACs failed with the SAME first assertion in two consecutive rounds (no progress)
+      - the fix needs a spec change, or a frozen test change
+      - the run itself cannot execute (build broken twice, a service missing)
+    run the bugfix chain: spec-kit-plan → spec-kit-tasks → spec-kit-implement (bugfix mode)
+    round += 1
+```
+
+Inside the loop every question that cannot wait is an **assumption** in decisions.md
+(preflight check 7), never an invented ruling. Bugs fixed by the loop are `claimed` with
+`Evidence: output:evidence/acceptance-r.txt`; they become `verified` only with an oracle
+(`ci:` running the acceptance suite on that commit, the user, or `review:`).
+
+## 7. Gates
+
+- `advance_phase(5→6)` and `close_feature` refuse a feature whose spec has ACs unless the
+  latest acceptance round is `PASS` and no code commit follows its `**Commit**`.
+- The final review's §1 reads the latest PASS round: `deferred` e2e and `manual` ACs must be
+  verified there (a targeted run, or the user's quoted confirmation) or the verdict cannot be READY.
diff --git a/src/references/auto-commit.md b/src/references/auto-commit.md
deleted file mode 100644
index 06d9996..0000000
--- a/src/references/auto-commit.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Auto-Commit Pattern
-
-Skills that produce spec artifacts commit immediately after creating or updating markdown documents. This document lists the canonical commit scopes and message templates for each skill.
-
-Project-specific overrides: Create `specs/git-conventions.md` in your project root to customise commit message templates, branch naming, and merge behaviour. If the file doesn't exist, the defaults below apply.
-
-## Standard Pattern
-
-```bash
-IF `git rev-parse --git-dir > /dev/null 2>&1`; THEN
-  COMMIT_MSG=""
-  git add 
-  git commit -m "$COMMIT_MSG" --no-verify
-  COMMIT_HASH=$(git rev-parse HEAD)
-  NOTE: "Committed as $COMMIT_HASH"
-ELSE
-  NOTE: "Not a git repository — skipping automatic commit"
-```
-
-## Per-Skill Usage
-
-| Skill | Scope | Commit Message (use template from specs/git-conventions.md) |
-|-------|-------|-------------------------------------------------------------|
-| spec-kit-constitution | `specs/constitution.md` | Constitution template: `spec(phase-0): constitution for [PROJECT]` |
-| spec-kit-specify | `specs/[feature]/spec.md` | Spec template: `spec(phase-1): [feature] spec` |
-| spec-kit-clarify | `specs/[feature]/clarify.md`, `specs/[feature]/spec.md` | Clarify template: `spec(phase-1.5): [feature] clarifications` |
-| spec-kit-plan | All plan artifacts | Plan template: `spec(phase-2): [feature] plan` |
-| spec-kit-plan (bugfix sub-round) | `plan.md` (appended bugfix sections) | Bugfix plan template: `spec(phase-2): [feature] bugfix plan (BUG-NNN, ...)` |
-| spec-kit-tasks | `specs/[feature]/tasks.md` | Tasks template: `spec(phase-3): [feature] tasks` |
-| spec-kit-tasks (bugfix sub-round) | `tasks.md` (appended bugfix tasks) | Bugfix tasks template: `spec(phase-3): [feature] bugfix tasks (BUG-NNN, ...)` |
-| spec-kit-implement (phase) | Source code per phase | Implement template: `feat: [feature] Phase N - [Phase Name]` |
-| spec-kit-implement (regression) | Source code for regression fixes | Regression template: `fix: [feature] BF-REGRESSION-001 - fix regressions` |
-| spec-kit-implement (bugfix, per-task) | Source code per bugfix fix | Bugfix template: `fix: [feature] BF-### - description` |
-| spec-kit-implement (bugfix sub-round quickfix) | plan section + tasks entry + fix | Quickfix template: `fix: [feature] BF-### - description (plan+tasks+fix)` |
-| spec-kit-test | `specs/[feature]/bugs.md` | Bug log template: `spec(phase-5): [feature] bug log` |
-| spec-kit-review (pre/post-implement) | review report | Review template: `spec(review): [feature] review findings` |
-| spec-kit-summarize | Summary/close + patched spec/plan | Summary template: `spec(phase-6): [feature] summary (health: N%)` |
-| spec-kit-refresh | Patched spec artifacts | Refresh template: `spec(refresh): [feature] reconcile artifacts` |
-
-## Rules
-
-- Always `--no-verify` (pre-commit hooks may block spec artifacts)
-- Hash is captured for history.md traceability
-- Silently skip if not a git repo
-- Never commit broken state during Implement (tests must pass first)
-- Additive-safe: never delete or reorder existing entries. Only append new, or modify specific fields minimally.
diff --git a/src/references/commits.md b/src/references/commits.md
new file mode 100644
index 0000000..8cae085
--- /dev/null
+++ b/src/references/commits.md
@@ -0,0 +1,35 @@
+# Commits
+
+Every phase ends in ONE commit, preceded by its `history.md` entry when history is on for the
+feature (`history-tracking.md`: default size L only). Project overrides: `specs/git-conventions.md`.
+
+## Per-skill messages
+
+| Skill | Scope | Message |
+|-------|-------|---------|
+| constitution | `specs/constitution.md` | `spec(phase-0): constitution for [PROJECT]` |
+| specify | `spec.md`, `decisions.md`, `history.md` | `spec(phase-1): [feature] spec` — size S: `spec(phase-1-3): [feature] spec, plan, tasks` |
+| clarify | `clarify.md`, `spec.md` | `spec(phase-1.5): [feature] clarifications` |
+| plan | plan artifacts | `spec(phase-2): [feature] plan` · bugfix: `spec(phase-2): [feature] bugfix plan (BUG-NNN, …)` |
+| tasks | `tasks.md` | `spec(phase-3): [feature] tasks` · bugfix: `spec(phase-3): [feature] bugfix tasks (BUG-NNN, …)` |
+| review (pre) | review report | `spec(review): [feature] review findings` |
+| implement | code + `tasks.md` `[X]` + evidence + history | `feat: [feature] Phase N - [name]` · bugfix: `fix: [feature] BF-### - description` · quickfix: `fix: [feature] BF-### - description (plan+tasks+fix)` · regression: `fix: [feature] BF-REGRESSION-001 - fix regressions` |
+| test | `bugs.md` | `spec(phase-5): [feature] bug log` |
+| test (accept) | `acceptance.md`, evidence, `bugs.md` | `spec(phase-5): [feature] acceptance round N (RESULT a/b)` |
+| review (final) | `review-final.md`, evidence, `bugs.md` | `spec(review): [feature] final review (verdict: X)` |
+| summarize / close | close doc, change record, patched spec/plan, ADRs, AGENTS.md | `spec(phase-6): [feature] close (health: N%)` |
+| refresh | patched artifacts | `spec(refresh): [feature] reconcile artifacts` |
+
+## Rules
+
+- **History first (when on).** The entry is appended (`mcp_spec_kit_append_history` or
+  `spec-kit/scripts/spec-kit-log.sh`) and `mcp_spec_kit_history_guard` says ok before `git commit`;
+  when off the guard answers ok and the close reads `spec-kit/scripts/spec-kit-history.sh`.
+- **Intent before code.** A change to requirements or design intent (spec FRs, plan decisions)
+  is committed before the code that follows it. Status-only edits (task `[X]`, bug status,
+  evidence files, history entry) ride the phase's code commit — one commit per phase boundary.
+- **Never `--no-verify`.** A hook that blocks a spec artifact is a hook to fix.
+- Never commit a red suite during implement; no commits inside a RED sub-phase.
+- No commit hashes in history entries (squash-merge kills them); the commit *message* is the link.
+- Not a git repo → skip silently.
+- Before every commit: `mcp_spec_kit_lint_artifacts` → 0 errors (no MCP: re-read ids and statuses).
diff --git a/src/references/evidence.md b/src/references/evidence.md
new file mode 100644
index 0000000..3a35b52
--- /dev/null
+++ b/src/references/evidence.md
@@ -0,0 +1,68 @@
+# Evidence of Done
+
+**Rule**: a statement by the agent that produced a change is never evidence that it works.
+The same model writes the code, the tests, the fixtures and the review; its fixtures encode
+its own misunderstanding. Every gate needs an **oracle** the agent did not author.
+
+## Oracles
+
+| Oracle | Form | Counts as |
+|--------|------|-----------|
+| `user` | A human ran or inspected it and said so (quote the words) | verification |
+| `ci:` | A CI run on the exact commit, with its result | verification |
+| `review:` | A review by a **different** agent than `Implemented-by` | verification |
+| `probe:` | Read-only query/call against the real system, saved under `evidence/` | evidence — required for every `[SEAM]` |
+| `output:` | Saved output of a test/build command under `evidence/` | evidence |
+
+`probe:` and `output:` support a **claim**; `verified` needs `user`, `ci:` or `review:`.
+
+## Files — every tier (`sizing.md`: the size changes the workflow, never the evidence)
+
+`specs/[feature]/evidence/`, one file per item, first line = command, second = UTC time.
+
+| File | When |
+|------|------|
+| `-probe-.txt` — read-only probe before a `[SEAM]` fixture | every `[SEAM]` task |
+| `-red.txt` — the phase's `[TEST]` tasks failing for the right reason | every implement phase (S: the one phase) |
+| `-green.txt` — the phase's tests passing | every implement phase |
+| `-characterisation.txt` — legacy code pinned before change | when it applies |
+| `acceptance-r.txt` (+ `-AC-###.txt` per command/probe AC) | every acceptance round |
+| `acceptance-freeze.json` — SHA of the AC tests after RED | every feature with ACs |
+| `final-.txt` — diff scan, build, test, lint, format | every final review |
+
+The history entry's `Evidence:` field (history on) or the commit body (history off) names these files. `lint_artifacts` warns about a done `[TEST]`
+task without a RED file and a done `[SEAM]` without a probe — every tier.
+
+## Acceptance criteria are always documented
+
+Every feature, S included, ends with an acceptance round in `acceptance.md` that lists every
+AC with its outcome. Automated wherever a harness exists (`unit` … `e2e`, `command`, `probe`);
+`manual` only where no tool can judge, and then the round (or the final review) quotes the
+user's confirmation — an unconfirmed manual AC is 👤 pending, never ✅.
+
+## Status vocabulary (bugs.md)
+
+`open` → `in-progress` → `claimed` (agent believes fixed; **Evidence:** lists files) →
+`verified` (only with **Verified-by:** `user` / `ci:` / `review:`) ·
+`superseded` (replaced by another entry). Legacy `resolved`/`fixed` read as `claimed`. The
+implementing agent never sets `verified`.
+
+## Author / reviewer split
+
+`Implemented-by` = the `` of the history.md implement entries, or — history off — the
+`**Implemented-by**:` line in the tasks.md header. The review reads it: a different agent →
+the review is `review:`; the same agent → **self-review** (fresh-context sub-agent for
+L), which opens the merge gate but never verifies a bug.
+
+## Gates
+
+| Gate | Minimum evidence |
+|------|------------------|
+| Implement phase commit | `output:` RED + GREEN of the phase; probe per seam |
+| Acceptance round | `acceptance.md` round with Result + Commit; `output:`; frozen tests unchanged |
+| Bug `claimed` | `output:` of the reproducing test green; `probe:` per seam touched |
+| Bug `verified` | `Verified-by:` oracle |
+| Final review | round with Verdict + Reviewed-commit; `output:` of diff_scan, build, test, lint; `ci:` when a pipeline exists |
+| Close | final review READY / READY-WITH-FOLLOWUPS, fresh; every bug verified or superseded; change record filled |
+
+A gate without evidence is **unverified**, never done.
diff --git a/src/references/history-tracking.md b/src/references/history-tracking.md
index ecba3d0..231a491 100644
--- a/src/references/history-tracking.md
+++ b/src/references/history-tracking.md
@@ -1,72 +1,86 @@
-# Process History
+# Process History — the record, not the story
 
-Every spec feature directory maintains `specs/[feature]/history.md` — an append-only process history. Each phase skill appends one entry when it completes.
+`specs/[feature]/history.md` is an append-only **record**: one fixed-field entry per phase
+completion, bugfix, regression run or close. It exists so that an agent (or a human) can read
+in ten seconds what was done, when, with what evidence, and by whom — and so the pre-commit
+guard can prove the entry was written before the commit.
 
-## Standard Entry Format
+It is **not** the place for narrative. Decisions, rationale and what-went-wrong belong in
+`close.md` / `change-record.md` (phase 6), `decisions.md` (assumptions) or the commit body.
+It is the record that survives the squash-merge; the close copies its timeline into `change-record.md`.
+In one deployment history files reached 215 KB with 1 600-word entries and invented
+timestamps — nobody read them. The format below is capped and machine-appended.
 
-```markdown
-## [ISO_TIMESTAMP] | [Phase Name] → Complete
-- **Skill**: spec-kit-[skill-name]
-- **Artifacts**: [comma-separated list of files created or modified]
-- **Commit**: [commit hash from git rev-parse HEAD, or "N/A" if no commit]
-- **Notes**: [optional — key decisions, deviations, or notable events]
-```
+## When it is kept
+
+`history:` in `specs/git-conventions.md` — `always` · `large` (default: size L only) · `never`;
+`**History**: on | off` in spec.md overrides it for one feature. The phase card says which
+applies. **On**: every phase appends an entry before its commit (`history_guard` enforces).
+**Off**: no entries; the close builds the change record's timeline from the branch's git log
+(`spec-kit/scripts/spec-kit-history.sh`, run before the squash) and `Implemented-by` comes from
+the `**Implemented-by**:` line implement writes into the tasks.md header. S/M bugfixes and small
+enhancements rarely need the per-phase record; L — many phases, weeks, the features auditors
+sample — does.
 
-## Example
+## Entry format
 
 ```markdown
-## 2026-06-08T10:00:00 | Phase 1 → Complete
-- **Skill**: spec-kit-specify
-- **Artifacts**: specs/001-user-auth/spec.md
-- **Commit**: a1b2c3d4
-- **Notes**: OAuth2 with JWT tokens, 3 user stories
+##  |  |  | 
+- Artifacts: 
+- Tests:  →    (or "none")
+- Evidence:    (or "none — unverified")
+- Commit: 
+- Note: <≤ 25 words — the one fact a reader needs; nothing else>
 ```
 
-## How to Use
+Rules:
+- **Timestamp from the clock**, never from memory: `mcp_spec_kit_timestamp()` or `date -u +%Y-%m-%dT%H:%M:%S+00:00`.
+- `` is `hermes`, `claude`, or the human's name — this is the `Implemented-by` the review and evidence rules read.
+- Whole entry ≤ 60 words after the header. The appender refuses longer notes.
+- Append only. Never edit or delete a past entry; a correction is a new entry.
+- No commit hashes (branches are squash-merged; the commit *message* is the traceability link).
 
-At the end of any phase skill, after all artifacts are written and committed, append to history.md:
+## How to append
 
+With the MCP server (preferred — it stamps the real time and enforces the cap):
+
+```text
+CALL mcp_spec_kit_append_history(feature="[feature]", phase="Phase 2", skill="spec-kit-plan",
+     agent="claude", artifacts="plan.md, research.md", tests="none",
+     evidence="none", commit="spec(phase-2): [feature] plan", note="HQ-currency resolution deferred to F")
 ```
-FULL_PATH="specs/[feature]/history.md"
 
-CREATE history.md IF NOT EXISTS with header:
-  # Process History: [Feature]
+Without MCP — the shipped script does the same from the shell:
 
-APPEND entry:
-  ## [$(date -u +"%Y-%m-%dT%H:%M:%SZ")] | [Phase] → Complete
-  - **Skill**: spec-kit-[skill]
-  - **Artifacts**: [files]
-  - **Commit**: $(git rev-parse HEAD 2>/dev/null || echo "N/A")
-  - **Notes**: [summary of what was done]
+```bash
+~/.hermes/skills/spec-kit/scripts/spec-kit-log.sh  ""   \
+    --artifacts "plan.md, research.md" --tests "none" --evidence "none" \
+    --commit "spec(phase-2): [feature] plan" --note "HQ-currency resolution deferred to F"
 ```
+(Claude Code: the same path under `~/.claude/skills/spec-kit/scripts/`.)
+
+If neither is available, write the entry by hand in the exact format, taking the time from `date -u`.
+
+## Phase labels
+
+| Skill | Phase label |
+|-------|-------------|
+| spec-kit-specify | `Phase 1` |
+| spec-kit-clarify | `Phase 1.5` |
+| spec-kit-plan | `Phase 2` (bugfix round: `Phase 2 — bugfix round N`) |
+| spec-kit-tasks | `Phase 3` (bugfix round: `Phase 3 — bugfix round N`) |
+| spec-kit-review | `Phase 3.5` / `Phase 5.5` |
+| spec-kit-implement | `Phase 4 — ` · `BF-###` · `Regression` · `Regression fix` |
+| spec-kit-test | `Phase 5` |
+| spec-kit-summarize | `Phase 6` |
+| spec-kit-refresh | `Refresh` |
+| workflow reopen | `Reopen` |
+
+The constitution is project-level and has no feature history.
+
+## Guard: history before every commit
 
-## Phase Name Reference
-
-| Skill | Phase Name |
-|-------|-----------|
-| spec-kit-constitution | Phase 0 |
-| spec-kit-specify | Phase 1 |
-| spec-kit-clarify | Phase 1.5 |
-| spec-kit-plan | Phase 2 |
-| spec-kit-tasks | Phase 3 |
-| spec-kit-review (pre-implement) | Phase 3.5 |
-| spec-kit-implement | Phase 4 (each sub-phase logged as Phase N) |
-| spec-kit-implement | Phase 4 → Full Regression → Pass (after all phases, full suite passes) |
-| spec-kit-implement | Phase 4 → Regression Fix → Complete (BF-REGRESSION-001 resolved) |
-| spec-kit-implement | Phase 4 → Bugfix BF-### → Complete (per-bugfix during bugfix mode) |
-| spec-kit-test | Phase 5 |
-| spec-kit-review (post-implement) | Phase 5.5 |
-| spec-kit-summarize | Phase 6 |
-| spec-kit-refresh | Refresh |
-| Reopen (workflow) | Reopen |
-
-## Guard: history.md Before Every Commit
-
-**history.md entries MUST be written before the corresponding git commit — never after.** Every commit in `spec-kit-implement` is preceded by a history.md entry:
-
-1. **Per-phase commit**: Entry appended in step 4f — includes test pass count and task completion count.
-2. **Bugfix commit (BF-###)**: Entry appended in bugfix mode step 3 — includes which BUG-NNN was fixed and test verification.
-3. **Regression fix commit (BF-REGRESSION-001)**: Entry appended in regression fix flow — includes full suite pass confirmation.
-4. **Full regression pass**: Entry appended in step 7 when all tests pass — standalone verification record (no commit, documents the checkpoint).
-
-The PRE-COMMIT GUARD reads history.md and blocks the commit if the entry is missing. This ensures the process log is never behind the git log.
+Every commit touching `specs/[feature]/` or the feature's code is preceded by an entry.
+`mcp_spec_kit_history_guard(feature, phase)` checks that an entry mentioning the phase label is
+newer than the last commit touching the feature; the Shared Commit Procedure in `preflight.md`
+calls it. Without MCP, read the last entry's header before `git commit`.
diff --git a/src/references/preflight.md b/src/references/preflight.md
index 4604296..ca092a4 100644
--- a/src/references/preflight.md
+++ b/src/references/preflight.md
@@ -1,141 +1,48 @@
 # Pre-Action Self-Check
 
-**Must be loaded and followed before ANY action in any spec-kit skill.**
-
-Run these checks in order. If any check fails, stop and report before proceeding.
-
-## Checks
+Run before any action in any spec-kit skill; stop and report on a failure. After a context
+compaction re-run 1–5 and re-read the phase card. Keep this file and the one-screen SKILL.md
+in context; open `spec-kit/references/skills/.md` only for the step you are on.
 
 ```
-1. BRANCH CHECK
-   CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
-   IF CURRENT_BRANCH == blocked_branches (from git-conventions.md, step 3):
-     BLOCK: "On a blocked branch. All spec-kit work must be on a
-             feature branch. Run:
-             git checkout -b {feature_prefix}/NNN-name
-             (or {bugfix_prefix}/NNN-name for bugfix)"
-     HALT
-   
-2. MODE DETECTION — STRICT
-   IF specs/[feature]/bugs.md EXISTS with Status: open entries:
-     BLOCK: "You are in bugfix mode. Cannot write code directly — bugs must go through the workflow.
-             Route: 'bugfix [feature]' → plan → tasks → implement."
-     HALT
-   ELSE:
-     MODE = feature
-
-3. UNLOGGED BUG CHECK — before any code change
-  IF the user reported a bug or issue (not a planned feature task):
-    IF specs/[feature]/bugs.md NOT EXISTS OR the reported issue has no BUG-NNN entry:
-      BLOCK: "Bug must be logged before it can be fixed. Run 'test [feature]' first to log the bug,
-              then 'bugfix [feature]' to start the fix loop.
-              Rule: Log Before Fix — ALWAYS."
-      ROUTE to: spec-kit-test
-      HALT
-
-4. GIT CONVENTIONS
-   IF specs/git-conventions.md EXISTS in the project root:
-     LOAD and apply for branch naming, commit messages, and merge behaviour.
-     CHECK version: read `Conventions version:` line from the file
-       IF version < 1: NOTE "Your git-conventions.md is outdated. Re-copy from spec-kit/templates/git-conventions-template.md."
-     NOTE: Conventions override the defaults shown in each skill.
-   ELSE:
-     CREATE specs/git-conventions.md from spec-kit/templates/git-conventions-template.md
-     NOTE: "Created specs/git-conventions.md with default conventions. Edit to customise for this project."
-
-4. WORKFLOW LOAD CHECK — code-writing phase only
-   IF you are about to call write_file, patch, or terminal(build/test):
-     IF spec-kit-workflow is NOT loaded:
-       BLOCK: "Must load spec-kit-workflow first for branch guardrails
-               and phase routing. Run: skill_view(name='spec-kit-workflow')"
-       HALT
-
-5. HISTORY LOG CHECK — BEFORE creating or modifying any markdown document
-   IF you are about to create or modify any markdown document in specs/[feature]/:
-     ENSURE specs/[feature]/history.md EXISTS (create with header if missing)
-     NOTE: "history.md is the process log for this feature. Every markdown
-            change MUST be recorded here BEFORE the next commit."
+1. BRANCH   git rev-parse --abbrev-ref HEAD ∈ blocked_branches (git-conventions.md)
+            → BLOCK "feature branch required: git checkout -b {feature_prefix}/NNN-name"
+2. MODE     specs/[feature]/bugs.md has Status: open | in-progress
+            → bugfix mode: code only through 'bugfix [feature]' (plan → tasks → implement)
+3. LOG BEFORE FIX   the user reports a bug with no BUG-NNN entry
+            → BLOCK, route spec-kit-test, HALT
+4. CONVENTIONS      specs/git-conventions.md missing → create from
+            spec-kit/templates/git-conventions-template.md; `Conventions version:` < 1 → say so
+5. PHASE CARD       MCP: mcp_spec_kit_get_next_actions(feature) — read it; no MCP: derive the
+            phase from the files and state it in one line. Source code outside Implement → BLOCK
+            history ON for this feature (phase card; history-tracking.md) and history.md missing
+            → create it (spec-kit/templates/history-template.md)
+6. ASSUMPTIONS      at every ASK / WAIT with no human answer: record an `assumption` in
+            decisions.md (question, taken, alternative) — never an invented "ruling"; a human
+            answer → `ruling` quoting them. Only questions the USER would want to decide (scope,
+            behaviour, user-visible trade-offs) go here; a design choice inside the plan's remit
+            is plan.md content, not an assumption.
 ```
 
-## Quick summary for fast reference
-
-- Not on main/master? ✓
-- Bug mode blocks code? ✓ (open bugs → BLOCK, route through bugfix)
-- Bug logged before fix? ✓ (unlogged bug → BLOCK, route to spec-kit-test)
-- Workflow loaded before code? ✓
-- history.md exists for this feature? ✓ (created if missing)
-
-## Post-Completion Requirements (MANDATORY)
-
-After every skill completes that created or modified any markdown document:
-
-1. **history.md is already ready** (pre-action check #5 already ensured it exists). Append an entry for each document created or modified:
-   - Format: `## [ISO_TIMESTAMP] | [Phase Name] → Complete` with skill, artifacts, commit hash, notes
-   - See `spec-kit/references/history-tracking.md` for the exact format
-   - This is NOT optional — if you skip this, the process log will be missing
+## Commit procedure (every skill that writes artifacts)
 
-2. **PRE-COMMIT GUARD — Verify history.md is updated**
-   BEFORE running `git add` and `git commit`:
-   ```text
-   READ specs/[feature]/history.md
-   IF any markdown document created/modified in THIS skill run is NOT recorded:
-     BLOCK: "Cannot commit — history.md is missing entries for [document(s)].
-             Append entries first."
-   ```
-   Only proceed to commit after history.md is verified complete.
-   - **Spec/plan changes that alter requirements or design intent** → MUST be committed BEFORE any related code. This preserves the causal chain: spec describes what → code implements it. Never commit spec changes as a side-effect of a code commit.
-   - **Status-only updates** (bug verified, task marked [X], bug status changed) → CAN share a commit with code. These document what the code did, not what it should do.
-   - **Bugfix sub-round documents** (new plan section for new bugs, new tasks for new bugs):
-     - `bugfix` (default): plan gets its own commit, tasks get its own commit, implementation commits per fix.
-     - `quickfix` (user opt-in): plan + tasks + fix batched in one commit. Plan ref and task entry ALWAYS exist.
-   - **Phase 6 close** (patched spec/plan + close.md) → ONE commit. This is explicit intentional reconciliation.
-   - **One change → one commit**. Multiple related changes in one logical action (e.g. clarify updates clarify.md + amends spec.md) → one commit.
-   - Use commit template from specs/git-conventions.md (see auto-commit.md).
-   - Skip silently if not a git repo.
-
----
-
-### Shared Commit Procedure (reference from every skill)
-
-**Every skill that creates or modifies markdown artifacts MUST follow this procedure instead of re-implementing it.**
-
-```text
-1. APPEND to specs/[feature]/history.md:
-   - Phase: [Phase Name]
-   - Artifact: [comma-separated list of artifacts created/modified]
-
-2. PRE-COMMIT GUARD:
-   READ specs/[feature]/history.md
-   IF the entry for this phase is NOT recorded:
-     BLOCK: "Cannot commit — history.md is missing the [phase] entry. Append first."
-
-3. COMMIT:
-   Follow the auto-commit template for this phase:
-   - Scope: [artifacts scope]
-   - Message: [commit message template]
-   git commit -m "[message]" --no-verify
 ```
-
-Skills MUST replace their full "Append to history.md and Commit" section with:
-```text
-Follow the Shared Commit Procedure in spec-kit/references/preflight.md:
-- Phase: [Phase Name]
-- Artifact: [comma-separated list]
-- Scope: [git scope for auto-commit.md]
-- Message: "[commit message template]"
+1. history ON (phase card) → APPEND the history.md entry (history-tracking.md — fixed fields,
+   real time, ≤ 60 words): mcp_spec_kit_append_history(feature, phase, skill, agent, artifacts,
+   tests, evidence, commit, note)  |  no MCP: spec-kit/scripts/spec-kit-log.sh …
+   history OFF → nothing to append (implement keeps **Implemented-by** in tasks.md instead)
+2. mcp_spec_kit_history_guard(feature, phase) → ok · mcp_spec_kit_lint_artifacts → 0 errors
+3. git add ; git commit -m ""
+   Hooks run — never --no-verify.
 ```
+When on, `history.md` is the record that survives the squash-merge; a commit without its entry
+is a gap an auditor will find. When off, the change record's timeline is built from git at close.
 
-This ensures the 3-step pattern (append → guard → commit) is defined in ONE place, not copy-pasted across every skill. See each skill's section for the phase-specific phase name, artifacts, and commit message.
-
-3. **Additive-safe editing**. During design phases (0-3), you may freely iterate — rewrite, restructure, refactor spec/plan/tasks as needed. The review skill may propose changes freely. Each design phase skill commits its artifacts immediately (no batching).
-   
-   During implementation and bugfix phases (4+), the additive-safe rule tightens: never delete or reorder existing entries in bugs.md, tasks.md, plan.md, spec.md, clarify.md, close.md, or implementation-summary.md. You MAY modify existing entries — update status fields, amend text, correct inaccuracies — but the modification must be minimal (change only the specific field or section needed). Never restructure or refactor a document beyond what's required for the change. New entries (new bugs, tasks, plan sections) always append at the end. The goal: preserve every existing bug ID, task ID, and requirement — only update what the current change demands.
-   
-   If you return to modify spec/plan during test or bugfix phases: commit those changes immediately after editing, following the same per-document commit pattern.
-
-4. **Ordering**: bugs.md entries must be ascending by BUG-NNN. tasks.md entries must be ascending by T###. New entries append with the next sequential ID.
-
-## Enforcement
+## No complete overwrite — every phase
 
-These checks are NOT optional. If you skip them and write to the wrong branch,
-the result is workflow corruption. Stop and verify every time.
+Spec artifacts (`spec.md`, `plan.md`, `tasks.md`, `bugs.md`, `clarify.md`, `decisions.md`,
+`acceptance.md`, `review-final.md`, close documents) are never rewritten: append sections,
+insert entries, patch fields, flip status markers. Before any write, read the file. Forbidden:
+copying a template over an existing file, deleting ids, reformatting, rewriting ≥ 50 % of the
+lines. First creation is the only exception. Ids (`BUG-NNN`, `T###`, `BF-###`, `AC-###`, `D-###`)
+are ascending and never reused.
diff --git a/src/references/sizing.md b/src/references/sizing.md
new file mode 100644
index 0000000..87786fa
--- /dev/null
+++ b/src/references/sizing.md
@@ -0,0 +1,54 @@
+# Size Tiers (S / M / L)
+
+Ceremony follows the size of the change — the **workflow** and the **length of the artifacts**
+shrink; the evidence does not. `spec-kit-specify` **always asks** the tier, recommendation first
+and marked "(Recommended)" with the signals that triggered it. The answer is a ruling in
+decisions.md and `**Size**: S | M | L — ` in spec.md. Unattended → the recommendation is
+recorded as an assumption. A spec without the line is treated as M.
+
+**S is for a single bugfix or a small enhancement** — one layer, a handful of files, nothing
+new at the boundary. Anything with a new seam, a second layer or a security / tenant / data
+dimension is at least M.
+
+## Choosing — the highest tier any row triggers
+
+| Signal | S | M | L |
+|--------|---|---|---|
+| Layers touched (UI, API, DB, infra, jobs) | 1 | 2 | 3+ |
+| Files expected to change | ≤ ~6 | ~7–25 | > 25 |
+| New external seam (schema, HTTP contract, message, file format) | none | one, additive | several, or breaking |
+| New dependency / new pattern | no | one, conventional | yes |
+| Security, auth, money, deletion, tenant boundary, personal data | no | — | yes |
+| Expected tasks | ≤ ~8 | ~9–25 | > 25 |
+| Unknowns to research | none | a few | many / spike |
+
+Typo, rename, config value → no spec-kit at all.
+
+## What each tier produces — the workflow and the artifacts get leaner, the evidence stays
+
+| Step | S | M | L |
+|------|---|---|---|
+| spec.md | **a few lines**: one sentence of intent, 1–3 FRs, **1–2 ACs**, the Security & Privacy line ("None — because …" allowed), 1 SC | full template | full template |
+| Clarify | only if a marker remains | if markers remain | recommended |
+| plan.md | **half a page**: Summary, Current Design, seams, the AC → test row(s), Rounds | full; research / data-model / contracts / quickstart only when needed | full + all that apply |
+| Specify → Plan → Tasks | **auto-chained**, ONE commit `spec(phase-1-3)` | one commit per phase | one commit per phase |
+| tasks.md | flat list, ≤ ~8 tasks | phases | phases |
+| Pre-implement review (3.5) | skip | **lite**: coverage, underspecification, codebase fit, devil's advocate | **required, full** + devil's advocate by a separate sub-agent |
+| Implement evidence | **same for every tier**: `probe:` per `[SEAM]`, RED and GREEN file per phase, AC tests frozen after RED | same | same |
+| **Acceptance round** (`acceptance.md`) | **every tier**: automated ACs run and recorded; manual ACs carry the user's quoted confirmation | same | same |
+| `ci:` | when a pipeline exists | yes | yes |
+| Final review (5.5) | §1 coverage line + exceptions, §2 rules, §4 devil's advocate (brief), §5 checklist; no stack research | full, exceptions-only tables | full, by the other agent or a fresh-context sub-agent; devil's advocate separate |
+| Close | `close` (one page) + `change-record.md` | `close` + change record; gap table exceptions only | `summarize` (full gap table) + change record |
+| ADR / AGENTS.md step | yes ("none met the bar" is fine) | yes | yes |
+| `history.md` (default `history: large`; spec `**History**:` overrides) | off — timeline from git at close | off | **on** — entry before every commit |
+
+**What never shrinks**: the RED/GREEN files, the probe per seam, the acceptance round that
+documents every AC passing (automated where a harness exists, `manual` with the user's quoted
+words where none can), the oracle rule (your word is not evidence), the final-review gate,
+the change record. A small change still has to prove it works.
+
+## Changing the tier
+
+A bigger change than the tier (new seam, third layer): stop, say so, ask. On approval edit the
+`**Size**:` line, add the missing artifacts additively, record the ruling. No downgrade once
+higher-tier artifacts exist.
diff --git a/src/references/skills/spec-kit-constitution.md b/src/references/skills/spec-kit-constitution.md
new file mode 100644
index 0000000..e87d900
--- /dev/null
+++ b/src/references/skills/spec-kit-constitution.md
@@ -0,0 +1,586 @@
+# spec-kit-constitution — full procedure
+
+**Task Persona**: Adopt the mindset of a project founder setting ground rules.
+Constitutions should be principled but practical — they guide decisions without
+being bureaucratic. Every rule must have a clear purpose. Always offer choice
+with tradeoffs explained.
+
+**Phase**: 0 (Project Foundation)
+
+**Purpose**: Create or update the project constitution at `specs/constitution.md`.
+
+Three input modes:
+1. **Brownfield** (existing code): Auto-detects stack from project files —
+   60+ detection patterns for language, framework, test runner, CI, database,
+   and linting. Pre-fills ⭐-marked defaults.
+2. **Free-text description** (new project): User describes the project in
+   natural language (e.g. "React Native mobile app for fitness, small team,
+   ship fast"). Agent maps description to purpose → architecture → tech →
+   principle defaults automatically. User reviews and adjusts.
+3. **Wizard** (guided, new project): Interactive 3-level decision tree
+   (9 purposes × 25 architecture options). User picks at each level.
+   Always presents 3 options per principle with pros and cons.
+
+**When NOT to use**: This is a one-time setup per project. Do NOT re-run for
+every feature — principles are project-wide.
+
+**Prerequisites**: None. This is the first skill — run first for a new project.
+
+**Artifacts**: `specs/constitution.md`
+
+**Routing**: Load this skill when the user says "create constitution" or
+"create project principles". If loaded directly (not via spec-kit-workflow),
+consider loading the workflow first for prerequisite checks.
+
+## Pre-flight
+Load and follow `spec-kit/references/preflight.md` before any action in this skill.
+
+## Execution
+
+### Step 0: Check for existing constitution
+
+```
+IF specs/constitution.md EXISTS:
+  LOAD existing constitution
+  NOTE: "Constitution exists at v[VERSION]. Run 'amend constitution' to update."
+  HALT — constitution is one-time setup, do not overwrite without user intent
+```
+
+### Step 1: Detect mode — brownfield vs greenfield
+
+```
+SCAN project root for these files to identify the tech stack:
+
+LOAD the brownfield file detection tables from `spec-kit/references/constitution-tables.md`
+
+  IF any project files detected:
+    MODE = brownfield
+    COMPILE a detection summary:
+      "Detected [language] project with [framework].
+       Test: [test_framework]. CI: [ci_platform]. DB: [database].
+       Linting: [linter]. Formatting: [formatter]."
+
+    USE the detection to pre-fill ⭐ recommendations:
+      - Testing: If pytest/Jest/Vitest/go test detected → ⭐ B (Pragmatic TDD)
+                   If no test files found → ⭐ C (Test-After)
+      - Linting: If ESLint/Ruff/RuboCop/clippy config exists → ⭐ A or B
+                   If no lint config → ⭐ C (Minimal)
+      - Git: If .github/workflows exists → ⭐ A (Trunk-Based) or B (Feature Branches)
+               If Jenkinsfile → ⭐ C (Git Flow)
+      - DB: If migrations detected → ⭐ A (Migration-First)
+              If no DB files → SKIP Principle 10
+
+  ELSE:
+    MODE = greenfield
+    NOTE: "No existing project detected. Would you like to:
+           1. Describe your project in a sentence — I'll map it to purpose,
+              architecture, tech, and principle defaults automatically
+           2. Use the guided wizard — 3 levels of choices with tradeoffs at each step"
+    
+    ASK: "Which approach do you prefer? (1) Free-text description or (2) Guided wizard"
+    
+    RECORD: input_mode = [free-text | wizard]
+```
+
+### Step 2a: Free-Text — Description to Constitution
+
+**Only for MODE=greenfield AND input_mode=free-text.**
+
+The user provides a natural-language project description. The agent maps it
+to a purpose (A-I), architecture (A1-I3), technology choices, and principle
+defaults automatically. The user reviews the inferred choices and may accept
+or adjust any of them.
+
+```text
+1. PROMPT: "Describe your project in a few sentences — what are you building,
+   what platform/target, team size, and any key constraints?"
+
+2. AWAIT user input (e.g. "React Native mobile app for fitness tracking,
+   small two-person team, want to ship quickly, no backend — Firebase")
+
+3. INFER from the description:
+
+   MAP the description to a purpose code (A-I):
+     - Look for keywords: "mobile app", "iOS", "Android", "desktop"
+       → Purpose C (Native/Desktop Client)
+     - "web app", "SaaS", "API", "dashboard", "full-stack"
+       → Purpose A (User-Facing Application)
+     - "library", "package", "SDK", "npm", "PyPI"
+       → Purpose D (Library/SDK)
+     - "CLI", "tool", "script", "pipeline", "Terraform"
+       → Purpose E (Infrastructure/CLI/DevOps)
+     - "game", "Unity", "Unreal", "Godot"
+       → Purpose F (Game)
+     - "extension", "browser add-on", "Chrome extension"
+       → Purpose G (Browser Extension)
+     - "notebook", "research", "analysis", "Jupyter"
+       → Purpose H (Research/Notebook)
+     - "firmware", "embedded", "IoT", "Arduino", "ESP32"
+       → Purpose I (IoT/Embedded)
+     - "portfolio", "blog", "landing page", "marketing site"
+       → Purpose B (Content Site/Marketing)
+     - If ambiguous: infer the closest match and note the uncertainty
+
+   MAP architecture from implied stack:
+     - "React Native", "Flutter", "Tauri" → C2 (Cross-Platform)
+     - "iOS app (Swift)", "Android (Kotlin)" → C1 (Native)
+     - "Electron", "PWA", "Capacitor" → C3 (Web Wrapper)
+     - "Firebase", "Vercel", "Cloudflare" → A4 (Serverless)
+     - "Unity", "Unreal", "Godot" → F1 (Engine-Centric)
+     - "Rails", "Django", "Laravel" → A1 (Monolith)
+     - "microservices", "distributed" → A3 (Microservices)
+     - "Arduino", "sensor firmware" → I3 (MicroPython/Arduino)
+     - "bare-metal", "RTOS", "FreeRTOS" → I1 (Bare-Metal/RTOS)
+     - "single notebook", "analysis only" → H1 (Single Notebook)
+     - "static site", "SSG" → B1 (Static Site Generator)
+     - Default: use the most common architecture for the detected purpose
+
+   MAP tech choices from explicit mentions:
+     - "React Native" → TypeScript, React Native framework
+     - "Flutter" → Dart, Flutter
+     - "Firebase" → BaaS for auth/db
+     - Extract any explicit language/framework mentions
+
+   MAP principle defaults from inferred purpose using the Step 2c
+   (Purpose-to-Principle) mapping table below.
+
+4. PRESENT the inferred result as a table:
+
+   | Inference | Value | Correct? |
+   |-----------|-------|----------|
+   | Purpose | C — Native / Desktop Client | ✅ / 🔄 |
+   | Architecture | C2 — Cross-Platform (Flutter/React Native) | ✅ / 🔄 |
+   | Language | TypeScript (React Native) | ✅ / 🔄 |
+   | Testing | B — Pragmatic TDD (recommended for native apps) | ✅ / 🔄 |
+
+   ASK: "Does this look right? You can say 'all good' to proceed with these
+         defaults, or correct specific items. I'll then walk through the
+         12 principles to confirm or adjust."
+
+5. IF user says "all good" or confirms:
+   PROCEED to Step 2c (Load principles reference) then Step 3
+
+6. IF user corrects specific items:
+   UPDATE the inferred values
+   RECORD corrections as user rationale
+   PROCEED to Step 3
+
+7. IF user says "I want the wizard instead":
+   SET input_mode = wizard
+   ROUTE to Step 2b (Wizard mode below)
+
+8. IF the description is too vague to map confidently:
+   NOTE: "Description is quite broad. I'll use [purpose] as a starting point,
+          but let me know if that doesn't fit."
+   PROCEED with best-guess inference
+```
+
+**Inference examples:**
+
+| User says | Inferred purpose | Inferred arch | Principle defaults |
+|-----------|-----------------|---------------|-------------------|
+| "iOS app with SwiftUI for habit tracking, solo dev" | C — Native | C1 — Native Platform | C defaults, Testing C (solo dev) |
+| "React Native mobile app for fitness, small team, Firebase" | C — Native | C2 — Cross-Platform | C defaults, Testing B |
+| "Django REST API for a SaaS dashboard" | A — User-Facing | A1 — Monolith | A defaults |
+| "CLI tool in Go for managing Kubernetes clusters" | E — Infra/CLI | E1 — Single Binary | E defaults |
+| "Three.js browser game, WebGL, casual" | F — Game | F3 — Web/Retro | F defaults |
+| "Jupyter notebook analyzing stock market data" | H — Research | H1 — Single Notebook | H defaults |
+
+---
+
+### Step 2b: Wizard — 3-Level Decision Tree
+
+**Only for MODE=greenfield AND (input_mode=wizard OR no input_mode set yet).**
+
+Guide the user through three levels of decisions. Each level narrows the
+options and pre-fills recommended defaults for the next level. Use the
+brownfield detection examples table from `spec-kit/references/constitution-tables.md` for recommended defaults once
+language + framework are chosen.
+
+---
+
+#### Level 1 — Highest-Level Purpose
+
+Ask the user: *"What is this project's primary purpose?"*
+
+Present these 9 options with their tradeoffs:
+
+| Option | Type | Examples | Testing impact | Arch impact | Docs impact | Deps impact |
+|--------|------|----------|---------------|-------------|-------------|-------------|
+| **A — User-Facing Application** | Web/mobile API, frontend, full-stack app | SaaS, e-commerce, social app, dashboard, CMS | Needs integration + F2E tests. TDD pays off. | Architecture matters — will need to scale. | API docs, user docs, setup guide critical. | Framework deps expected (React, Django, etc.) |
+| **B — Content Site / Marketing** | Static or lightly dynamic, no auth/DB | Portfolio, landing page, blog, documentation site, marketing site | Minimal. Visual checks + broken link checker. No business logic to test. | Simple — SSG, template-driven, or plain HTML/CSS. No backend needed. | Content IS the documentation. Readme for build/deploy. | SSG framework or plain HTML/CSS. Zero server deps. |
+| **C — Native / Desktop Client** | Standalone client app, no backend to architect | iOS app, Android app, macOS app, Windows app, Linux desktop app, Electron app, Tauri app, Qt app | UI/snapshot tests, integration tests. Manual QA for visual polish. | Client-side architecture (MVC, MVVM, Redux, Composable). Platform SDK native or cross-platform framework. | User-facing help, API docs for local features, store listing. | Platform SDK, UI framework. Cross-platform framework for shared code. |
+| **D — Library / SDK / Package** | Reusable code for other developers | npm package, PyPI lib, Go module, crate | Exhaustive unit tests essential. API surface must be tested. | Clean public API, minimal internal coupling. | API docs, README, examples, changelog mandatory. | Zero or minimal deps to avoid transitive bloat. |
+| **E — Infrastructure / CLI / DevOps** | Automation, ops tools, platform | CLI tool, Terraform module, CI pipeline, daemon | Integration tests with real infra. Manual testing common. | Simple, composable. No over-engineering. | README + --help. Code that IS the documentation. | Minimal. Static binaries preferred. |
+| **F — Game** | Interactive application with game loop, rendering, input | 2D platformer, 3D FPS, puzzle game, RPG, mobile game, WebGL game | Unit tests for game logic. Visual/playtest testing critical. Integration tests for netcode. | ECS, scene graph, component-based. Game loop, render pipeline, physics. | Design doc, mechanics doc, modding API docs. README + gameplay guide. | Engine dependency (Unity, Unreal, Godot, Bevy). Graphics, audio, physics libs. |
+| **G — Browser Extension** | Browser add-on modifying/extending the browser | Chrome extension, Firefox add-on, Safari extension, Edge extension | Manual browser testing. Puppeteer/Playwright for F2E. | Content scripts, service worker (MV3), popup page, options page. Cross-browser API abstraction. | Store listing, permissions guide, feature docs, privacy policy. | Minimal — browser APIs. Polyfill for cross-browser support (webextension-polyfill). |
+| **H — Research / Notebook** | Data exploration, academic research, one-off analysis | Jupyter notebook, R Markdown, Quarto doc, MATLAB script, experimental Python script | Minimal to none. Visual inspection of outputs. Assertions in cells. | Single notebook or notebook + reusable scripts. No deployment. No production infra. | Notebook cell comments, README with reproduction steps. Dataset provenance. | Permissive — pandas, numpy, matplotlib, torch, scipy, tidyverse. Whatever is needed. |
+| **I — IoT / Embedded** | Firmware, device software, real-time systems | Sensor firmware, motor controller, smart home device, drone flight controller, RTOS application | Hardware-in-the-loop testing. Simulation for CI. Manual device testing essential. | HAL, RTOS tasks, driver layer. Memory-constrained. Real-time constraints. | Pinout docs, protocol specs, register maps. Datasheet references. | Minimal or zero std. Vendor SDKs. No dynamic allocation. Cross-compilation toolchain. |
+
+```
+ASK: "What kind of project are you building?"
+RECORD: purpose = [A | B | C | D | E | F | G | H | I]
+NOTE: purpose determines the weight of each principle below.
+```
+
+After the user picks their purpose, ask about monorepo:
+
+```text
+ASK: "Is this a multi-project monorepo with different purposes?
+      (e.g., a repo containing a web app + mobile app + shared library)
+      [yes | no]"
+
+IF yes:
+  NOTE: "Multi-project monorepo detected. The constitution will define
+         each sub-project separately under a 'Projects' section."
+
+  ASK: "How many sub-projects does this monorepo contain?"
+  RECORD: sub_project_count = [N]
+
+  FOR each sub-project (1 to N):
+    ASK: "Sub-project [N] name? (e.g., 'frontend', 'mobile-app', 'shared-lib')"
+    RECORD: sub_project_name = [name]
+
+    RUN Levels 1-3 for this sub-project independently:
+      ASK its purpose (can differ per sub-project)
+      ASK its architecture (can differ)
+      ASK its tech choices
+
+  AFTER all sub-projects defined, the constitution will contain a
+  'Projects' table at the top, and shared principles will be determined
+  by the PRIMARY sub-project (the largest or most important one).
+
+  IF monorepo:
+    MODE = monorepo
+    PRIMARY purpose = [chosen by user]
+
+---
+
+#### Level 2 — Architecture Approach
+
+Based on the chosen purpose, present the architecture options:
+
+LOAD the Level 2 architecture tables for each purpose from `spec-kit/references/constitution-tables.md`
+
+```
+ASK: "Given your purpose [A|B|C|D|E|F|G|H|I], which architecture approach fits?"
+RECORD: architecture = [A1|A2|A3|A4 | B1|B2|B3 | C1|C2|C3 | D1|D2|D3 | E1|E2|E3|E4 | F1|F2|F3 | G1|G2|G3 | H1|H2|H3 | I1|I2|I3]
+```
+
+---
+
+#### Level 3 — Technology Choices
+
+Based on purpose + architecture, guide the user through technical choices.
+For each choice, present 3 options using the project-type-aware defaults
+from the tables below.
+
+LOAD the Level 3 technology choice brackets for each purpose from `spec-kit/references/constitution-tables.md`
+
+For each bracket, present the specific language options as follows:
+
+```
+  | Option | Language | Framework suggestions | Pros | Cons |
+  |--------|----------|----------------------|------|------|
+  | A | [lang] | [framework list] | [pros] | [cons] |
+  | B | [lang] | [framework list] | [pros] | [cons] |
+  | C | [lang] | [framework list] | [pros] | [cons] |
+
+  USER picks: [A | B | C]
+```
+
+After the user picks language + framework, use the **Brownfield Detection
+Examples table** from `spec-kit/references/constitution-tables.md` to find the matching row
+and pre-fill recommended defaults for the remaining principles.
+
+If the user's exact combination isn't in the table, infer from the closest
+match:
+- Same language + similar framework → use that row
+- Same purpose category → use generic defaults for that purpose
+
+---
+
+#### Step 2c: Default Mapping — Purpose to Principle Weights
+
+Once purpose + architecture are chosen, map them to recommended defaults
+for the 12 principles. These are weighted suggestions — the user still
+picks A/B/C in Step 3.
+
+```
+PURPOSE = A (User-Facing App):
+  Testing → A or B (TDD important for reliability)
+  Linting → B (Pragmatic — balance quality and speed)
+  Architecture → user's choice from Level 2
+  Dependencies → B (Curated — need frameworks)
+  Git Workflow → B (Feature branches — standard)
+  Documentation → B (Critical-only — API docs + setup)
+  Error Handling → A (Defensive — user-facing app)
+  Performance → B (Profile-then-optimize)
+  Code Review → A or B (Strict or Risk-based)
+  Database → A (Migration-first — if using DB)
+  Config/Secrets → B (Environment-based)
+  Dev Toolchain → B (Standard toolchain)
+
+PURPOSE = B (Content Site / Marketing):
+  Testing → C (Test-After — no business logic to test, visual QA only)
+  Linting → B (Pragmatic — template code needs flexibility)
+  Architecture → user's choice from Level 2
+  Dependencies → B (Curated — SSG framework + maybe CMS client)
+  Git Workflow → A (Trunk-based — content changes should ship fast)
+  Documentation → B (Critical-only — build/deploy instructions + content guide)
+  Error Handling → C (Minimal — static sites have no runtime errors)
+  Performance → C (Ignore-until-painful — SSG output is inherently fast)
+  Code Review → C (Post-merge — content edits shouldn't block)
+  Database → SKIP (no database on content sites)
+  Config/Secrets → C (Config-in-repo — build config is part of the source)
+  Dev Toolchain → B (Standard toolchain — SSG, asset pipeline, CDN deploy)
+
+PURPOSE = D (Library / SDK):
+  Testing → A (Strict TDD — API surface must be tested)
+  Linting → A (Strict — public API consistency)
+  Architecture → user's choice from Level 2
+  Dependencies → A or B (Minimal or Curated)
+  Git Workflow → B (Feature branches)
+  Documentation → A (Exhaustive — API docs mandatory)
+  Error Handling → B (Contract-based — surface errors cleanly)
+  Performance → B (Profile-then-optimize)
+  Code Review → A (Strict — every change reviewed)
+  Database → SKIP (libraries shouldn't dictate storage)
+  Config/Secrets → A (Strict — secrets never in lib)
+  Dev Toolchain → B (Standard toolchain)
+
+PURPOSE = E (Infrastructure / CLI / DevOps):
+  Testing → B (Pragmatic — integration-heavy)
+  Linting → A (Strict — CLI UX consistency)
+  Architecture → user's choice from Level 2
+  Dependencies → A (Minimal — static binaries)
+  Git Workflow → A (Trunk-based — fast iteration)
+  Documentation → C (Code-as-docs — help text + README)
+  Error Handling → C (Minimal — propagate, top-level catch)
+  Performance → A (Optimize-first — CLI responsiveness)
+  Code Review → B (Risk-based — config changes vs engine)
+  Database → SKIP (infra tools shouldn't depend on DB)
+  Config/Secrets → A (Strict — env + config files)
+  Dev Toolchain → C (Full DX — automation matters)
+
+PURPOSE = F (Game):
+  Testing → C (Test-After — playtesting and visual QA dominant)
+  Linting → B (Pragmatic — engine code needs flexibility)
+  Architecture → user's choice from Level 2
+  Dependencies → C (Permissive — engines, assets, middleware, audio libs)
+  Git Workflow → B (Feature branches — asset changes need review)
+  Documentation → B (Critical-only — design doc + mechanics + API)
+  Error Handling → A (Defensive — game crashes ruin UX)
+  Performance → A (Optimize-first — frame budget is hard limit)
+  Code Review → B (Risk-based — gameplay logic vs asset changes)
+  Database → SKIP (save systems are engine-managed or custom binary)
+  Config/Secrets → C (Config-in-repo — game config is part of the game)
+  Dev Toolchain → C (Full DX — asset pipeline, build chain, packaging)
+
+PURPOSE = I (IoT / Embedded):
+  Testing → C (Test-After — hardware testing dominates)
+  Linting → A (Strict — firmware bugs are expensive, no OTA)
+  Architecture → user's choice from Level 2
+  Dependencies → A (Minimal — no stdlib, no heap, vendor SDK only)
+  Git Workflow → A (Trunk-based — most constrained, fast iteration)
+  Documentation → A (Exhaustive — pinouts, registers, protocols)
+  Error Handling → A (Defensive — watchdog, brownout, fail-safe)
+  Performance → A (Optimize-first — memory and cycles are hard limits)
+  Code Review → A (Strict — hardware damage risk, no hotfix possible)
+  Database → SKIP (no database on embedded devices)
+  Config/Secrets → B (Environment-based — compile-time flags, EEPROM)
+  Dev Toolchain → C (Full DX — cross-compiler, flashing, logic analyzer)
+
+PURPOSE = C (Native / Desktop Client):
+  Testing → B (Pragmatic — UI tests for critical paths, manual QA for visual)
+  Linting → B (Pragmatic — platform SDKs have their own conventions)
+  Architecture → user's choice from Level 2
+  Dependencies → B (Curated — platform SDK + UI framework, minimize transitive)
+  Git Workflow → B (Feature branches — release management matters)
+  Documentation → B (Critical-only — user-facing help + setup + store listing)
+  Error Handling → A (Defensive — app crashes cause user frustration)
+  Performance → B (Profile-then-optimize — startup time, frame drops, memory)
+  Code Review → A (Strict — app store review failures are costly)
+  Database → SKIP (local storage is platform-managed: Core Data, Room, SharedPrefs)
+  Config/Secrets → B (Environment-based — build flavors, feature flags, remote config)
+  Dev Toolchain → C (Full DX — build pipeline, code signing, app store deploy)
+
+PURPOSE = G (Browser Extension):
+  Testing → C (Test-After — manual browser testing dominates)
+  Linting → B (Pragmatic — content scripts need browser API flexibility)
+  Architecture → user's choice from Level 2
+  Dependencies → A (Minimal — browser APIs preferred, avoid bloating extension)
+  Git Workflow → B (Feature branches — store release cycles)
+  Documentation → A (Exhaustive — store listing, permissions, privacy policy mandatory)
+  Error Handling → A (Defensive — broken extension in user's browser is invisible failure)
+  Performance → A (Optimize-first — content script perf impacts every page user visits)
+  Code Review → A (Strict — privileged API misuse can cause account/data theft)
+  Database → SKIP (storage API is browser-provided)
+  Config/Secrets → A (Strict — API keys, tokens must never be in extension code)
+  Dev Toolchain → B (Standard toolchain — build, zip, upload to stores)
+
+PURPOSE = H (Research / Notebook):
+  Testing → C (Test-After — visual inspection of outputs, assertions in cells)
+  Linting → C (Minimal — notebooks are exploratory, not production code)
+  Architecture → user's choice from Level 2
+  Dependencies → C (Permissive — use whatever lib the analysis needs)
+  Git Workflow → A (Trunk-based — research is fast iteration, no release branches)
+  Documentation → B (Critical-only — reproduction steps + dataset provenance)
+  Error Handling → C (Minimal — errors are part of exploration, top-level catch)
+  Performance → C (Ignore-until-painful — correct analysis first, optimize if needed)
+  Code Review → C (Post-merge — notebooks are exploratory, not approval-gated)
+  Database → SKIP (research uses files, not databases)
+  Config/Secrets → C (Config-in-repo — dataset paths, API keys in .env.example)
+  Dev Toolchain → A (Minimal — just a notebook runtime, no build pipeline)
+```
+
+Present these as a summary table to the user:
+
+```
+  Based on your choices (Purpose: [name], Architecture: [name]), here are
+  the recommended defaults for each principle:
+
+  | Principle | Recommended | Why |
+  |-----------|-------------|-----|
+  | Testing   | ⭐ [option] | [reason] |
+  | Linting   | ⭐ [option] | [reason] |
+  | ...       |             |      |
+
+  Say 'bugfix [feature]' to start a new bugfix round.
+```
+
+Then proceed to Step 3 to let the user confirm or adjust each principle.
+
+---
+
+### Step 2d: Load the principles reference (both modes)
+
+```
+LOAD spec-kit/references/constitution-principles.md
+
+This reference defines 12 principles, each with 3 options (A/B/C).
+Each option has a rule, pros, and cons.
+
+FOR each principle:
+  READ the 3 options
+  IF MODE == brownfield:
+    SELECT the option that best matches detected project artifacts
+    TAG it with ⭐ "detected"
+  IF MODE == greenfield:
+    USE the pre-filled mapping from Step 2c
+    TAG the recommended option with ⭐ "recommended for [purpose]"
+```
+
+### Step 3: Present each principle with choice
+
+**For each principle, present the 3 options as a formatted table.**
+Always show pros and cons. Never skip the choice — even if a detected default
+exists, the user may disagree.
+
+```
+PRESENT for each principle:
+
+  ## Principle N: [Name]
+
+  | Option | Rule | Pros | Cons |
+  |--------|------|------|------|
+  | ⭐ A — [Name] *(detected)* | ... | ... | ... |
+  | B — [Name] | ... | ... | ... |
+  | C — [Name] | ... | ... | ... |
+
+  The ⭐ marker means this was auto-detected from your project files.
+  Pick A, B, or C (or type 'skip' to use detected default).
+
+  USER picks: [A | B | C | skip]
+  RECORD the chosen option
+  ASK: "Any notes or rationale for this choice?" → RECORD as rationale
+```
+
+In greenfield mode, after showing the 3 options, include the purpose-based
+recommendation from Step 2c instead of a generic guiding question:
+
+```
+  ⭐ This option is recommended for [purpose name] projects because
+     [reason from Step 2c mapping].
+  You can still pick A, B, or C — this is a recommendation, not a requirement.
+
+  USER picks: [A | B | C]
+  RECORD the chosen option
+  ASK: "Any notes or rationale for this choice?" → RECORD as rationale
+```
+
+### Step 4: Handle principle exceptions
+
+```
+IF project has no database (no DB config, no ORM, no schema files):
+  SKIP Principle 10 (Database & Schema)
+  NOTE: "Skipping Database principle — no database detected."
+```
+
+### Step 5: Write the constitution
+
+```
+COPY spec-kit/templates/constitution-template.md → specs/constitution.md
+
+FILL each section with:
+  - Chosen option letter and name
+  - Full rule text from the reference
+  - Recorded rationale
+  - Rejected alternatives table with reasons
+
+IF MODE == monorepo:
+  FILL the Projects table at the top with each sub-project's:
+    - Name, Purpose, Language/Framework, Architecture option
+  SHARED principles apply to the PRIMARY sub-project
+  NOTE per principle: "Applies to all sub-projects. Project-specific
+    variations documented in the Projects section."
+
+ELSE (single project):
+  INCLUDE in the Tech Stack section:
+    - Detected language/framework (brownfield) or "New project — TBD" (greenfield)
+    - Test framework, CI, package manager
+```
+
+### Step 6: Version management
+- **MAJOR** (1.x.x → 2.0.0): Backward-incompatible governance changes
+- **MINOR** (x.1.x → x.2.0): New principles
+- **PATCH** (x.x.1 → x.x.2): Clarifications
+
+
+### MCP state sync (optional, when MCP server is configured)
+
+After writing the file and before committing, confirm it with the project-level
+tool (the server checks that specs/constitution.md exists; it stores nothing):
+
+```text
+CALL mcp_spec_kit_project_set_constitution(status="present", principles='{"key": "value", ...}')
+# principles is optional — echoed back after JSON validation
+```
+
+### Commit
+
+The constitution is project-level: commit directly per `spec-kit/references/commits.md` — `spec(phase-0): constitution for [PROJECT]`.
+
+## Completion
+- Report: "Constitution ratified with [N] principles."
+- Report mode: brownfield, free-text, or wizard (greenfield)
+- If free-text mode: Show which purpose/architecture/tech were inferred from user's description
+- List all chosen options (A/B/C per principle)
+- List any principles skipped with reason
+- Propose: Run `spec-kit-specify` to create the first feature specification.
+
+LOAD the Brownfield Detection Examples table from `spec-kit/references/constitution-tables.md`
+
+## Common Pitfalls
+1. **Skipping the choice dialog**: Always present ALL 3 options with pros/cons.
+   The user needs to understand tradeoffs to make an informed decision.
+2. **Burying detected defaults**: In brownfield mode, show ⭐ clearly but let the
+   user override. Detection is guidance, not dictation.
+3. **Assuming all 12 principles apply**: Skip Database principle for stateless
+   projects. Skip Code Review for solo projects (but mentioning it is still useful).
+4. **Overwriting an existing constitution**: Always check first. Constitution is
+   one-time setup. If the user wants to amend, offer to add principles with
+   version bump.
+
+## Prerequisite Enforcement
+**No prerequisites** — this is Phase 0.
diff --git a/src/references/skills/spec-kit-implement.md b/src/references/skills/spec-kit-implement.md
new file mode 100644
index 0000000..4bb3e7b
--- /dev/null
+++ b/src/references/skills/spec-kit-implement.md
@@ -0,0 +1,62 @@
+# spec-kit-implement — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## The phase cycle
+```
+Phase N (Setup → Foundational → stories → Polish; S: the one flat list is one phase)
+═══ RED ═══   for each [TEST] task: write it (one behaviour per test; real code, not mocks,
+              unless unavoidable; behaviour, not implementation) → run it → it FAILS because
+              the feature is missing (not a typo). tee → evidence/-red.txt (every tier)
+              then mcp_spec_kit_acceptance_freeze(feature)   # SHA of every [AC-###] test file
+═══ SEAMS ═══ for each [SEAM] task: read-only probe of the real system/data FIRST
+              → evidence/-probe-.txt (command + result); the fixture has the SAME
+              shape (columns, rows per key, types). A hand-built fixture without a probe is how
+              a fix passes green and fails in production. All sizes.
+═══ GREEN ═══ for each code task: the simplest code that passes (hardcode now, refactor in
+              Polish). Then run ONLY this phase's tests (tee → evidence/-green.txt);
+              run the build — TypeScript MUST compile (Vitest/Jest swallow type errors).
+═══ CLOSE ═══ tasks [X] · fixed bugs → claimed + Evidence · history ON: entry
+              (mcp_spec_kit_append_history: "Phase 4 — ", agent = Implemented-by, evidence files)
+              history OFF: "**Implemented-by**: " in the tasks.md header (first phase only),
+              evidence files named in the commit body
+              · mcp_spec_kit_history_guard + mcp_spec_kit_lint_artifacts
+              · ONE commit "feat: [feature] Phase N - [name]"
+```
+- A frozen `[AC-###]` test that "needs" editing to go green means the code or the spec is wrong:
+  STOP and ASK; a refreeze needs the user's ruling (`acceptance_freeze refreeze=true reason=…`).
+- TDD bypassed (`tasks.md` header): implement and verify manually per task; the acceptance tests
+  are written after the code and frozen at the first acceptance round.
+- Legacy code without tests: characterisation test first (`evidence/-characterisation.txt`),
+  then change it. Untestable (visual, race, external) → note beside the task; the close flags it.
+- Re-run: find the first incomplete phase, resume at its RED; keep earlier `[X]` marks.
+- After compaction or at every sub-phase start: `mcp_spec_kit_get_next_actions` (the phase card).
+
+## Bugfix mode (BF-### tasks)
+```
+0. READ  — the code of the bug area; cross-check the bugs.md Plan Ref against what the code
+           really does. Contradiction → STOP, flag it. (Never fix from the report alone.)
+1. RED   — a test that reproduces the bug; run → fails
+2. GREEN — minimal fix; run → passes; evidence/BF-###-green.txt (all sizes — it is the claim);
+           probe per seam touched → evidence/BF-###-probe-.txt
+3. CLAIM — bugs.md Status: claimed + Evidence: … (never verified)
+4. HISTORY entry (phase "BF-###") → guard → COMMIT "fix: [feature] BF-### - description"
+```
+New bug found mid-fix → log it (`mcp_spec_kit_next_id(kind="BUG")`, inserted before the
+Summary separator), do not fix inline; say "BUG-NNN logged — address via 'bugfix' after this
+round". Trivial test-only fixes (missing assertion, wrong fixture) may be fixed inline.
+**Quickfix** (`quickfix [feature]`, explicit opt-in): plan section + task + fix in ONE commit
+`fix: [feature] BF-### - description (plan+tasks+fix)`; the documents still exist; tests still written.
+
+## After the last phase
+- Spec has ACs → route `accept [feature]` (`spec-kit-test`): the full fast suites + this
+  feature's e2e specs, failures → bugs → bugfix chain → accept again. Build verification first.
+- Legacy spec without ACs → full suite → `evidence/regression-.txt` + `ci:` when a
+  pipeline exists (no pipeline → "unverified claim"); failures → classify NEW vs PRE-EXISTING,
+  one umbrella `BF-REGRESSION-001` task, fix, re-run, commit `fix: [feature] BF-REGRESSION-001 - fix regressions`.
+- `mcp_spec_kit_advance_phase(from_phase=4)`.
+
+## Guardrail
+Code-editing tools (`write_file`, `patch`, `terminal` for builds) are allowed ONLY here
+(including bugfix implementation). A bug mentioned by the user is logged (`spec-kit-test`)
+before it is fixed — never fixed directly.
diff --git a/src/references/skills/spec-kit-plan.md b/src/references/skills/spec-kit-plan.md
new file mode 100644
index 0000000..2c75389
--- /dev/null
+++ b/src/references/skills/spec-kit-plan.md
@@ -0,0 +1,46 @@
+# spec-kit-plan — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Context
+Load `spec.md`, `specs/constitution.md` (guidance, not a gate), and the codebase: existing
+layers, DI style, test harnesses, naming. The plan reuses what exists before inventing.
+`plan.md` present and not bugfix mode → BLOCK (No Complete Overwrite → `bugfix` / `reopen`).
+
+## By tier (`spec-kit/references/sizing.md`)
+- **S**: Summary · Current Design placeholder · the Technical Context lines that matter · External
+  Seams · Acceptance Test Strategy · Rounds. No research / data-model / contracts / quickstart
+  unless the plan cannot be understood without one.
+- **M**: + Design section; research / data-model / contracts / quickstart only where the feature
+  needs them (a new entity → data-model; a new endpoint → contracts).
+- **L**: all that apply; research.md with decision → rationale → alternatives per real choice.
+Design bigger than the tier (new seam, third layer) → STOP, ASK to raise it; on approval edit
+the Size line, record the ruling.
+
+## Sections that matter most
+- **External Seams**: every DB function / view, HTTP contract, message, file format, external
+  service — with what a read-only probe should query. Implement refuses a fixture without one.
+- **Acceptance Test Strategy** (`spec-kit/references/acceptance.md` §2): per AC the level,
+  harness, test file, environment (none / Docker / running stack), result source (TRX / JUnit
+  path or command). A level with no harness yet → a Setup task, or ASK to change the level.
+- **Security & Privacy** answers from the spec → where the check lives (policy, filter, validator,
+  log scrubber) — one line each in Design.
+- Constitution gates (simplicity, anti-abstraction, integration-first): violations justified in
+  Complexity Tracking, never silently.
+
+## Decisions
+ASK the user for choices they would want to make (behaviour, scope, user-visible trade-offs);
+no human → `decisions.md` assumption with the alternative not taken. Design choices inside the
+plan's remit (which component, which helper, which test layout) are plan.md content — not
+assumptions, not rulings.
+
+## Bugfix mode
+Per open bug: root cause from the code (not the report alone) → ONE dated round appended under
+`## Rounds (ADR log)`: `### Round N —  —  — supersedes: <§ or nothing>` with
+Context / Decision / Consequences / Plan Ref → set `Plan Ref` in `bugs.md`. Never edit earlier
+rounds or `## Current Design` (the close regenerates it); a contradiction with the current
+design → say so in *supersedes* and ASK. Then route `spec-kit-tasks` automatically.
+
+## MCP, then commit
+`mcp_spec_kit_update_artifact(plan.md)` · `mcp_spec_kit_advance_phase(from_phase=2)` ·
+`mcp_spec_kit_lint_artifacts` · commit per `spec-kit/references/commits.md`.
diff --git a/src/references/skills/spec-kit-review.md b/src/references/skills/spec-kit-review.md
new file mode 100644
index 0000000..86d9041
--- /dev/null
+++ b/src/references/skills/spec-kit-review.md
@@ -0,0 +1,115 @@
+# spec-kit-review — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Mode detection
+```
+close doc exists                                  → closed-review (report only, no round)
+tasks.md exists AND no implementation code        → pre-implement
+every task [X] AND code AND no close doc          → bugs.md open/in-progress? REFUSE ("bugfix first") : final
+both match → ASK which; undetermined → ASK
+```
+SIZE from spec.md. REVIEWED_COMMIT = `git rev-parse --short HEAD` before anything else.
+BASE = merge-checklist `base_branch`, else `branch_source` in git-conventions, else main.
+
+## Reviewer
+`Implemented-by` = the `` of the implement entries in `history.md`, or the
+`**Implemented-by**:` line in the tasks.md header when history is off for the feature.
+Another agent available → it reviews → `review:`. Else (Claude Code: the Agent tool) a
+**fresh-context sub-agent** given ONLY this procedure, the feature path, BASE and the project
+rule files — never the implementation transcript → `self-review by  (fresh context: yes)`.
+Else `self-review by `. A self-review opens the merge gate; it never verifies a bug.
+**Order of reading for the final review**: diff and spec first, acceptance.md, then plan, then
+`decisions.md` last — so the author's rationale does not anchor the verdict.
+
+## Pre-implement (3.5)
+Scope: this feature only. Out of scope (note under "Project-level notes", no severity): missing
+constitution or CI, pre-existing debt elsewhere, broad stack opinions, taste.
+
+| Pass | M (lite) | L |
+|------|----------|---|
+| Coverage: every FR / story / SC / AC → a task; tasks → a requirement | ✓ | ✓ |
+| Underspecification: verbs without measurable objects; vague adjectives; placeholders | ✓ | ✓ |
+| Codebase fit: existing patterns, abstractions reused, integration points, paths match layout | ✓ | ✓ |
+| Design soundness: abstraction level, data flow traceable, error-handling strategy, next 2–3 features | ✓ | ✓ |
+| Security & Privacy: each spec row has a design answer in the plan | ✓ | ✓ |
+| Duplication, ambiguity, naming drift, completeness, inconsistency | | ✓ |
+| Best practice: research current guidance for each major technology / pattern | | ✓ |
+| Bugfix coverage (bugfix mode): every open bug → BF task + verifying test | ✓ | ✓ |
+
+**Devil's advocate** (M: a separate pass by the same reviewer; L: a separate sub-agent, a
+different model when available, briefed with the plan and the code — not the review so far):
+1. the strongest case against the plan, and the simplest alternative delivering ~80 % of the value;
+2. pre-mortem — "it is three months later and this failed in production; why?";
+3. abuse cases per new seam: another tenant's id, unauthorized role, oversized / malformed input,
+   data exposure in a response or a log, replay / concurrency;
+4. the riskiest assumptions in decisions.md — which would hurt most if wrong.
+≤ 5 objections with a concrete scenario each; the author answers every one (accepted →
+task / spec change; rebutted with evidence; deferred → follow-up). Unanswered → the report says so.
+
+Severity: CRITICAL (zero coverage, architecture violation, security, data integrity) · HIGH
+(maintainability pain, pattern misalignment, missing error chain) · MEDIUM (drift, non-functional
+gap) · LOW → do not report. Report: findings table, coverage table, codebase-fit assessment,
+devil's-advocate table, metrics. CRITICAL → resolve before implement.
+
+## Final (5.5)
+```
+LOAD spec (FR/SC/ACs/edge cases), plan (Current Design, seams), tasks, data-model, contracts,
+     acceptance.md (latest round), bugs.md, evidence/, constitution (MUSTs for the touched
+     layers), specs/merge-checklist.md (missing → from the template, ASK to confirm), AGENTS.md
+     + agent rule files, linter configs; decisions.md LAST
+RUN  git diff --stat BASE...HEAD; git diff BASE...HEAD -- . ':(exclude)specs'
+MECHANICAL  mcp_spec_kit_diff_scan(feature, base=BASE) → evidence/final-diff-scan.txt
+            (no MCP: git merge-tree, grep the added lines for secrets / conflict markers /
+            focused tests / TODO, list forbidden and > 1 MB files, unplanned files)
+            every merge-checklist command → evidence/final-.txt; a command that cannot
+            run = ❌ unverified with the reason, never assumed green; ci: for REVIEWED_COMMIT
+§1  spec has ACs → latest acceptance round PASS and not stale (else NOT READY: "run accept");
+    frozen tests unchanged. Deferred e2e → run now if the stack is up (evidence/final-AC-###.txt)
+    else 👤; manual ACs → the user's quoted words or 👤.
+    For each FR / SC / edge case: find the code (path:line) and the proving test — write ONLY
+    the rows that are not ✅ (⚠️ partial / unproven · ❌ missing = CRITICAL · ↔ deviates · 👤).
+    Contracts and data-model vs code; unplanned files / behaviour → scope creep (HIGH if it
+    changes behaviour).
+§2  every applicable constitution MUST, merge-checklist P-item, AGENTS.md / rule-file rule and
+    each non-empty spec Security & Privacy row → ✅ / ❌ with path:line; n/a rows one line.
+    Violated MUST = HIGH; CRITICAL when security, data or a declared non-negotiable.
+§3  on the changed code: architecture conformance, error chains (nothing swallowed, no internals
+    leaked), security (secrets, injection, authz, tenant / ownership, unvalidated input),
+    data integrity (transactions, races, migrations), concurrency, structural duplication,
+    complexity (> ~100-line functions, deep nesting), API surface. Stack practice: M/L.
+    Tests: assert §1 behaviour; edge cases; every [SEAM] fixture matches its probe (missing = HIGH);
+    RED + GREEN file per implement phase; acceptance round present with every AC's outcome
+    (manual ACs → the user's quoted confirmation, else 👤).
+§4  devil's advocate (final): concrete break attempts — another tenant's id, empty / stale /
+    boundary period, concurrent edit, failing dependency, unauthorized role, oversized input;
+    "would this test still pass if the code were wrong?"; argue the opposite verdict.
+    L: a separate sub-agent that reads the code and the spec, not this round. ≤ 5 objections,
+    each answered (accepted → bug / rebutted with evidence / deferred); unanswered blocks READY for L.
+§5  checklist: every G-item and P-item with ✅ / ❌ and its evidence file.
+VERDICT  CRITICAL / HIGH or blocking ❌           → NOT READY
+         no defect, owner confirmations pending   → AWAITING-OWNER   (👤 rows, ↔ rulings)
+         only MEDIUM / non-blocking ❌             → READY-WITH-FOLLOWUPS
+         else                                     → READY
+§6  bugs for CRITICAL / HIGH / blocking failures (spec-kit-test format, mcp_spec_kit_next_id,
+    confirm each with the user); MEDIUM → follow-ups; ↔ deviations → WAIT: patch spec/plan
+    (intentional) / log a bug / defer to close; PR description: what / why / how verified /
+    risks / rollback / strongest objections and how they were answered
+```
+An unverified blocking item is ❌ unless the user accepts the risk in writing (quote in
+decisions.md and the round). A code commit after Reviewed-commit makes the round stale; a
+specs-only commit (the owner's answers, Round N+1) does not.
+
+**Nitpick filter**: formatting, import order, naming that is clear, 2–3-line repetition,
+micro-optimisations without a measured problem, edge cases the spec does not require → delete.
+"Is this in the top things that must change before merge?" — if not, it is not a finding.
+
+## Closed-review
+Same checks as final, written as a report; no round, no commit. CRITICAL / HIGH → offer:
+refactoring tasks in tasks.md + `reopen`, or note for future work — with the user's approval.
+
+## Commit
+History entry first (preflight commit procedure; closed-review: none). Pre: `spec(review): [feature]
+review findings`. Final: `mcp_spec_kit_lint_artifacts` (rounds need Verdict + Reviewed-commit) →
+`spec(review): [feature] final review (verdict: X)` — specs only, so the round stays fresh. Read-only on source code; writes only the report / round, evidence,
+bugs.md entries, approved spec/plan patches, merge-checklist.md on first use.
diff --git a/src/references/skills/spec-kit-specify.md b/src/references/skills/spec-kit-specify.md
new file mode 100644
index 0000000..75587ae
--- /dev/null
+++ b/src/references/skills/spec-kit-specify.md
@@ -0,0 +1,37 @@
+# spec-kit-specify — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Parsing the description
+Extract actors, actions, data, constraints. Short name = 2–4 word action-noun ("user-auth",
+"oauth2-api-integration"). Feature dir `specs/NNN-short-name/` with the next number; MCP
+`mcp_spec_kit_init_feature(feature, name)` creates it (and nothing else).
+
+## Writing the spec
+- User scenarios P1/P2/P3, each with an *independent test* line and its ACs.
+- FR-### testable and technology-agnostic: "System MUST …", "Users MUST be able to …". A simple
+  feature is one paragraph + 2–3 FRs — do not force the template.
+- Success criteria measurable (time, count, rate), entities domain-only.
+- **Security & Privacy table** — answer every row; the honest "None — because [reason]" is
+  the expected answer for most UI work; a non-empty row becomes a plan item and a final-review
+  §2 verdict.
+- `[NEEDS CLARIFICATION: …]` at most 3; more means the scope is too vague — ask first.
+
+## Acceptance criteria (`spec-kit/references/acceptance.md` §1)
+One observable outcome per AC, Given/When/Then, `Verify:` = the LOWEST level that proves it;
+`e2e` and `manual` need a reason in parentheses; ≤ 2 e2e per feature — prefer an integration
+test of the API plus a component test of the UI. Every FR named by ≥ 1 AC (lint warns).
+
+## The size question (always)
+```
+SCORE spec-kit/references/sizing.md signals → RECOMMENDED = highest tier triggered
+ASK "Size for [feature]?"  1.  (Recommended) —    2./3. the other tiers, one line each
+  (Claude Code: AskUserQuestion, recommended option first)
+WRITE **Size**:  —    RECORD the ruling in decisions.md (quote); unattended → assumption
+```
+Size S after the user confirms the spec: run `spec-kit-plan` (short) and `spec-kit-tasks` (flat),
+ONE commit `spec(phase-1-3): [feature] spec, plan, tasks`.
+
+## MCP, then commit
+`mcp_spec_kit_update_artifact(spec.md)` · `mcp_spec_kit_advance_phase(from_phase=1)` (returns the
+phase card) · `mcp_spec_kit_lint_artifacts` → 0 errors · commit per `spec-kit/references/commits.md`.
diff --git a/src/references/skills/spec-kit-summarize.md b/src/references/skills/spec-kit-summarize.md
new file mode 100644
index 0000000..0601e96
--- /dev/null
+++ b/src/references/skills/spec-kit-summarize.md
@@ -0,0 +1,109 @@
+# spec-kit-summarize — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Gate
+```
+review-final.md latest round: missing → BLOCK "run the final review"
+  NOT READY → BLOCK "bugfix, then re-review" · AWAITING-OWNER → BLOCK "get the owner's answer, Round N+1"
+  code changed after Reviewed-commit (git log ..HEAD -- . ':(exclude)specs') → BLOCK "re-review"
+bugs.md open / in-progress → BLOCK "bugfix"
+mcp_spec_kit_get_feature_state → state.final_review / acceptance say the same
+```
+Mode: "close" / "summarize" as said; else S/M → close, L → summarize (full gap table). Output
+depth follows `git diff {branch_source} --name-status`, not the size of the spec: few files →
+short; a single bugfix → one paragraph (root cause + fix). Every sentence reflects the diff.
+
+## Gap analysis
+```
+FOR each FR / story / SC / entity / contract (M: only the ones that are not ✅; L: all):
+  ✅ Resolved — as planned (code + test + evidence named)  |  ✅ Resolved — intentional deviation (rationale)
+  ⚠️ Acknowledged — deferred, reason and who decided        |  ❌ Not Done — missing, no reason → bug
+health = round((resolved + acknowledged) / total × 100); total 0 → 100
+Reuse review-final §1 rows and the acceptance matrix — do not re-derive them.
+```
+Deviations → propose each spec.md / plan.md / data-model.md patch ("(Updated at close)"); WAIT;
+rejected → ⚠️ needs review in Artifact State. Regenerate `plan.md` → `## Current Design` (≤ 1
+page, what is BUILT; rounds untouched).
+
+## Evidence table
+Acceptance / regression `output:` + `ci:`; a `probe:` per seam in the plan or the diff;
+`Implemented-by` from the history.md implement entries (or the tasks.md header when history is off) and the review label from review-final.md. No oracle → ❌
+unverified — never omitted, never upgraded. `claimed` bugs without `Verified-by` → *Unverified
+claims*; the feature may still close, saying so.
+
+## ADRs
+```
+ADR_DIR = git-conventions adr_dir | mcp_spec_kit_next_id(kind="ADR").adr_dir | first of docs/adr,
+          docs/decisions, doc/adr, adr | none → ASK to create (default docs/adr + README index);
+          declined → every candidate feature-local
+INDEX + TEMPLATE = the project's (README/index.md "## Template", else the newest ADR's shape,
+          else spec-kit/templates/adr-template.md); follow the index's rules
+HARVEST  decisions.md rulings (+ confirmed assumptions) · plan Rounds and design decisions ·
+         research decisions · review findings that changed the design · approved deviations ·
+         the diff (new dependency / pattern / boundary nobody wrote down)
+BAR (any): constrains code beyond this feature · expensive to reverse (schema, contract, data
+         ownership, platform, dependency) · chooses between real alternatives a reader would
+         re-litigate · changes or contradicts an existing ADR · AGENTS.md / constitution would
+         otherwise be wrong.   Feature-local (component name, helper, test layout) → plan.md.
+PER candidate passing the bar: same decision exists → append Evidence / Related; contradicts an
+         Accepted ADR → new ADR "supersedes NNNN" + the old status line "Superseded by ";
+         narrows / extends → "amends NNNN"; else new. PRESENT (number, title, Decision, action,
+         origin) → WAIT → write (Status Accepted + date + quoted ruling as Deciders, or Proposed)
+         or "feature-local (declined)". Update the index. Fill the close's table; "none met the
+         ADR bar" is a row — the section is never omitted (close_feature checks it).
+```
+
+## AGENTS.md
+For AGENTS.md and files restating it (CLAUDE.md, .github/copilot-instructions.md, .claude/rules/*,
+.cursor/rules/*): which statements does the diff, a new / superseded ADR, or resolved debt make
+WRONG or INCOMPLETE — commands, layout, boundaries, versions, dependencies, conventions, known
+debt, ADR list, the spec-kit block. No narrative, no changelog. Targeted patch per section →
+WAIT → apply approved ones only. Record "updated — " or "no change needed — ".
+
+## Runbooks and changelog (optional — only what the project keeps)
+```
+RUNBOOKS = git-conventions runbooks_dir (absent → skip): grep the runbooks for commands, settings,
+  endpoints, procedures the diff changed → targeted patch per statement, WAIT, apply approved
+CHANGELOG = git-conventions changelog (absent → skip): under "## [Unreleased]" add ONE line in the
+  right group (Added / Changed / Fixed / Removed / Security): " ()" — never
+  a feature narrative; the PR description already has that
+```
+
+## Design doc and epic row (optional — only what the project keeps)
+```
+DESIGN_DIR = git-conventions design_dir · EPICS_DIR = epics_dir   (absent → "none kept", skip)
+FOR each module in plan.md **Modules**:  DOC = DESIGN_DIR/.md
+  missing → NOTE "no design doc for  — run 'spec-kit design '" (never create it here)
+  else → which sections does the diff make wrong? components (paths), data flow, seams /
+         contracts, invariants & security, testing, known debt, Decisions (new ADRs)
+         → targeted patch per section, WAIT, apply approved; append "-   — "
+         to the change log; bump Last patched
+EPIC = spec.md **Epic**:  FILE = EPICS_DIR//features.md
+  missing → NOTE "spec names epic  but  does not exist — run 'spec-kit epic '"
+  else → set this feature's row: Status closed · PR · Health N% · ADRs; add the row if absent;
+         epics_index on (default) → update the epic's row in EPICS_DIR/README.md (features closed / planned);
+         every row closed or dropped → suggest "close epic "
+RECORD both outcomes in the close document (Artifact State) and in the change record (Decisions / follow-ups)
+```
+
+## Change record
+`spec-kit/templates/change-record-template.md` → `specs/[feature]/change-record.md`. Every field
+filled from what exists (spec Security & Privacy, size ruling, history.md, acceptance round,
+review round, decisions, ADRs) or written `pending` (PR reviewer, deployment approval) — never
+blank. Timeline: history on → one row per history.md entry (date, phase, agent, evidence, commit
+message); history off → `spec-kit/scripts/spec-kit-history.sh [feature]` (date · author · subject)
+run on the branch now, before the squash. The record is the one page an auditor reads and the
+one that survives the squash-merge.
+
+## Reopen
+Close doc exists → APPEND `## Reopened — ` (previous health → new health, changed
+artifacts, new gaps, decisions); the original close is never edited. A requirement that went
+from ✅ to worse → ASK: new entry (recommended) or overwrite.
+
+## Finish
+❌ Not Done gaps → `open` bugs (`mcp_spec_kit_next_id`). `mcp_spec_kit_update_artifact(close.md)` ·
+`mcp_spec_kit_close_feature` (errors: open bugs, verified without oracle, review missing / NOT READY /
+stale, no Architecture Decisions) · `mcp_spec_kit_lint_artifacts` · ONE commit
+`spec(phase-6): [feature] close (health: N%)` after the history entry (preflight commit procedure). Report: mode,
+health, tasks, bugs, patches, ADRs, AGENTS.md, change record.
diff --git a/src/references/skills/spec-kit-tasks.md b/src/references/skills/spec-kit-tasks.md
new file mode 100644
index 0000000..c383ec1
--- /dev/null
+++ b/src/references/skills/spec-kit-tasks.md
@@ -0,0 +1,39 @@
+# spec-kit-tasks — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Context
+Load plan, spec, data-model, contracts. `tasks.md` present and not bugfix mode → BLOCK (No
+Complete Overwrite). Bugfix mode → load tasks, bugs, the plan's rounds; append only.
+
+## TDD question
+ASK "Generate test tasks (TDD) or skip tests?" — every time. Skip → header
+`> **TDD**: Bypassed by user request` (the final review notes the weaker guarantee).
+
+## Layout
+- S: one flat list, `[TEST]` tasks first, then code. M/L: Setup/Foundational → one phase per
+  user story (its tests first) → Polish.
+- `T### [P] [US#] [TEST] [AC-###] [SEAM] Description — exact/path.ext` — no task without a path.
+- Tests are grouped by phase boundary, not 1:1 with code tasks: one test file may cover several
+  tasks; one task may need several tests.
+
+## Mapping
+```
+FOR each FR-### and user story: name the implementing task(s)
+FOR each AC with level unit / integration / component / e2e:
+  ≥ 1 "T### [TEST] [AC-###] … — "
+  in the phase that delivers it; the test NAME carries the id (AC003_… / 'AC-003 …' / test_ac003_…)
+FOR each command / probe AC: a task that writes the check, tagged [AC-###]
+FOR each seam in the plan's External Seams: [SEAM] on the task that touches it
+mcp_spec_kit_lint_artifacts → no "[AC-###] has no [TEST] task" error
+```
+
+## Bugfix mode
+Per open bug: `BF-### [TEST]` reproducing test + `BF-###` fix task, inserted BEFORE
+`## Dependencies & Execution Order`; never delete or renumber; duplicate id → ASK. Then route
+`spec-kit-implement` automatically.
+
+## Ids, MCP, commit
+`mcp_spec_kit_next_id(kind="T"|"BF")` (no MCP: highest + 1) · `mcp_spec_kit_update_artifact(tasks.md)`
+· `mcp_spec_kit_advance_phase(from_phase=3)` · `mcp_spec_kit_lint_artifacts` · commit per
+`spec-kit/references/commits.md`. Report: task count, phases, TDD mode, parallel and bugfix tasks.
diff --git a/src/references/skills/spec-kit-test.md b/src/references/skills/spec-kit-test.md
new file mode 100644
index 0000000..0287443
--- /dev/null
+++ b/src/references/skills/spec-kit-test.md
@@ -0,0 +1,53 @@
+# spec-kit-test — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+## Log before fix
+ALWAYS write the bug to `bugs.md` first, then HALT. Do not fix, plan or read source code; the
+user says `bugfix [feature]` to start the loop.
+
+## Bug entry
+```
+### BUG-NNN: [summary]
+- **Severity**: critical / major / minor / trivial   - **Area**: [spec section / component / AC-###]
+- **Description**: observed vs expected              - **Steps to Reproduce**: 1. … 2. …
+- **Actual Result** / **Expected Result**
+- **Requires Clarification**: [ ] no / [ ] yes        - **Plan Ref**: (filled by plan)
+- **Status**: open   - **Evidence**: (with claimed)   - **Verified-by**: (with verified)
+```
+Insert BEFORE the `---` that precedes `## Summary`; add the Summary row; fix the tallies.
+Confirm each entry with the user. Status vocabulary and the oracle rule:
+`spec-kit/references/evidence.md`.
+
+## Accept mode — one round (`spec-kit/references/acceptance.md` §5–6)
+```
+PREREQ: every task [X]; spec.md has ACs; lint shows no "has no [TEST] [AC-###] task" error
+N = rounds in acceptance.md + 1;  COMMIT = git rev-parse --short HEAD
+COMMANDS = specs/merge-checklist.md acceptance_* (missing → add from the template, ASK once)
+1. RUN acceptance_fast   (FULL unit + integration + component — also the regression)
+2. E2E_SPECS = this feature's [TEST] [AC-###] e2e files; run acceptance_e2e only if
+   acceptance_e2e_ready exits 0 — else those ACs are "deferred" (the final review handles them)
+3. command / probe ACs → evidence/acceptance-r-AC-###.txt ("RESULT: PASS|FAIL" first line)
+4. console → evidence/acceptance-r.txt (command + UTC time on top)
+5. mcp_spec_kit_acceptance_status(feature, results=, round=N)
+6. APPEND "## Round N —  — " to acceptance.md: Result, Commit, counts, matrix,
+   regressions, frozen changes, Next
+7. PASS → "route the final review" · STOPPED (frozen test changed) → ASK revert / refreeze
+   FAIL → per fail / missing AC and regression: an existing open/claimed bug names it → back
+   to open ("failed again in round N", append the new Actual); else a new bug — Severity major
+   (critical for security/data ACs), Area AC-###, Steps = Given/When, Actual = first failing
+   assertion, Expected = Then, Source: acceptance round N. No per-bug confirmation in the loop.
+   STOP and ASK when: N == acceptance_max_rounds · same ACs + same first assertion as round N-1 ·
+   the fix needs a spec or frozen-test change · the run could not execute twice.
+   Else hand to spec-kit-workflow 'bugfix [feature]', which routes 'accept' again after implement.
+```
+Loop-fixed bugs stay `claimed` (`Evidence: output:evidence/acceptance-r.txt`) until an oracle.
+
+## Verify
+Oracle required: the user's quoted words, a green `ci:` on that commit, or
+`review:`. The implementing agent's claim → refuse. Set `Status: verified` +
+`Verified-by:`. All verified and (no ACs or latest round PASS) → "run `final review [feature]`".
+
+## Commit
+`mcp_spec_kit_lint_artifacts` → 0 errors · `spec(phase-5): [feature] bug log` (accept mode:
+`spec(phase-5): [feature] acceptance round N (RESULT a/b)`) per `spec-kit/references/commits.md`.
diff --git a/src/references/skills/spec-kit-workflow.md b/src/references/skills/spec-kit-workflow.md
new file mode 100644
index 0000000..2eaefc4
--- /dev/null
+++ b/src/references/skills/spec-kit-workflow.md
@@ -0,0 +1,60 @@
+# spec-kit-workflow — full procedure
+
+> **Loaded on demand** — the one-screen SKILL.md is the entry point; this file holds only what it leaves out. Read the section you need. Hermes tools (`terminal`, `write_file`/`patch`, `read_file`, `search_files`, `skill_view`) map to Claude Code `Bash`, `Write`/`Edit`, `Read`, `Grep`/`Glob`, `Skill`; MCP `mcp_spec_kit_*` = `mcp__spec-kit__*`.
+
+Routing only — never execute a phase here. "bugfix" → the Bugfix section, not specify.
+
+## Bootstrap and phase detection
+`specs/constitution.md` missing → route `spec-kit-constitution`, HALT (once per session; features
+never check it again). Constitution principles are injected into phase skills as guidance, not gates.
+
+| Artifacts | Phase |
+|-----------|-------|
+| spec.md | Specified (1) · clarify.md → clarified |
+| plan.md | Planned (2) · tasks.md → tasked (3) · tasks with `[X]` → implementing (4) |
+| bugs.md with open bugs | bugfix loop (5) · only `claimed` → awaiting an oracle |
+| all tasks done, ACs, no fresh PASS round | **accept due** |
+| no open bug, acceptance PASS (or no ACs), no fresh READY round | **final review due** · AWAITING-OWNER → the owner's answers |
+| review-final READY / READY-WITH-FOLLOWUPS, fresh | **must close** |
+| close.md / implementation-summary.md | complete · + open bugs → reopened |
+
+Drift: a close doc with ⚠️ / ❌ artifact rows → "run `refresh [feature]`".
+
+## Prerequisites per skill
+specify none · clarify spec · plan spec · tasks spec + plan · review (pre) spec + plan + tasks ·
+review (final) every task `[X]`, no open bug, acceptance PASS · implement tasks · test spec ·
+summarize tasks + fresh READY final review · refresh spec.
+
+## Bugfix
+```
+bugfix [feature]:
+  close doc exists → "use reopen [feature]"
+  each open bug: Plan Ref missing → spec-kit-plan first (user confirms)
+                 Requires Clarification = yes → spec-kit-clarify first
+  AUTO-CHAIN spec-kit-plan → spec-kit-tasks → spec-kit-implement (no user choice; review on request)
+  implement done, spec has ACs → accept [feature] automatically
+quickfix [feature]: explicit opt-in only — plan section + task + fix in ONE commit; docs still exist
+test [feature]: logs and STOPS; new bugs mid-round wait for the next round
+accept [feature]: spec-kit-test accept mode → FAIL → bugfix (auto) → accept again … until PASS
+  or a stop condition (max rounds, no progress, spec / frozen-test change, run cannot execute) → ASK
+all bugs verified (oracle each) → suggest the final review, then close — never auto-close
+```
+
+## Reopen
+Needs a close doc. Branch `{original_prefix}/NNN-name{reopen_suffix}` per `specs/git-conventions.md`
+(default `-bugfixing`); `bugs.md` created if missing; the bugfix loop runs; the close APPENDS a
+dated section. A requirement that went from ✅ to ❌ → ASK before writing.
+
+## Guardrails
+| Phase | May write | Code tools |
+|-------|-----------|------------|
+| Specify / Clarify | spec.md, clarify.md, decisions.md | no |
+| Plan / Tasks | plan artifacts / tasks.md | no |
+| Review | report · review-final.md, evidence/final-*, bugs.md entries, merge-checklist.md (first use), approved spec/plan patches | runs build/test/lint only |
+| Implement (incl. bugfix) | source, tasks.md `[X]`, bugs.md → claimed, evidence/ | **yes** |
+| Test | bugs.md, acceptance.md, evidence/acceptance-* | no |
+| Summarize / Close | close.md, change-record.md, spec/plan/data-model patches (approved), ADRs + index, AGENTS.md patches, bugs.md gap bugs | no |
+| Refresh | spec/plan/data-model/contracts patches (per-item approval) | no |
+
+Unknown phase → ASK. Code outside Implement → refuse, name the phase. "[feature] is done" without
+a close doc → BLOCK "run close [feature]".
diff --git a/src/scripts/spec-kit-history.sh b/src/scripts/spec-kit-history.sh
new file mode 100755
index 0000000..e615cfc
--- /dev/null
+++ b/src/scripts/spec-kit-history.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# spec-kit-history.sh — a feature's timeline from the branch's git log, for the change record
+# when history.md is off (history: large / never). Run on the feature branch BEFORE the squash.
+# Usage: spec-kit-history.sh  []   → date | author | subject
+set -euo pipefail
+[ $# -ge 1 ] || { sed -n '2,4p' "$0"; exit 2; }
+feature="$1"; base="${2:-}"
+[ -d "specs/$feature" ] || { echo "specs/$feature does not exist" >&2; exit 1; }
+if [ -z "$base" ]; then
+  first="$(git log --reverse --format=%H -- "specs/$feature" | head -1)"
+  [ -n "$first" ] || { echo "no commits touch specs/$feature yet" >&2; exit 1; }
+  if git rev-parse -q --verify "$first^" >/dev/null 2>&1; then range="$first^..HEAD"; else range="HEAD"; fi
+else
+  range="$base..HEAD"
+fi
+git log --reverse --date=format:%Y-%m-%d --format='%cd | %an | %s' --grep="$feature" "$range"
diff --git a/src/scripts/spec-kit-log.sh b/src/scripts/spec-kit-log.sh
new file mode 100755
index 0000000..9e97733
--- /dev/null
+++ b/src/scripts/spec-kit-log.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# spec-kit-log.sh — append one fixed-field entry to specs//history.md
+# (the no-MCP fallback for mcp_spec_kit_append_history). Stamps the REAL UTC time.
+#
+# Usage:
+#   spec-kit-log.sh  ""   \
+#       [--artifacts "a, b"] [--tests "cmd → N passed"] [--evidence "output:…; ci:…"] \
+#       [--commit "message"] [--note "≤ 25 words"]
+set -euo pipefail
+if [ $# -lt 4 ]; then sed -n '2,9p' "$0"; exit 2; fi
+feature="$1"; phase="$2"; skill="$3"; agent="$4"; shift 4
+artifacts="" ; tests="none"; evidence="none — unverified"; commit=""; note=""
+while [ $# -gt 0 ]; do
+  case "$1" in
+    --artifacts) artifacts="$2"; shift 2 ;;
+    --tests)     tests="$2"; shift 2 ;;
+    --evidence)  evidence="$2"; shift 2 ;;
+    --commit)    commit="$2"; shift 2 ;;
+    --note)      note="$2"; shift 2 ;;
+    *) echo "unknown option: $1" >&2; exit 2 ;;
+  esac
+done
+file="specs/$feature/history.md"
+[ -d "specs/$feature" ] || { echo "specs/$feature does not exist" >&2; exit 1; }
+if [ "$(printf '%s' "$note" | wc -w)" -gt 25 ]; then echo "note exceeds 25 words — shorten it (narrative belongs in implementation-summary.md)" >&2; exit 1; fi
+[ -f "$file" ] || printf '# Process History: %s\n' "$feature" > "$file"
+ts="$(date -u +%Y-%m-%dT%H:%M:%S+00:00)"
+{
+  printf '\n## %s | %s | %s | %s\n' "$ts" "$phase" "$skill" "$agent"
+  printf -- '- Artifacts: %s\n' "${artifacts:-none}"
+  printf -- '- Tests: %s\n' "$tests"
+  printf -- '- Evidence: %s\n' "$evidence"
+  printf -- '- Commit: %s\n' "${commit:-n/a}"
+  printf -- '- Note: %s\n' "${note:--}"
+} >> "$file"
+echo "appended to $file at $ts"
diff --git a/src/skills/spec-kit-clarify.md b/src/skills/spec-kit-clarify.md
index 1d47133..52ec8ee 100644
--- a/src/skills/spec-kit-clarify.md
+++ b/src/skills/spec-kit-clarify.md
@@ -13,74 +13,21 @@ metadata:
 
 # spec-kit-clarify
 
-**Task Persona**: Adopt the mindset of a curious detail-gatherer. Ambiguities hide assumptions that cause rework. Ask precise, targeted questions. Probe edge cases, constraints, and unstated expectations. Do not proceed until the ambiguity is resolved — uncertain specs produce broken code.
+**Phase**: 1.5 (optional) · **Persona**: precise questioner — ambiguities hide assumptions that cause rework; never ask for the sake of process.
+**Purpose**: resolve underspecified areas of `spec.md` by a short Q&A logged in `clarify.md`.
+**Not for**: specs with no real ambiguity → `spec-kit-plan`.
 
-**Phase**: 1.5
+## Before writing
+- `spec-kit/references/preflight.md`. **BLOCK** if `spec.md` is missing. Load `spec.md`; bugfix mode: also the bugs flagged *Requires Clarification*.
 
-**Purpose**: Identify and resolve underspecified areas in the current feature spec through a structured Q&A dialog.
+## Steps
+1. Scan: scope, domain model, UX flow, non-functional attributes, integrations, edge cases, terminology, the Security & Privacy table.
+2. ≤ 5 questions per session, **one at a time**, each answerable by 2–5 options or a short answer. Obvious from context → do not ask.
+3. Present → WAIT → validate → record. No human (unattended) → record an **assumption** (preflight 6), never invent an answer.
+4. After every answer update `spec.md` at once (replace the marker); `clarify.md` is the log (`## Q1: …` / `**Answer**` / `**Resolution**`), `spec.md` the truth.
 
-**When NOT to use**: For straightforward specs with no ambiguities — proceed to Plan directly.
+## Done when
+- [ ] Every answer applied; unanswered questions left as markers. history.md entry, then commit (`spec-kit/references/preflight.md` procedure): `spec(phase-1.5): [feature] clarifications`.
 
-**Routing**: Load this skill when the user says "clarify [feature]" or "resolve ambiguities". If loaded directly, load spec-kit-workflow first to check prerequisites.
- Do NOT ask questions for the sake of process.
-
-**Artifacts**:
-- `specs/[feature]/clarify.md`
-- Updated `specs/[feature]/spec.md` (with resolved ambiguities)
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Validate prerequisites
-```
-IF specs/[feature]/spec.md NOT EXISTS:
-  ERROR: "Run spec-kit-specify first"
-```
-
-### Load spec
-```
-LOAD specs/[feature]/spec.md
-IF bugfix mode: LOAD bugs.md, filter for bugs needing clarification
-```
-
-### Ambiguity scan
-Check: Functional scope, domain model, UX flow, non-functional attributes, integrations, edge cases, terminology.
-
-### Generate questions (max 5 per session)
-One question at a time. Each answerable via multiple choice (2-5 options) or short answer.
-
-### Sequential questioning loop
-For each question: present → wait → validate → record.
-After each answer: UPDATE spec.md, replace `[NEEDS CLARIFICATION]` markers.
-
-### Generate clarify.md
-```markdown
-# Clarification Log: [Feature]
-## Q1: [Question]
-**Answer**: [Selected]
-**Resolution**: [How applied to spec]
-```
-
-### Repeat
-After answer, loop: next question → answer → update spec.md.
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 1.5 — Clarify
-- Artifact: `clarify.md`, `spec.md` (amended)
-- Scope: `specs/[feature]/clarify.md`, `spec.md`
-- Message: `"spec(phase-1.5): [feature] clarifications"`
-
-## Completion
-- Propose: `spec-kit-plan`
-
-## Common Pitfalls
-1. **Asking unnecessary questions**: If the answer is obvious from context, don't ask. The user's time is valuable.
-2. **More than 5 questions**: Keep sessions focused. Unanswered questions can be addressed in a second session.
-3. **Not updating the spec**: After each answer, immediately update spec.md. The clarify.md is a log; spec.md is the source of truth.
-
-## Prerequisite Enforcement
-**BLOCKED** if: spec.md does not exist (run `spec-kit-specify` first).
+## Next
+`spec-kit-plan`.
diff --git a/src/skills/spec-kit-constitution.md b/src/skills/spec-kit-constitution.md
index 44248d9..ac9560b 100644
--- a/src/skills/spec-kit-constitution.md
+++ b/src/skills/spec-kit-constitution.md
@@ -1,6 +1,7 @@
 ---
 name: spec-kit-constitution
-description: Load when the user says 'spec-kit constitution', 'speckit constitution', 'spec-kit principles', 'speckit principles', "create constitution", "create project principles", or "set up project principles" — Phase 0 project setup. Three modes: brownfield (auto-detect from existing code), free-text (describe your project in a sentence, agent maps to purpose/arch/principles), and guided wizard (3-level decision tree with 9 purposes × 25 architecture options).
+description: >
+  Load when the user says 'spec-kit constitution', 'speckit constitution', 'spec-kit principles', 'speckit principles', "create constitution", "create project principles", or "set up project principles" — Phase 0 project setup. Three modes: brownfield (auto-detect from existing code), free-text (describe your project in a sentence, agent maps to purpose/arch/principles), and guided wizard (3-level decision tree with 9 purposes × 25 architecture options).
 version: 2.1.0
 author: Hermes Agent
 license: MIT
@@ -13,580 +14,25 @@ metadata:
 
 # spec-kit-constitution
 
-**Task Persona**: Adopt the mindset of a project founder setting ground rules.
-Constitutions should be principled but practical — they guide decisions without
-being bureaucratic. Every rule must have a clear purpose. Always offer choice
-with tradeoffs explained.
+**Phase**: 0 (project foundation, one-time) · **Persona**: project founder setting ground rules — principled but practical; every rule has a purpose; always offer choices with trade-offs.
+**Purpose**: create `specs/constitution.md`. Modes: **brownfield** (detect the stack, pre-fill ⭐ defaults), **free-text** (describe the project → purpose/architecture/tech/principles inferred), **wizard** (3-level tree: 9 purposes × 25 architectures × tech brackets).
+**Full procedure**: `spec-kit/references/skills/spec-kit-constitution.md` (detection tables, inference mapping, purpose→principle defaults, monorepo mode). Reference data: `spec-kit/references/constitution-principles.md` (12 principles × 3 options), `spec-kit/references/constitution-tables.md`.
+**Not for**: per-feature runs — principles are project-wide.
 
-**Phase**: 0 (Project Foundation)
+## Before writing
+- `spec-kit/references/preflight.md`. `specs/constitution.md` exists → report its version and **HALT** (amend only on explicit request).
 
-**Purpose**: Create or update the project constitution at `specs/constitution.md`.
+## Steps
+1. Detect mode: scan the project root with the detection tables. Files found → brownfield summary ("Detected [language]/[framework]; tests …; CI …; DB …; lint …"). Nothing → **ASK**: free-text description or wizard.
+2. Free-text: map description → purpose (A–I) → architecture → tech → principle defaults; present the inference table; **WAIT** for "all good" or corrections.
+3. Wizard: Level 1 purpose (9 options with trade-offs) → monorepo question → Level 2 architecture → Level 3 technology bracket (3 options each). Pre-fill the 12 principles from the purpose mapping.
+4. For **each** of the 12 principles present the 3 options (rule, pros, cons) with the ⭐ default marked; **WAIT** for A/B/C/skip and an optional rationale. Skip Database for stateless projects.
+5. Copy `spec-kit/templates/constitution-template.md` → `specs/constitution.md`: chosen option + rule text + rationale + rejected alternatives per principle; tech stack (or "TBD"); monorepo → Projects table. Version 1.0.0 (MAJOR incompatible governance / MINOR new principle / PATCH clarification).
 
-Three input modes:
-1. **Brownfield** (existing code): Auto-detects stack from project files —
-   60+ detection patterns for language, framework, test runner, CI, database,
-   and linting. Pre-fills ⭐-marked defaults.
-2. **Free-text description** (new project): User describes the project in
-   natural language (e.g. "React Native mobile app for fitness, small team,
-   ship fast"). Agent maps description to purpose → architecture → tech →
-   principle defaults automatically. User reviews and adjusts.
-3. **Wizard** (guided, new project): Interactive 3-level decision tree
-   (9 purposes × 25 architecture options). User picks at each level.
-   Always presents 3 options per principle with pros and cons.
+## Done when
+- [ ] Every principle chosen by the user (never silently); skipped ones listed with a reason.
+- [ ] MCP (optional): `mcp_spec_kit_project_set_constitution(status="present")` (checks the file exists).
+- [ ] Commit directly (`spec-kit/references/commits.md`): `spec(phase-0): constitution for [PROJECT]`.
 
-**When NOT to use**: This is a one-time setup per project. Do NOT re-run for
-every feature — principles are project-wide.
-
-**Prerequisites**: None. This is the first skill — run first for a new project.
-
-**Artifacts**: `specs/constitution.md`
-
-**Routing**: Load this skill when the user says "create constitution" or
-"create project principles". If loaded directly (not via spec-kit-workflow),
-consider loading the workflow first for prerequisite checks.
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Step 0: Check for existing constitution
-
-```
-IF specs/constitution.md EXISTS:
-  LOAD existing constitution
-  NOTE: "Constitution exists at v[VERSION]. Run 'amend constitution' to update."
-  HALT — constitution is one-time setup, do not overwrite without user intent
-```
-
-### Step 1: Detect mode — brownfield vs greenfield
-
-```
-SCAN project root for these files to identify the tech stack:
-
-LOAD the brownfield file detection tables from `spec-kit/references/constitution-tables.md`
-
-  IF any project files detected:
-    MODE = brownfield
-    COMPILE a detection summary:
-      "Detected [language] project with [framework].
-       Test: [test_framework]. CI: [ci_platform]. DB: [database].
-       Linting: [linter]. Formatting: [formatter]."
-
-    USE the detection to pre-fill ⭐ recommendations:
-      - Testing: If pytest/Jest/Vitest/go test detected → ⭐ B (Pragmatic TDD)
-                   If no test files found → ⭐ C (Test-After)
-      - Linting: If ESLint/Ruff/RuboCop/clippy config exists → ⭐ A or B
-                   If no lint config → ⭐ C (Minimal)
-      - Git: If .github/workflows exists → ⭐ A (Trunk-Based) or B (Feature Branches)
-               If Jenkinsfile → ⭐ C (Git Flow)
-      - DB: If migrations detected → ⭐ A (Migration-First)
-              If no DB files → SKIP Principle 10
-
-  ELSE:
-    MODE = greenfield
-    NOTE: "No existing project detected. Would you like to:
-           1. Describe your project in a sentence — I'll map it to purpose,
-              architecture, tech, and principle defaults automatically
-           2. Use the guided wizard — 3 levels of choices with tradeoffs at each step"
-    
-    ASK: "Which approach do you prefer? (1) Free-text description or (2) Guided wizard"
-    
-    RECORD: input_mode = [free-text | wizard]
-```
-
-### Step 2a: Free-Text — Description to Constitution
-
-**Only for MODE=greenfield AND input_mode=free-text.**
-
-The user provides a natural-language project description. The agent maps it
-to a purpose (A-I), architecture (A1-I3), technology choices, and principle
-defaults automatically. The user reviews the inferred choices and may accept
-or adjust any of them.
-
-```text
-1. PROMPT: "Describe your project in a few sentences — what are you building,
-   what platform/target, team size, and any key constraints?"
-
-2. AWAIT user input (e.g. "React Native mobile app for fitness tracking,
-   small two-person team, want to ship quickly, no backend — Firebase")
-
-3. INFER from the description:
-
-   MAP the description to a purpose code (A-I):
-     - Look for keywords: "mobile app", "iOS", "Android", "desktop"
-       → Purpose C (Native/Desktop Client)
-     - "web app", "SaaS", "API", "dashboard", "full-stack"
-       → Purpose A (User-Facing Application)
-     - "library", "package", "SDK", "npm", "PyPI"
-       → Purpose D (Library/SDK)
-     - "CLI", "tool", "script", "pipeline", "Terraform"
-       → Purpose E (Infrastructure/CLI/DevOps)
-     - "game", "Unity", "Unreal", "Godot"
-       → Purpose F (Game)
-     - "extension", "browser add-on", "Chrome extension"
-       → Purpose G (Browser Extension)
-     - "notebook", "research", "analysis", "Jupyter"
-       → Purpose H (Research/Notebook)
-     - "firmware", "embedded", "IoT", "Arduino", "ESP32"
-       → Purpose I (IoT/Embedded)
-     - "portfolio", "blog", "landing page", "marketing site"
-       → Purpose B (Content Site/Marketing)
-     - If ambiguous: infer the closest match and note the uncertainty
-
-   MAP architecture from implied stack:
-     - "React Native", "Flutter", "Tauri" → C2 (Cross-Platform)
-     - "iOS app (Swift)", "Android (Kotlin)" → C1 (Native)
-     - "Electron", "PWA", "Capacitor" → C3 (Web Wrapper)
-     - "Firebase", "Vercel", "Cloudflare" → A4 (Serverless)
-     - "Unity", "Unreal", "Godot" → F1 (Engine-Centric)
-     - "Rails", "Django", "Laravel" → A1 (Monolith)
-     - "microservices", "distributed" → A3 (Microservices)
-     - "Arduino", "sensor firmware" → I3 (MicroPython/Arduino)
-     - "bare-metal", "RTOS", "FreeRTOS" → I1 (Bare-Metal/RTOS)
-     - "single notebook", "analysis only" → H1 (Single Notebook)
-     - "static site", "SSG" → B1 (Static Site Generator)
-     - Default: use the most common architecture for the detected purpose
-
-   MAP tech choices from explicit mentions:
-     - "React Native" → TypeScript, React Native framework
-     - "Flutter" → Dart, Flutter
-     - "Firebase" → BaaS for auth/db
-     - Extract any explicit language/framework mentions
-
-   MAP principle defaults from inferred purpose using the Step 2c
-   (Purpose-to-Principle) mapping table below.
-
-4. PRESENT the inferred result as a table:
-
-   | Inference | Value | Correct? |
-   |-----------|-------|----------|
-   | Purpose | C — Native / Desktop Client | ✅ / 🔄 |
-   | Architecture | C2 — Cross-Platform (Flutter/React Native) | ✅ / 🔄 |
-   | Language | TypeScript (React Native) | ✅ / 🔄 |
-   | Testing | B — Pragmatic TDD (recommended for native apps) | ✅ / 🔄 |
-
-   ASK: "Does this look right? You can say 'all good' to proceed with these
-         defaults, or correct specific items. I'll then walk through the
-         12 principles to confirm or adjust."
-
-5. IF user says "all good" or confirms:
-   PROCEED to Step 2c (Load principles reference) then Step 3
-
-6. IF user corrects specific items:
-   UPDATE the inferred values
-   RECORD corrections as user rationale
-   PROCEED to Step 3
-
-7. IF user says "I want the wizard instead":
-   SET input_mode = wizard
-   ROUTE to Step 2b (Wizard mode below)
-
-8. IF the description is too vague to map confidently:
-   NOTE: "Description is quite broad. I'll use [purpose] as a starting point,
-          but let me know if that doesn't fit."
-   PROCEED with best-guess inference
-```
-
-**Inference examples:**
-
-| User says | Inferred purpose | Inferred arch | Principle defaults |
-|-----------|-----------------|---------------|-------------------|
-| "iOS app with SwiftUI for habit tracking, solo dev" | C — Native | C1 — Native Platform | C defaults, Testing C (solo dev) |
-| "React Native mobile app for fitness, small team, Firebase" | C — Native | C2 — Cross-Platform | C defaults, Testing B |
-| "Django REST API for a SaaS dashboard" | A — User-Facing | A1 — Monolith | A defaults |
-| "CLI tool in Go for managing Kubernetes clusters" | E — Infra/CLI | E1 — Single Binary | E defaults |
-| "Three.js browser game, WebGL, casual" | F — Game | F3 — Web/Retro | F defaults |
-| "Jupyter notebook analyzing stock market data" | H — Research | H1 — Single Notebook | H defaults |
-
----
-
-### Step 2b: Wizard — 3-Level Decision Tree
-
-**Only for MODE=greenfield AND (input_mode=wizard OR no input_mode set yet).**
-
-Guide the user through three levels of decisions. Each level narrows the
-options and pre-fills recommended defaults for the next level. Use the
-brownfield detection examples table from `spec-kit/references/constitution-tables.md` for recommended defaults once
-language + framework are chosen.
-
----
-
-#### Level 1 — Highest-Level Purpose
-
-Ask the user: *"What is this project's primary purpose?"*
-
-Present these 9 options with their tradeoffs:
-
-| Option | Type | Examples | Testing impact | Arch impact | Docs impact | Deps impact |
-|--------|------|----------|---------------|-------------|-------------|-------------|
-| **A — User-Facing Application** | Web/mobile API, frontend, full-stack app | SaaS, e-commerce, social app, dashboard, CMS | Needs integration + F2E tests. TDD pays off. | Architecture matters — will need to scale. | API docs, user docs, setup guide critical. | Framework deps expected (React, Django, etc.) |
-| **B — Content Site / Marketing** | Static or lightly dynamic, no auth/DB | Portfolio, landing page, blog, documentation site, marketing site | Minimal. Visual checks + broken link checker. No business logic to test. | Simple — SSG, template-driven, or plain HTML/CSS. No backend needed. | Content IS the documentation. Readme for build/deploy. | SSG framework or plain HTML/CSS. Zero server deps. |
-| **C — Native / Desktop Client** | Standalone client app, no backend to architect | iOS app, Android app, macOS app, Windows app, Linux desktop app, Electron app, Tauri app, Qt app | UI/snapshot tests, integration tests. Manual QA for visual polish. | Client-side architecture (MVC, MVVM, Redux, Composable). Platform SDK native or cross-platform framework. | User-facing help, API docs for local features, store listing. | Platform SDK, UI framework. Cross-platform framework for shared code. |
-| **D — Library / SDK / Package** | Reusable code for other developers | npm package, PyPI lib, Go module, crate | Exhaustive unit tests essential. API surface must be tested. | Clean public API, minimal internal coupling. | API docs, README, examples, changelog mandatory. | Zero or minimal deps to avoid transitive bloat. |
-| **E — Infrastructure / CLI / DevOps** | Automation, ops tools, platform | CLI tool, Terraform module, CI pipeline, daemon | Integration tests with real infra. Manual testing common. | Simple, composable. No over-engineering. | README + --help. Code that IS the documentation. | Minimal. Static binaries preferred. |
-| **F — Game** | Interactive application with game loop, rendering, input | 2D platformer, 3D FPS, puzzle game, RPG, mobile game, WebGL game | Unit tests for game logic. Visual/playtest testing critical. Integration tests for netcode. | ECS, scene graph, component-based. Game loop, render pipeline, physics. | Design doc, mechanics doc, modding API docs. README + gameplay guide. | Engine dependency (Unity, Unreal, Godot, Bevy). Graphics, audio, physics libs. |
-| **G — Browser Extension** | Browser add-on modifying/extending the browser | Chrome extension, Firefox add-on, Safari extension, Edge extension | Manual browser testing. Puppeteer/Playwright for F2E. | Content scripts, service worker (MV3), popup page, options page. Cross-browser API abstraction. | Store listing, permissions guide, feature docs, privacy policy. | Minimal — browser APIs. Polyfill for cross-browser support (webextension-polyfill). |
-| **H — Research / Notebook** | Data exploration, academic research, one-off analysis | Jupyter notebook, R Markdown, Quarto doc, MATLAB script, experimental Python script | Minimal to none. Visual inspection of outputs. Assertions in cells. | Single notebook or notebook + reusable scripts. No deployment. No production infra. | Notebook cell comments, README with reproduction steps. Dataset provenance. | Permissive — pandas, numpy, matplotlib, torch, scipy, tidyverse. Whatever is needed. |
-| **I — IoT / Embedded** | Firmware, device software, real-time systems | Sensor firmware, motor controller, smart home device, drone flight controller, RTOS application | Hardware-in-the-loop testing. Simulation for CI. Manual device testing essential. | HAL, RTOS tasks, driver layer. Memory-constrained. Real-time constraints. | Pinout docs, protocol specs, register maps. Datasheet references. | Minimal or zero std. Vendor SDKs. No dynamic allocation. Cross-compilation toolchain. |
-
-```
-ASK: "What kind of project are you building?"
-RECORD: purpose = [A | B | C | D | E | F | G | H | I]
-NOTE: purpose determines the weight of each principle below.
-```
-
-After the user picks their purpose, ask about monorepo:
-
-```text
-ASK: "Is this a multi-project monorepo with different purposes?
-      (e.g., a repo containing a web app + mobile app + shared library)
-      [yes | no]"
-
-IF yes:
-  NOTE: "Multi-project monorepo detected. The constitution will define
-         each sub-project separately under a 'Projects' section."
-
-  ASK: "How many sub-projects does this monorepo contain?"
-  RECORD: sub_project_count = [N]
-
-  FOR each sub-project (1 to N):
-    ASK: "Sub-project [N] name? (e.g., 'frontend', 'mobile-app', 'shared-lib')"
-    RECORD: sub_project_name = [name]
-
-    RUN Levels 1-3 for this sub-project independently:
-      ASK its purpose (can differ per sub-project)
-      ASK its architecture (can differ)
-      ASK its tech choices
-
-  AFTER all sub-projects defined, the constitution will contain a
-  'Projects' table at the top, and shared principles will be determined
-  by the PRIMARY sub-project (the largest or most important one).
-
-  IF monorepo:
-    MODE = monorepo
-    PRIMARY purpose = [chosen by user]
-
----
-
-#### Level 2 — Architecture Approach
-
-Based on the chosen purpose, present the architecture options:
-
-LOAD the Level 2 architecture tables for each purpose from `spec-kit/references/constitution-tables.md`
-
-```
-ASK: "Given your purpose [A|B|C|D|E|F|G|H|I], which architecture approach fits?"
-RECORD: architecture = [A1|A2|A3|A4 | B1|B2|B3 | C1|C2|C3 | D1|D2|D3 | E1|E2|E3|E4 | F1|F2|F3 | G1|G2|G3 | H1|H2|H3 | I1|I2|I3]
-```
-
----
-
-#### Level 3 — Technology Choices
-
-Based on purpose + architecture, guide the user through technical choices.
-For each choice, present 3 options using the project-type-aware defaults
-from the tables below.
-
-LOAD the Level 3 technology choice brackets for each purpose from `spec-kit/references/constitution-tables.md`
-
-For each bracket, present the specific language options as follows:
-
-```
-  | Option | Language | Framework suggestions | Pros | Cons |
-  |--------|----------|----------------------|------|------|
-  | A | [lang] | [framework list] | [pros] | [cons] |
-  | B | [lang] | [framework list] | [pros] | [cons] |
-  | C | [lang] | [framework list] | [pros] | [cons] |
-
-  USER picks: [A | B | C]
-```
-
-After the user picks language + framework, use the **Brownfield Detection
-Examples table** from `spec-kit/references/constitution-tables.md` to find the matching row
-and pre-fill recommended defaults for the remaining principles.
-
-If the user's exact combination isn't in the table, infer from the closest
-match:
-- Same language + similar framework → use that row
-- Same purpose category → use generic defaults for that purpose
-
----
-
-#### Step 2c: Default Mapping — Purpose to Principle Weights
-
-Once purpose + architecture are chosen, map them to recommended defaults
-for the 12 principles. These are weighted suggestions — the user still
-picks A/B/C in Step 3.
-
-```
-PURPOSE = A (User-Facing App):
-  Testing → A or B (TDD important for reliability)
-  Linting → B (Pragmatic — balance quality and speed)
-  Architecture → user's choice from Level 2
-  Dependencies → B (Curated — need frameworks)
-  Git Workflow → B (Feature branches — standard)
-  Documentation → B (Critical-only — API docs + setup)
-  Error Handling → A (Defensive — user-facing app)
-  Performance → B (Profile-then-optimize)
-  Code Review → A or B (Strict or Risk-based)
-  Database → A (Migration-first — if using DB)
-  Config/Secrets → B (Environment-based)
-  Dev Toolchain → B (Standard toolchain)
-
-PURPOSE = B (Content Site / Marketing):
-  Testing → C (Test-After — no business logic to test, visual QA only)
-  Linting → B (Pragmatic — template code needs flexibility)
-  Architecture → user's choice from Level 2
-  Dependencies → B (Curated — SSG framework + maybe CMS client)
-  Git Workflow → A (Trunk-based — content changes should ship fast)
-  Documentation → B (Critical-only — build/deploy instructions + content guide)
-  Error Handling → C (Minimal — static sites have no runtime errors)
-  Performance → C (Ignore-until-painful — SSG output is inherently fast)
-  Code Review → C (Post-merge — content edits shouldn't block)
-  Database → SKIP (no database on content sites)
-  Config/Secrets → C (Config-in-repo — build config is part of the source)
-  Dev Toolchain → B (Standard toolchain — SSG, asset pipeline, CDN deploy)
-
-PURPOSE = D (Library / SDK):
-  Testing → A (Strict TDD — API surface must be tested)
-  Linting → A (Strict — public API consistency)
-  Architecture → user's choice from Level 2
-  Dependencies → A or B (Minimal or Curated)
-  Git Workflow → B (Feature branches)
-  Documentation → A (Exhaustive — API docs mandatory)
-  Error Handling → B (Contract-based — surface errors cleanly)
-  Performance → B (Profile-then-optimize)
-  Code Review → A (Strict — every change reviewed)
-  Database → SKIP (libraries shouldn't dictate storage)
-  Config/Secrets → A (Strict — secrets never in lib)
-  Dev Toolchain → B (Standard toolchain)
-
-PURPOSE = E (Infrastructure / CLI / DevOps):
-  Testing → B (Pragmatic — integration-heavy)
-  Linting → A (Strict — CLI UX consistency)
-  Architecture → user's choice from Level 2
-  Dependencies → A (Minimal — static binaries)
-  Git Workflow → A (Trunk-based — fast iteration)
-  Documentation → C (Code-as-docs — help text + README)
-  Error Handling → C (Minimal — propagate, top-level catch)
-  Performance → A (Optimize-first — CLI responsiveness)
-  Code Review → B (Risk-based — config changes vs engine)
-  Database → SKIP (infra tools shouldn't depend on DB)
-  Config/Secrets → A (Strict — env + config files)
-  Dev Toolchain → C (Full DX — automation matters)
-
-PURPOSE = F (Game):
-  Testing → C (Test-After — playtesting and visual QA dominant)
-  Linting → B (Pragmatic — engine code needs flexibility)
-  Architecture → user's choice from Level 2
-  Dependencies → C (Permissive — engines, assets, middleware, audio libs)
-  Git Workflow → B (Feature branches — asset changes need review)
-  Documentation → B (Critical-only — design doc + mechanics + API)
-  Error Handling → A (Defensive — game crashes ruin UX)
-  Performance → A (Optimize-first — frame budget is hard limit)
-  Code Review → B (Risk-based — gameplay logic vs asset changes)
-  Database → SKIP (save systems are engine-managed or custom binary)
-  Config/Secrets → C (Config-in-repo — game config is part of the game)
-  Dev Toolchain → C (Full DX — asset pipeline, build chain, packaging)
-
-PURPOSE = I (IoT / Embedded):
-  Testing → C (Test-After — hardware testing dominates)
-  Linting → A (Strict — firmware bugs are expensive, no OTA)
-  Architecture → user's choice from Level 2
-  Dependencies → A (Minimal — no stdlib, no heap, vendor SDK only)
-  Git Workflow → A (Trunk-based — most constrained, fast iteration)
-  Documentation → A (Exhaustive — pinouts, registers, protocols)
-  Error Handling → A (Defensive — watchdog, brownout, fail-safe)
-  Performance → A (Optimize-first — memory and cycles are hard limits)
-  Code Review → A (Strict — hardware damage risk, no hotfix possible)
-  Database → SKIP (no database on embedded devices)
-  Config/Secrets → B (Environment-based — compile-time flags, EEPROM)
-  Dev Toolchain → C (Full DX — cross-compiler, flashing, logic analyzer)
-
-PURPOSE = C (Native / Desktop Client):
-  Testing → B (Pragmatic — UI tests for critical paths, manual QA for visual)
-  Linting → B (Pragmatic — platform SDKs have their own conventions)
-  Architecture → user's choice from Level 2
-  Dependencies → B (Curated — platform SDK + UI framework, minimize transitive)
-  Git Workflow → B (Feature branches — release management matters)
-  Documentation → B (Critical-only — user-facing help + setup + store listing)
-  Error Handling → A (Defensive — app crashes cause user frustration)
-  Performance → B (Profile-then-optimize — startup time, frame drops, memory)
-  Code Review → A (Strict — app store review failures are costly)
-  Database → SKIP (local storage is platform-managed: Core Data, Room, SharedPrefs)
-  Config/Secrets → B (Environment-based — build flavors, feature flags, remote config)
-  Dev Toolchain → C (Full DX — build pipeline, code signing, app store deploy)
-
-PURPOSE = G (Browser Extension):
-  Testing → C (Test-After — manual browser testing dominates)
-  Linting → B (Pragmatic — content scripts need browser API flexibility)
-  Architecture → user's choice from Level 2
-  Dependencies → A (Minimal — browser APIs preferred, avoid bloating extension)
-  Git Workflow → B (Feature branches — store release cycles)
-  Documentation → A (Exhaustive — store listing, permissions, privacy policy mandatory)
-  Error Handling → A (Defensive — broken extension in user's browser is invisible failure)
-  Performance → A (Optimize-first — content script perf impacts every page user visits)
-  Code Review → A (Strict — privileged API misuse can cause account/data theft)
-  Database → SKIP (storage API is browser-provided)
-  Config/Secrets → A (Strict — API keys, tokens must never be in extension code)
-  Dev Toolchain → B (Standard toolchain — build, zip, upload to stores)
-
-PURPOSE = H (Research / Notebook):
-  Testing → C (Test-After — visual inspection of outputs, assertions in cells)
-  Linting → C (Minimal — notebooks are exploratory, not production code)
-  Architecture → user's choice from Level 2
-  Dependencies → C (Permissive — use whatever lib the analysis needs)
-  Git Workflow → A (Trunk-based — research is fast iteration, no release branches)
-  Documentation → B (Critical-only — reproduction steps + dataset provenance)
-  Error Handling → C (Minimal — errors are part of exploration, top-level catch)
-  Performance → C (Ignore-until-painful — correct analysis first, optimize if needed)
-  Code Review → C (Post-merge — notebooks are exploratory, not approval-gated)
-  Database → SKIP (research uses files, not databases)
-  Config/Secrets → C (Config-in-repo — dataset paths, API keys in .env.example)
-  Dev Toolchain → A (Minimal — just a notebook runtime, no build pipeline)
-```
-
-Present these as a summary table to the user:
-
-```
-  Based on your choices (Purpose: [name], Architecture: [name]), here are
-  the recommended defaults for each principle:
-
-  | Principle | Recommended | Why |
-  |-----------|-------------|-----|
-  | Testing   | ⭐ [option] | [reason] |
-  | Linting   | ⭐ [option] | [reason] |
-  | ...       |             |      |
-
-  Say 'bugfix [feature]' to start a new bugfix round.
-```
-
-Then proceed to Step 3 to let the user confirm or adjust each principle.
-
----
-
-### Step 2d: Load the principles reference (both modes)
-
-```
-LOAD spec-kit/references/constitution-principles.md
-
-This reference defines 12 principles, each with 3 options (A/B/C).
-Each option has a rule, pros, and cons.
-
-FOR each principle:
-  READ the 3 options
-  IF MODE == brownfield:
-    SELECT the option that best matches detected project artifacts
-    TAG it with ⭐ "detected"
-  IF MODE == greenfield:
-    USE the pre-filled mapping from Step 2c
-    TAG the recommended option with ⭐ "recommended for [purpose]"
-```
-
-### Step 3: Present each principle with choice
-
-**For each principle, present the 3 options as a formatted table.**
-Always show pros and cons. Never skip the choice — even if a detected default
-exists, the user may disagree.
-
-```
-PRESENT for each principle:
-
-  ## Principle N: [Name]
-
-  | Option | Rule | Pros | Cons |
-  |--------|------|------|------|
-  | ⭐ A — [Name] *(detected)* | ... | ... | ... |
-  | B — [Name] | ... | ... | ... |
-  | C — [Name] | ... | ... | ... |
-
-  The ⭐ marker means this was auto-detected from your project files.
-  Pick A, B, or C (or type 'skip' to use detected default).
-
-  USER picks: [A | B | C | skip]
-  RECORD the chosen option
-  ASK: "Any notes or rationale for this choice?" → RECORD as rationale
-```
-
-In greenfield mode, after showing the 3 options, include the purpose-based
-recommendation from Step 2c instead of a generic guiding question:
-
-```
-  ⭐ This option is recommended for [purpose name] projects because
-     [reason from Step 2c mapping].
-  You can still pick A, B, or C — this is a recommendation, not a requirement.
-
-  USER picks: [A | B | C]
-  RECORD the chosen option
-  ASK: "Any notes or rationale for this choice?" → RECORD as rationale
-```
-
-### Step 4: Handle principle exceptions
-
-```
-IF project has no database (no DB config, no ORM, no schema files):
-  SKIP Principle 10 (Database & Schema)
-  NOTE: "Skipping Database principle — no database detected."
-```
-
-### Step 5: Write the constitution
-
-```
-COPY spec-kit/templates/constitution-template.md → specs/constitution.md
-
-FILL each section with:
-  - Chosen option letter and name
-  - Full rule text from the reference
-  - Recorded rationale
-  - Rejected alternatives table with reasons
-
-IF MODE == monorepo:
-  FILL the Projects table at the top with each sub-project's:
-    - Name, Purpose, Language/Framework, Architecture option
-  SHARED principles apply to the PRIMARY sub-project
-  NOTE per principle: "Applies to all sub-projects. Project-specific
-    variations documented in the Projects section."
-
-ELSE (single project):
-  INCLUDE in the Tech Stack section:
-    - Detected language/framework (brownfield) or "New project — TBD" (greenfield)
-    - Test framework, CI, package manager
-```
-
-### Step 6: Version management
-- **MAJOR** (1.x.x → 2.0.0): Backward-incompatible governance changes
-- **MINOR** (x.1.x → x.2.0): New principles
-- **PATCH** (x.x.1 → x.x.2): Clarifications
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 0 — Constitution
-- Artifact: `specs/constitution.md`
-- Scope: `specs/constitution.md`
-- Message: `"spec(phase-0): constitution for [PROJECT]"`
-
-## Completion
-- Report: "Constitution ratified with [N] principles."
-- Report mode: brownfield, free-text, or wizard (greenfield)
-- If free-text mode: Show which purpose/architecture/tech were inferred from user's description
-- List all chosen options (A/B/C per principle)
-- List any principles skipped with reason
-- Propose: Run `spec-kit-specify` to create the first feature specification.
-
-LOAD the Brownfield Detection Examples table from `spec-kit/references/constitution-tables.md`
-
-## Common Pitfalls
-1. **Skipping the choice dialog**: Always present ALL 3 options with pros/cons.
-   The user needs to understand tradeoffs to make an informed decision.
-2. **Burying detected defaults**: In brownfield mode, show ⭐ clearly but let the
-   user override. Detection is guidance, not dictation.
-3. **Assuming all 12 principles apply**: Skip Database principle for stateless
-   projects. Skip Code Review for solo projects (but mentioning it is still useful).
-4. **Overwriting an existing constitution**: Always check first. Constitution is
-   one-time setup. If the user wants to amend, offer to add principles with
-   version bump.
-
-## Prerequisite Enforcement
-**No prerequisites** — this is Phase 0.
+## Next
+Report mode, inferred items, chosen options; propose `spec-kit-specify`.
diff --git a/src/skills/spec-kit-design.md b/src/skills/spec-kit-design.md
new file mode 100644
index 0000000..4bb7d42
--- /dev/null
+++ b/src/skills/spec-kit-design.md
@@ -0,0 +1,42 @@
+---
+name: spec-kit-design
+description: >
+  Load when the user says 'spec-kit design [module]', 'speckit design [module]', "write the design doc for [module]", "refresh the design doc for [module]", "how does [module] work" (when a design doc should answer it), or "document the architecture of [module]" — a living module design document (purpose, components, data flow, seams, invariants, security, testing, debt). Only for projects that keep `design_dir` in specs/git-conventions.md.
+version: 1.0.0
+author: Hermes Agent
+license: MIT
+category: software-development
+metadata:
+  hermes:
+    tags: [spec-kit, design, architecture, module]
+    related_skills: [spec-kit-plan, spec-kit-summarize, spec-kit-epic, spec-kit-refresh]
+---
+
+# spec-kit-design
+
+**Phase**: cross-feature (standalone) · **Persona**: the architect who describes what is **built** — components, flows, seams, invariants — in ≤ 3–4 pages a new engineer or an auditor reads first; not a decision log (ADRs), not a plan (epic), not a feature (spec).
+**Purpose**: create or refresh `[design_dir]/[module].md` (`spec-kit/templates/design-doc-template.md`) from the code. A module is **space**: a bounded part of the system that outlives every epic. Feature closes patch it; this skill writes or re-baselines it.
+**`system`** is the reserved module name: `[design_dir]/system.md` is the one-page system view (C4 L1 context + L2 containers: services, stores, external systems, trust boundaries) that every module doc hangs off; create it first.
+**Not for**: projects without `design_dir` (the plan's `## Current Design` is the design — say so and stop); recording a decision (→ an ADR at close); a feature's own design (→ `spec-kit-plan`).
+
+## Before writing
+- Preflight checks 1 and 4 (`spec-kit/references/preflight.md`). `design_dir` from `specs/git-conventions.md`; absent → **ASK** once whether to add it (default `docs/design`); declined → stop.
+- Read the code first: directories, entry points, DI registrations, DB objects, contracts, tests. Then the constitution, the ADR index, AGENTS.md, closed specs whose plan names the module (`**Modules**:`).
+- Existing doc → No Complete Overwrite: patch section by section with approval (refresh), never rewrite.
+
+## Create
+1. Boundary: what the module owns, what it does not, which services / projects / directories.
+2. Components table (`path` per row), data flow (one request or event end to end), seams and contracts table (owner per seam).
+3. **Invariants and security**: the tenant / authorization boundary (where the check is — `path:line`), personal data handled and what must never be logged, other invariants. Cite code, not intentions.
+4. Testing (harnesses, goldens, probes), known debt (ticket / ADR per item), the ADRs that shaped it.
+5. Status header `current`, owner, last-patched. Commit `docs(design): [module] design doc` (`spec-kit/references/commits.md`).
+
+## Refresh
+Diff the page against the code (`git log -- ` since *Last patched*): ≤ 5 discrepancies per session, "doc says … / code does … → patch?" **WAIT** each; append a change-log line; bump *Last patched*. Never bulk-apply.
+
+## Done when
+- [ ] Every section filled from the code with paths; security invariants cite `path:line`; ≤ 3–4 pages; status header present.
+- [ ] Project ADR index and AGENTS.md point at the doc (propose the one-line patch, **WAIT**).
+
+## Next
+Feature closes keep it true (`spec-kit-summarize` step "design doc + epic row"); `spec-kit-epic` plans name it under `**Modules**:`.
diff --git a/src/skills/spec-kit-epic.md b/src/skills/spec-kit-epic.md
new file mode 100644
index 0000000..6bcd51b
--- /dev/null
+++ b/src/skills/spec-kit-epic.md
@@ -0,0 +1,49 @@
+---
+name: spec-kit-epic
+description: >
+  Load when the user says 'spec-kit epic [name]', 'speckit epic [name]', "create an epic for [programme]", "epic status [name]", "close epic [name]", "plan epic [name]", "break down epic [name]", "review epic [name]", or "which features belong to [epic]" — an epic: one body of work made of many single-spec features, run through its own specify → plan → breakdown → review (with devil's advocate) → build → close. Only for projects that keep `epics_dir` in specs/git-conventions.md.
+version: 1.0.0
+author: Hermes Agent
+license: MIT
+category: software-development
+metadata:
+  hermes:
+    tags: [spec-kit, epic, programme, roadmap]
+    related_skills: [spec-kit-specify, spec-kit-summarize, spec-kit-design, spec-kit-workflow]
+---
+
+# spec-kit-epic
+
+**Phase**: cross-feature (standalone) · **Persona**: delivery lead and architect one level up — one goal, the architecture across features, the features in order, the rules they all obey; never a feature's line-level design.
+**Purpose**: run an epic through the same shape as a feature, in `[epics_dir]/[epic]/`: **E1 specify** `epic.md` → **E2 plan** `plan.md` → **E3 breakdown** `features.md` (the epic's tasks are features) → **E3.5 review** `review.md` (+ devil's advocate) → **E4 build** (features run the normal workflow) → **E6 close**. An epic is **time**; a module is **space** (`spec-kit-design`).
+**Not for**: projects without `epics_dir` (every feature is its own epic — say so, stop); one feature (→ `spec-kit-specify`).
+
+## Before writing
+- Preflight checks 1 and 4 (`spec-kit/references/preflight.md`). `epics_dir` from `specs/git-conventions.md`; absent → **ASK** once (default `specs/epics`); declined → stop. Stage = the first missing file; an existing file is patched, never rewritten.
+- Load constitution, ADR index, AGENTS.md, the module design docs (`design_dir`) the epic will touch.
+
+## E1 Specify → `epic.md` (`spec-kit/templates/epic-template.md`)
+Id `NNN-short-name` like a feature: **NNN = the tracker's epic number** (ADO / Jira — ASK for it, record the link as `**Tracker**:`), else `mcp_spec_kit_next_id(kind="EPIC")`; the directory is `[epics_dir]/NNN-short-name/`. Goal (one sentence); **problem and users (why now)**; **success metrics** (post-launch, lagging — today / target / how measured); **alternatives considered** (incl. do nothing); scope in / **out**, stakeholders; **EAC-###** epic acceptance criteria — measurable at the end, each with how it will be verified (feature ACs, probe, command, user); cross-feature rules; epic-level Security & Privacy; ≤ 3 clarification markers (more → ask first). **WAIT** for the owner's confirmation. `epics_index: on` (default) → add the row to `[epics_dir]/README.md` (create from `spec-kit/templates/epics-index-template.md`). Commit `spec(epic): [epic] specify`.
+
+## E2 Plan → `plan.md` (`spec-kit/templates/epic-plan-template.md`)
+Current state from the design docs and the code (paths); target architecture; seams today → after; cross-feature decisions `ED-###` (alternatives, why; ADR bar at close); sequencing constraints and parallelism; rollout / migration / rollback; risks with owners. `**Modules**:` names the design docs the features will patch. Commit `spec(epic): [epic] plan`.
+
+## E3 Breakdown → `features.md` (`spec-kit/templates/epic-features-template.md`)
+Ordered rows, one per single-spec feature: intent, size guess, depends-on, modules, EACs; parallel groups in the Order line. Every EAC → ≥ 1 feature; every feature → ≥ 1 EAC or it is scope creep. First row must deliver something testable. ≤ ~12 rows — more means two epics. Commit `spec(epic): [epic] breakdown`.
+
+## E3.5 Review → `review.md` round (`spec-kit/templates/epic-review-template.md`) — required before the first feature
+Coverage and scope (EAC ↔ features, non-goals, size realism) · fit (constitution, ADRs, design docs' current state true, rules checkable) · sequencing and risk. **Devil's advocate** (5+ features: a separate sub-agent, different model when available; else a separate pass): strongest case against the epic + the ~80 % alternative, pre-mortem at six months, system-level abuse cases, the riskiest assumption; ≤ 5 objections, each answered. Verdict **GO / GO-WITH-CHANGES / NO-GO**; changes patched into epic / plan / features with approval; NO-GO → new round. Prefer the other agent or a fresh-context sub-agent. Commit `spec(epic): [epic] review (verdict: X)`.
+
+Every stage and every feature close that flips a row also updates the index row (status, features closed / planned, closed date).
+
+## E4 Build — `status [epic]` at any time
+Features run `spec-kit-specify` → … → `spec-kit-summarize` with `**Epic**: [epic]`; specify fills the row's spec dir and size, the close flips status / PR / health / ADRs. Status: refresh rows against `mcp_spec_kit_list_features()`; report stale rows, features naming the epic without a row, blocked order. A feature that cannot stay inside the plan → an `ED-###` amendment here, not a silent change.
+
+## E6 Close — every row closed or dropped (reason)
+Verify each **EAC** with evidence (feature ACs, a probe now, the owner's quoted words); fill *EAC coverage · Verified by*; close review round in `review.md` (verdict CLOSED / NOT-DONE, devil's advocate: "what does the goal look like unmet?"); harvest `ED-###` through the ADR bar (`spec-kit-summarize` rules); confirm the design docs were patched; Status → closed. **WAIT** for the owner; quote them. Commit `spec(epic): [epic] close`.
+
+## Done when
+- [ ] Stage file written, patched not rewritten; the owner's rulings quoted; every feature naming the epic has a row; the index row (when on) matches.
+
+## Next
+E1 → E2 → E3 → E3.5 → `spec-kit-specify` for row #1; each `spec-kit-summarize` updates its row; last row → E6.
diff --git a/src/skills/spec-kit-implement.md b/src/skills/spec-kit-implement.md
index 49aa526..ff5d829 100644
--- a/src/skills/spec-kit-implement.md
+++ b/src/skills/spec-kit-implement.md
@@ -13,370 +13,32 @@ metadata:
 
 # spec-kit-implement
 
-**Task Persona**: Adopt the mindset of a disciplined engineer building to spec. Follow the plan exactly. No scope creep, no unrequested refactoring, no added features. Write correct code and verify it with tests. Think like a builder, not a designer.
-
-**Phase**: 4
-
-**Purpose**: Execute implementation following `specs/[feature]/tasks.md`. Phase-level TDD: all tests for a phase written RED first, then all code written GREEN, then phase committed.
-
-**When NOT to use**: For spec-only changes (design iteration) — use `spec-kit-specify` or `spec-kit-plan`.
-
-**Routing**: Load this skill when the user says "implement [feature]" or "start implementation". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Git Commit Guidelines
-See `spec-kit/references/auto-commit.md`. Commits use `--no-verify`. Branch guard handled by preflight.md.
-
-Note: Each design phase skill (constitution, specify, clarify, plan, tasks) commits its own artifacts individually. Implement does NOT re-commit them.
-
-
-**Bugfix mode**: When tasks.md contains bugfix tasks (prefixed with BF-###), executes them alongside regular tasks.
-
-**Prerequisites**: `spec-kit-constitution` + `spec-kit-specify` + `spec-kit-plan` + `spec-kit-tasks` must be run first
-**Bugfix mode**: When bugs.md exists, load it for bugfix task context. Plan Ref validation is handled by the workflow orchestrator before routing to this skill — if you reached Implement, all bugs have valid Plan Refs.
-
-**Artifacts**: Updated `specs/[feature]/tasks.md` (with completion markers)
-
-## Bugfix Mode
-
-Bugfix tasks (prefixed with BF-###) follow the same RED→GREEN TDD cycle as regular feature phases:
-
-```text
-For each BF-### task:
-  0. READ — Confirm root cause understanding
-     - Read the relevant source code for the bug area
-     - Cross-check against the Plan Ref in bugs.md (created by spec-kit-plan)
-     - Verify the bug report description matches what the code actually does
-     - If the code contradicts the bug report or Plan Ref: STOP, flag the
-       discrepancy to the user before proceeding
-  1. RED — Write a test that reproduces the bug
-     - Focused test that demonstrates the faulty behaviour
-     - Run it → confirm it fails (proves the bug exists)
-  2. GREEN — Apply the minimal fix
-     - Run the test → confirm it passes
-```
-
-After GREEN is confirmed, record the bugfix in history.md and commit:
-
-3. **Append to history.md**: Write an entry to `specs/[feature]/history.md` noting which BUG-NNN was fixed and that tests pass.
-4. **Pre-commit guard**: READ `specs/[feature]/history.md` — confirm the BF-### entry is recorded. If missing, BLOCK.
-5. **Commit**: `git commit -m "fix: [feature] BF-### - description" --no-verify`
-
-This "read first" step prevents the common AI-agent trap where code is changed based on a bug report alone without verifying root cause against the actual code. The Plan Ref (from spec-kit-plan) gives the analysis; this step validates it against live code.
-
-Plan Ref validation and the bugfix routing decision (clarify vs direct plan) happen in the workflow orchestrator — this skill assumes all routing prerequisites are met.
-
-**New bugs discovered during fix**: If while fixing BF-### you discover new failures or edge cases not covered by the original bug report (reported by the user or found during code reading):
-- Log them as new entries in `bugs.md` (do NOT merge into the current BF-### task)
-  - INSERT each new bug BEFORE the `---` separator that precedes `## Summary`
-  - UPDATE the Summary table: add a row, increment counts, correct tallies
-- Each new bug must follow its own RED→GREEN cycle — do not fix it inline with the current task
-- Report to the user: "Found additional issue BUG-NNN — logged separately. Address it via 'bugfix [feature]' after this round completes."
-- Exception: trivial test-only fixes (missing assertion, wrong test fixture) can be fixed inline
-
-**Full workflow for new bugs**: When the user invokes "bugfix [feature]" after new bugs were logged, the workflow routes through the COMPLETE plan → tasks → implement cycle for those bugs, with document commits at each phase:
-  - **Plan**: bugfix sections appended to `plan.md` → committed as `spec(phase-2): [feature] bugfix plan (BUG-NNN, ...)`
-  - **Tasks**: bugfix tasks appended to `tasks.md` → committed as `spec(phase-3): [feature] bugfix tasks (BUG-NNN, ...)`
-  - **Implement**: each bugfix task follows its own RED→GREEN cycle → committed per fix
-  - Plan and tasks are NEVER skipped for new bugs — the full phase sequence is mandatory
-
-**Quickfix mode for trivial bugs**: If the user says "quickfix [feature]" instead of "bugfix [feature]":
-  - Plan section + tasks entry + fix are drafted in one logical pass
-  - The user sees a compact summary before approval
-  - ALL committed as ONE commit: `fix: [feature] BF-### - description (plan+tasks+fix)`
-  - The commit body includes plan ref and task ID for traceability
-  - Plan section and task entry ALWAYS exist — only commit granularity differs
-  - TDD tests are still written (same exceptions apply)
-  - Guardrails: user explicitly opts in; never inferred; separate commits still the default
-
-**What if a test cannot be written for a bug?** (e.g. visual layout issue, race condition, external dependency)
-- Note the reason in tasks.md next to the BF-### task
-- Apply the fix, then verify manually
-- The summary/close will flag the untested fix as a risk
-
-## Execution
-
-### TDD Mode Detection
-```
-SCAN tasks.md for `> **TDD**: Bypassed by user request`
-  IF found:
-    SET tdd_bypassed = true
-    NOTE: "TDD bypassed by user — implementation-only tasks, no test cycle."
-  IF not found:
-    SET tdd_bypassed = false
-    NOTE: "TDD active — phase-level RED-GREEN cycle enforced."
-```
-
-### Step 1: Validate prerequisites
-```
-IF specs/[feature]/tasks.md NOT EXISTS:
-  ERROR: "Run spec-kit-tasks first to generate task breakdown"
-IF specs/[feature]/plan.md NOT EXISTS:
-  ERROR: "Run spec-kit-plan first"
-IF specs/[feature]/spec.md NOT EXISTS:
-  ERROR: "Run spec-kit-specify first"
-```
-
-### Step 2: Load implementation context
-- LOAD `specs/[feature]/tasks.md` (REQUIRED)
-- LOAD `specs/[feature]/plan.md` (REQUIRED)
-- LOAD `specs/[feature]/data-model.md` (IF EXISTS)
-- LOAD `specs/[feature]/contracts/` (IF EXISTS)
-- LOAD `specs/[feature]/research.md` (IF EXISTS)
-- LOAD `specs/constitution.md` (IF EXISTS)
-- LOAD `specs/[feature]/quickstart.md` (IF EXISTS)
-- IF `specs/[feature]/bugs.md` EXISTS: LOAD bugs.md for bugfix task context
-
-### Step 3: Parse tasks.md
-Extract:
-- Task phases: Setup, Foundational, Core, Integration, Polish
-- Task dependencies: Sequential vs parallel execution rules
-- Task details: ID, description, file paths, parallel markers [P], [TEST] tags
-- Execution flow: Phase order and dependency requirements
-- TDD bypass header (if present)
-
-### Step 4: Phase-level TDD execution
-
-For each phase (Setup → Foundational → Core → Integration → Polish):
-Execute the entire phase as a batch, not task-by-task:
-
-```text
-  Phase N: [Phase Name]
-  
-  ═══ RED SUB-PHASE ═══
-  For EACH [TEST] task in this phase (in order):
-    a. WRITE the test(s)
-       - One behavior per test function
-       - Group related tests in the same file
-       - No mandatory 1:1 with implementation tasks:
-         * One test file can cover multiple implementation tasks
-         * One implementation task can have multiple test functions
-       - Real code, not mocks (unless truly unavoidable)
-       - Test behavior, not implementation
-    
-    b. RUN the specific test to verify RED:
-       terminal("pytest tests/test_file.py::test_name -v")
-       CONFIRM:
-         - Test fails (not errors from typos)
-         - Fails because the feature is missing
-         - ⚠️ This is EXPECTED — proves the test is valid. NOT a bug.
-         
-  ═══ GREEN SUB-PHASE ═══
-  For EACH implementation task in this phase (in order):
-    a. WRITE the simplest code to pass the test(s)
-       - Minimal — nothing more than needed
-       - Cheating is OK (hardcode, copy-paste — fix in refactor)
-    
-  After ALL implementation tasks in this phase are written:
-    b. RUN ONLY the tests relevant to this phase (NOT full suite):
-       terminal("pytest tests/test_auth.py -v")   # phase-specific test file(s)
-       CONFIRM:
-         - All tests for this phase pass ✓
-         - Do NOT run full test suite yet
-    
-    c. RUN the project build (if applicable):
-       terminal("npm run build") OR terminal("tsc --noEmit") OR terminal("go build")
-       NOTE: TypeScript projects MUST build — Vitest/Jest swallow type errors.
-    
-    d. UPDATE tasks.md — mark all tasks in this phase [X]
-```
-
-After marking tasks complete, record the phase in history.md and commit:
-
-1. **Record test count**: Note the number of tests run and passed for this phase.
-2. **Append to history.md**: Write an entry to `specs/[feature]/history.md` with the test pass status and task completion count.
-3. **Pre-commit guard**: READ `specs/[feature]/history.md` — confirm the phase entry is recorded. If missing, BLOCK — must append before commit.
-4. **Commit the phase**: `git add -A && git commit -m "feat: [feature] Phase N - [Phase Name]" --no-verify`
-
-```
-  ═══ Done with this phase ═══
-```
-
-**Execution rules:**
-- Test tasks always come before implementation tasks within a phase
-- All tests in a phase are written first (RED sub-phase), then all code (GREEN sub-phase)
-- No commits during RED sub-phase — commit happens once per phase at GREEN
-- No per-task regression runs — only run relevant tests for this phase
-- Parallel [P] tasks can be written in any order but still within RED/GREEN sub-phase boundaries
-
-#### TDD bypass mode (no test tasks)
-```text
-IF tdd_bypassed:
-  For each phase:
-    For EACH task in the phase:
-      a. IMPLEMENT directly
-      b. VERIFY manually (no automated tests to run)
-    UPDATE tasks.md — mark all tasks in phase [X]
-```
-
-After marking tasks complete: append to history.md, run pre-commit guard, then commit the phase.
-
-```text
-    git add -A
-    git commit -m "feat: [feature] Phase N - [Phase Name]" --no-verify
-```
-
-### Step 5: Progress reporting
-After each phase:
-- Report phase completed: N/Total phases
-- Report tasks completed: N/Total
-- Report tests passing: Yes/No
-- In bugfix mode: Also report bugfix task progress (BF-### completed/total)
-
-### Step 6: Handle errors
-- HALT execution if a non-parallel task cannot be completed
-- FOR parallel tasks [P]: continue with working tasks, report failed
-- PROVIDE clear error messages with context
-- SUGGEST next steps if implementation cannot proceed
-
-### Step 7: Full regression run — all existing tests
-
-After ALL phases are complete and committed, run the ENTIRE test suite.
-
-```text
-IF tdd_bypassed:
-  NOTE: "TDD was bypassed — skipping automated test verification."
-  PROCEED to Step 8 (build verification)
-  STOP
-```
-
-Detect and run the test framework. Then handle results:
-
-**If all tests pass:**
-1. REPORT: "All N tests pass. Feature implementation verified."
-2. **Append to history.md**: Write a full regression pass entry to `specs/[feature]/history.md`.
-3. PROCEED to Step 8 (build verification)
-
-**If any tests fail:**
-Classify each failure as NEW (implementation incomplete) or PRE-EXISTING (regression). Create umbrella bugfix task BF-REGRESSION-001 in tasks.md.
-
-For each regression:
-- DEBUG root cause → FIX code → RUN specific test to confirm GREEN
-
-After all regressions fixed:
-1. RUN full suite again
-2. IF all pass:
-   - **Append to history.md**: Write a regression fix entry to `specs/[feature]/history.md` noting BF-REGRESSION-001 resolved.
-   - **Pre-commit guard**: READ `specs/[feature]/history.md` — confirm the regression entry is recorded. If missing, BLOCK.
-   - Commit: `git commit -m "fix: [feature] BF-REGRESSION-001 - fix regressions" --no-verify`
-   - MARK BF-REGRESSION-001 as [X] in tasks.md
-   - REPORT: "All regressions fixed. All N tests pass."
-
-### Step 8: Build verification (if applicable)
-```bash
-IF npm run build / tsc --noEmit / go build / cargo build is available:
-  terminal("[build command]")
-  IF build fails: RETURN to fix compilation errors, then repeat Step 9 (full suite) then Step 10
-```
-
-## Implementation Rules (TDD Enforcement)
-
-- **Phase-level TDD**: All tests for a phase are written and verified RED first, then all code is written and verified GREEN. One commit per phase.
-- **RED verification is mandatory**: Every test must run and fail before implementation code is written. Without RED, the test proves nothing.
-- **GREEN verification at phase level**: After all implementation code, run the phase's tests to confirm green.
-- **No per-task commits**: Commit once per phase boundary, not after each individual test or task.
-- **No per-task regression runs**: Only run relevant tests for the current phase. Full suite runs once after all phases.
-- **Regression umbrella**: All post-implementation regressions are captured in one umbrella bugfix task (BF-REGRESSION-001), not individual bugs.
-- **TDD bypass**: If the user explicitly bypassed TDD, skip all automated test steps. The summary will note the bypass.
-- **Build after GREEN**: TypeScript projects MUST build — Vitest/Jest swallow type errors.
-
-### Iron Law: Why Tests Must Come First
-
-**If you wrote code before the test → delete it. Start over.** No exceptions without user permission.
-
-```
-Excuse                      | Reality
-----------------------------|-------------------------------------------
-"Too simple to test"        | Simple code breaks. Test takes 30s.
-"I'll test after"           | Tests-after pass immediately → prove nothing.
-"Already manually tested"   | Ad-hoc ≠ systematic. No record, can't re-run.
-"Deleting X hours wasteful" | Sunk cost. Keep unverified code = tech debt.
-"TDD is dogmatic"           | TDD finds bugs pre-commit, prevents regressions.
-"Tests after same goal"     | Tests-after = "what does it do?" Tests-first = "what should it do?"
-```
-
-In bugfix mode: Update bugs.md Status after fixing a bug (set to "resolved")
-
-## Phase Guardrail — STRICT
-
-This is the **ONLY** phase where code-editing tools are permitted.
-
-| Tool | Implement Phase | All Other Phases |
-|------|----------------|-----------------|
-| `write_file` (source code) | ALLOWED | **BLOCKED** |
-| `patch` (source code) | ALLOWED | **BLOCKED** |
-| `terminal` (build/compile/test) | ALLOWED | **BLOCKED** |
-| `write_file` (spec artifacts) | ALLOWED (tasks.md, bugs.md status) | Allowed (phase-specific only) |
-| `read_file`, `search_files`, `skill_view` | ALLOWED | ALLOWED |
-
-If you are in ANY other phase (Constitution, Specify, Clarify, Plan, Tasks, Review, Test), you MUST NOT call `write_file`, `patch`, or `terminal` for compilation/builds on source code files.
-
-### Bugfixing rule
-- Bug reports always go to `bugs.md` first (via `spec-kit-test`)
-- Bugfixes are NEVER implemented directly when a user mentions a bug
-- Bugfixes must follow: "bugfix [feature]" → plan → tasks → implement
-
-### Step 9: Append to history.md (before every commit)
-
-**Every commit in this skill must be preceded by a history.md entry.** This covers three commit types:
-
-1. **Per-phase commits** (Step 4h): history.md appended in Step 4f (test pass status included).
-2. **Bugfix commits** (BF-###, Step 5): history.md appended in Bugfix Mode step 3.
-3. **Regression fix commits** (BF-REGRESSION-001, Step 7): history.md appended in regression fix flow.
-
-**PRE-COMMIT GUARD** (applies to every commit):
-```text
-READ specs/[feature]/history.md
-IF the entry for the current work (phase completion, bugfix, or regression fix) is NOT recorded:
-  BLOCK: "Cannot commit — history.md is missing the entry. Append first."
-```
-
-**history.md entries MUST be appended BEFORE git commit -- never after.**
-
-## Completion
-
-Report:
-- Final status
-- TDD mode: Active / Bypassed by user
-- Phases completed: N/Total
-- Tests passing (TDD mode)
-- Regressions found and fixed (if any)
-- Build status (if applicable)
-- Summary of completed work
-- **Commit hash per phase**: `git log --oneline --grep="Phase [0-9]"`
-
-## Done When
-
-- [ ] All phases completed and committed
-- [ ] TDD mode (if active): Every test was verified RED before implementation
-- [ ] TDD mode (if active): Every phase's tests verified GREEN before commit
-- [ ] TDD mode (if active): Full regression suite passes — all tests green
-- [ ] TDD mode (if active): Regressions (if any) fixed via umbrella task
-- [ ] Build passes (if applicable)
-- [ ] All tasks in tasks.md marked [X] — no tasks deleted, status-only update
-- [ ] In bugfix mode: All bugfix tasks completed and verified
-- [ ] history.md entries appended for every commit:
-      - One entry per completed phase (with test pass count)
-      - One entry per bugfix (BF-###)
-      - One entry for full regression pass
-      - One entry for regression fix (if applicable)
-- [ ] PRE-COMMIT GUARD confirmed for every commit
-- [ ] Committed per phase boundary
-
-**Re-running this skill**:
-1. LOAD tasks.md and find the first incomplete phase
-2. RESUME from that phase's RED sub-phase
-3. PRESERVE all [X] completion markers from completed phases
-4. Only execute remaining incomplete phases
-
-## Prerequisite Enforcement
-
-**BLOCKED** if:
-- `spec-kit-specify` has not been run
-- `spec-kit-plan` has not been run
-- `spec-kit-tasks` has not been run
-
-**WARN** if:
-- `spec-kit-constitution` has not been run — proceeding without constitutional gates
+**Phase**: 4 · **Persona**: disciplined engineer building to spec — no scope creep, no unrequested refactoring; builder, not designer.
+**Purpose**: execute `tasks.md` phase by phase — the phase's tests RED, then code GREEN, then one commit. `BF-###` tasks run the same cycle.
+**Full procedure**: `spec-kit/references/skills/spec-kit-implement.md` (bugfix / quickfix, regression umbrella, re-run). **Rules that bind**: `spec-kit/references/evidence.md` (your word is not evidence; RED/GREEN/probe files every tier) · `spec-kit/references/commits.md`.
+
+## Before writing
+- `spec-kit/references/preflight.md`. **BLOCK** if `tasks.md`, `plan.md` or `spec.md` is missing. The only phase that edits source code.
+- Load tasks, plan, data-model, contracts, research, quickstart, constitution, bugs (as present). `> **TDD**: Bypassed` → no test cycle. Evidence rules are the same for every size.
+- MCP: `mcp_spec_kit_get_next_actions` — read the phase card now and after every compaction.
+
+## Per phase
+1. **RED** — write every `[TEST]` task of the phase; run them; each fails for the right reason. Save `evidence/-red.txt`. Then `mcp_spec_kit_acceptance_freeze(feature)` — a frozen `[AC-###]` test changes only with the user's approval (`spec-kit/references/acceptance.md`).
+2. **`[SEAM]`** — before the fixture: read-only probe of the real system → `evidence/-probe-.txt`; the fixture matches its shape. All sizes.
+3. **GREEN** — simplest code; run this phase's tests; save `evidence/-green.txt`; run the build (TypeScript must compile).
+4. Mark the phase's tasks `[X]`; fixed bugs → `claimed` + `Evidence:` (never `verified`).
+5. History on (phase card) → entry (`mcp_spec_kit_append_history`: phase, skill, **agent = Implemented-by**, artifacts, tests, evidence = the RED/GREEN/probe files, commit, note ≤ 25 words); history off → first phase writes `**Implemented-by**: ` into the tasks.md header and the commit body names the evidence files. Then `mcp_spec_kit_history_guard` + `mcp_spec_kit_lint_artifacts` → commit `feat: [feature] Phase N - [name]` (bugfix: `fix: [feature] BF-### - description`).
+- Legacy code without tests → characterisation test first. Untestable item → note beside the task; the close flags it.
+- No commits during RED; no per-task regression runs; a non-parallel task that cannot complete → HALT and report.
+- New bug mid-fix → log it (`mcp_spec_kit_next_id(kind="BUG")`), do not fix inline (trivial test-only fixes excepted).
+- A question the user would want to decide → `decisions.md` assumption (preflight 6).
+
+## After all phases
+6. Spec has ACs → route `accept [feature]` (`spec-kit-test` accept mode — full fast suites + this feature's e2e, failures → bugs → bugfix chain). No ACs → full regression `evidence/regression-.txt` + `ci:`; failures → `BF-REGRESSION-001`.
+7. Build verification. MCP: `mcp_spec_kit_advance_phase(from_phase=4)`.
+
+## Done when
+- [ ] Every phase committed with its RED + GREEN files and its history entry (or tasks.md `Implemented-by` when history is off); AC tests frozen after RED; every `[SEAM]` has a matching `probe:`; fixed bugs `claimed`, none `verified` here; all tasks `[X]`.
+
+## Next
+`accept [feature]` (automatic with ACs) → `spec-kit-test` for user-found bugs → **final review** (`spec-kit-review`) by the other agent or a fresh-context sub-agent.
diff --git a/src/skills/spec-kit-plan.md b/src/skills/spec-kit-plan.md
index ec08ba6..1db151b 100644
--- a/src/skills/spec-kit-plan.md
+++ b/src/skills/spec-kit-plan.md
@@ -13,110 +13,27 @@ metadata:
 
 # spec-kit-plan
 
-**Task Persona**: Adopt the mindset of a system architect and philosopher. Think deeply about tradeoffs, edge cases, failure modes, and scalability. Challenge assumptions. Every requirement must be accounted for — missing details now cause rework later. A thorough plan saves tenfold time in implementation.
-
-**Phase**: 2
-
-**Purpose**: Create or update the implementation plan at `specs/[feature]/plan.md`. Defines **HOW** to implement the spec: architecture, data flow, module boundaries, API contracts.
-
-The plan must:
-- **Study existing specs and codebase** to understand current architecture, patterns, and conventions
-- **Minimize impact on existing code** — design the implementation with the smallest possible footprint while respecting constitution rules and architecture principles
-- **Avoid code-level implementation details** — the plan describes approach and structure, not line-level implementation. Concrete coding belongs in the Implement phase.
-- **Resolve constitutional gates** — verify the approach aligns with project principles
-- **Generate design artifacts**: `research.md`, `data-model.md`, `contracts/*`, `quickstart.md`
-
-**When NOT to use**: For trivial changes (typo fix, config change) — skip planning and go directly to implementation.
-
-**Routing**: Load this skill when the user says "plan [feature]" or "create plan for [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-
-**Artifacts**:
-- `specs/[feature]/plan.md`
-- `specs/[feature]/research.md`
-- `specs/[feature]/data-model.md`
-- `specs/[feature]/quickstart.md`
-- `specs/[feature]/contracts/`
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Validate prerequisites
-```
-IF specs/[feature]/spec.md NOT EXISTS:
-  ERROR: "Run spec-kit-specify first"
-IF specs/constitution.md NOT EXISTS:
-  BLOCK: "No constitution found. Run spec-kit-constitution first."
-  HALT
-```
-
-### Load context
-```
-LOAD specs/[feature]/spec.md, specs/constitution.md (IF EXISTS)
-
-IF bugfix mode (reopened bugfix):
-  NOTE: "Bugfix mode — plan.md already exists. Will append bugfix sections only."
-  LOAD existing specs/[feature]/plan.md
-  LOAD bugs.md for bug context
-ELSE:
-  LOAD spec-kit/templates/plan-template.md
-  COPY spec-kit/templates/plan-template.md → specs/[feature]/plan.md
-```
-
-### Fill Technical Context
-Document: language/version, dependencies, storage, test framework, platform, project type, performance goals, constraints.
-
-### Constitutional Gates (advisory)
-Evaluate: simplicity (≤3 projects), anti-abstraction (use framework directly), integration-first (contracts defined).
-If gate fails without justification → document as violation in plan.
-
-### Research
-Generate `research.md`: decision → rationale → alternatives considered for each technology choice.
-
-### Design & Contracts
-Generate `data-model.md`: entities, fields, relationships, validation, state transitions.
-Generate `contracts/`: API specs, command schemas.
-Generate `quickstart.md`: key validation scenarios.
-
-### Project structure
-Choose template: Single project (`src/`, `tests/`) / Web app / Mobile + API.
-
-### Bugfix planning (bugfix mode)
-For each open bug: analyze root cause, append bugfix section to plan.md (do NOT remove existing plan content), set Plan Ref in bugs.md.
-
-**Additive-safe**: Append new bugfix sections at the end of plan.md. Never delete existing plan sections. You may modify existing sections minimally (e.g. mark a section as superseded by a bugfix). If a new fix contradicts an existing plan section, ask the user for guidance.
-
-### Note on commits
-Each skill commits its own artifacts immediately. See `spec-kit/references/auto-commit.md`.
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 2 — Plan
-- Artifact: `plan.md`, `research.md`, `data-model.md`, `contracts/*`, `quickstart.md`
-- Scope: all plan artifacts for this feature
-- Message: `"spec(phase-2): [feature] plan"`
-
-### Done When
-- [ ] All plan artifacts created (plan.md, research.md, data-model.md, contracts/*, quickstart.md)
-- [ ] Bugfix mode: plan sections appended only (additive-only) — existing content preserved
-- [ ] history.md entry appended
-- [ ] Committed
-
-## Completion
-- Generated artifacts list
-- Gate status (pass/fail with justifications)
-- Propose: `spec-kit-tasks`
-
-### Auto-Chaining (Bugfix Mode)
-After plan → automatically route to `spec-kit-tasks` (no user choice).
-
-## Common Pitfalls
-1. **Over-engineering simple features**: Not every feature needs research, data-model, and contracts. Generate only what's needed for clarity.
-2. **Ignoring constitution gates**: Gates are advisory but flagging violations helps the user understand trade-offs.
-3. **Skipping bugfix Plan Ref**: In bugfix mode, always add a Plan Ref to bugs.md — it provides traceability.
-
-## Prerequisite Enforcement
-**BLOCKED** if: spec.md does not exist, or constitution.md does not exist.
+**Phase**: 2 · **Persona**: system architect — trade-offs, failure modes, smallest footprint on existing code.
+**Purpose**: `specs/[feature]/plan.md` (+ `research.md`, `data-model.md`, `contracts/`, `quickstart.md` when the tier needs them) — HOW: architecture, data flow, boundaries, seams, acceptance test strategy. Approach, not line-level code.
+**Full procedure**: `spec-kit/references/skills/spec-kit-plan.md` · **Not for**: trivial changes.
+
+## Before writing
+- `spec-kit/references/preflight.md`. **BLOCK** if `spec.md` is missing. Load `spec.md`, `specs/constitution.md` (guidance), the codebase's patterns.
+- `plan.md` exists and not bugfix mode → **BLOCK** (`bugfix` / `reopen`). Bugfix mode → append only.
+
+## Steps
+1. Copy `spec-kit/templates/plan-template.md`; Technical Context — only the lines that matter. `design_dir` kept → `**Modules**:` names the design docs the close will patch (read them first — they describe what is built).
+2. Tier from spec.md (`spec-kit/references/sizing.md`): S → Summary, Current Design, Seams, Acceptance strategy, Rounds; M → + Design, and research / data-model / contracts / quickstart only when needed; L → all that apply. Bigger than the tier → stop, **ASK** to raise it.
+3. Constitution gates (advisory) — violations justified in Complexity Tracking.
+4. **External Seams** table — every DB function, HTTP contract, message, file format the feature touches (implement probes each). **Acceptance Test Strategy** — per AC: level, harness, test file, needs, result source (`spec-kit/references/acceptance.md`). The Security & Privacy rows of the spec get a design answer here (where the check lives).
+5. `research.md`: decision → rationale → alternatives, per real technology choice only.
+6. Questions the user would want to decide → ASK; no human → `decisions.md` assumption. Design choices within the plan's remit stay in plan.md.
+7. Bugfix mode: per open bug, root cause → ONE dated round under `## Rounds (ADR log)` (Context / Decision / Consequences / Plan Ref) → set `Plan Ref` in `bugs.md`. Never edit earlier rounds or `## Current Design`.
+
+## Done when
+- [ ] Plan artifacts for the tier written; bugfix: appended only.
+- [ ] MCP: `mcp_spec_kit_update_artifact(plan.md)` · `mcp_spec_kit_advance_phase(from_phase=2)` · `mcp_spec_kit_lint_artifacts` → 0 errors.
+- [ ] history.md entry, then commit (`spec-kit/references/preflight.md` procedure): `spec(phase-2): [feature] plan` (bugfix: `… bugfix plan (BUG-NNN, …)`).
+
+## Next
+`spec-kit-tasks` (bugfix mode and size S: automatically).
diff --git a/src/skills/spec-kit-refresh.md b/src/skills/spec-kit-refresh.md
index c5829b0..2fc3155 100644
--- a/src/skills/spec-kit-refresh.md
+++ b/src/skills/spec-kit-refresh.md
@@ -13,72 +13,14 @@ metadata:
 
 # spec-kit-refresh
 
-**Task Persona**: Adopt the mindset of an auditor reconciling intent with reality. Artifacts drift from code over time — bring them back into alignment without over-correcting. Be precise: flag what changed, propose updates, get approval.
+**Phase**: standalone · **Persona**: auditor reconciling intent with reality — flag, propose, get approval; never over-correct.
+**Purpose**: bring `spec.md`, `plan.md`, `data-model.md`, `contracts/` back in line with the code after manual changes — no close document, no health score (that is `spec-kit-summarize`).
 
-**Phase**: N/A (standalone)
+## Steps
+1. Preflight (`spec-kit/references/preflight.md`); requires `spec.md`. Load the artifacts and `git diff {branch_source} --name-status` (`specs/git-conventions.md`, default main).
+2. Per FR-### and per plan / data-model / contract item: Match / Mismatch / Missing / Unplanned.
+3. ≤ 5 discrepancies per session: "spec says … / code does … → update spec to match code?" **WAIT** for each; never bulk-apply.
+4. Apply approved patches only — additive or targeted, nothing deleted. May regenerate `plan.md` → `## Current Design`.
 
-**Purpose**: Reconcile spec/plan artifacts with actual code without generating a summary or close document. For manual code changes or mid-stream alignment.
-
-**When NOT to use**: To close a feature — use `spec-kit-summarize` instead.
-
-**Routing**: Load this skill when the user says "refresh [feature]" or "sync spec for [feature]". Standalone — no prerequisite routing needed.
- To verify fresh implementation — the implement skill's batch commit already captures the design.
-
-**Prerequisites**: `specs/[feature]/spec.md` must exist.
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Load artifacts and code state
-```
-LOAD specs/[feature]/spec.md, plan.md (IF EXISTS), data-model.md, contracts/
-RUN: git diff {branch_source} --name-status
-  (branch_source from specs/git-conventions.md, default: main)
-```
-
-### Identify discrepancies
-```
-For each FR-###: compare spec description against actual code.
-Classify: Match / Mismatch / Missing / Unplanned
-```
-
-### Present discrepancies to user (max 5 per session)
-```
-"spec.md says: [excerpt]"
-"Code does:   [actual behavior]"
-"→ Update spec to match code? (yes/no)"
-```
-
-### Refresh plan.md and data-model.md
-Same per-item approval for architecture, data model, and contract discrepancies.
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Refresh
-- Artifact: patched `spec.md`/`plan.md`
-- Scope: patched spec artifacts
-- Message: `"spec(refresh): [feature] reconcile artifacts"`
-
-## Completion
-### Done When
-- [ ] Each patch approved by user before applying
-- [ ] Additive-safe: spec/plan entries never deleted; modifications are minimal field updates
-- [ ] history.md entry appended (pre-commit guard verified)
-- [ ] Committed
-
-## Common Pitfalls
-
-1. **Using refresh instead of close**: Refresh doesn't generate a close document. The feature won't be marked complete.
-2. **Bulk patching without user approval**: Each discrepancy needs explicit yes/no. Don't auto-approve.
-
-## Key Difference from Summary
-
-| Aspect | summarize | refresh |
-|--------|-----------|---------|
-| Output | summary/close document | In-place patches |
-| Gap analysis | Full matrix | Per-item yes/no |
-| Spec health | Computed | Not computed |
-| When | End of feature | Mid-stream alignment |
+## Done when
+- [ ] Every patch approved before applying. history.md entry, then commit (`spec-kit/references/preflight.md` procedure): `spec(refresh): [feature] reconcile artifacts`.
diff --git a/src/skills/spec-kit-review.md b/src/skills/spec-kit-review.md
index a33ec25..48467e2 100644
--- a/src/skills/spec-kit-review.md
+++ b/src/skills/spec-kit-review.md
@@ -1,7 +1,8 @@
 ---
 name: spec-kit-review
-description: Load when the user says 'spec-kit review [feature]', 'speckit review [feature]', "review [feature]", "quality check [feature]", or "analyze [feature]" — cross-artifact consistency check (pre-implement) and code quality review (post-implement).
-version: 1.1.0
+description: >
+  Load when the user says 'spec-kit review [feature]', 'speckit review [feature]', 'spec-kit final review [feature]', 'speckit final review [feature]', "review [feature]", "final review [feature]", "merge readiness [feature]", "is [feature] ready to merge", "quality check [feature]", or "analyze [feature]" — pre-implement cross-artifact check (3.5) and the mandatory final merge-readiness review (5.5): spec conformance, constitution rules, code quality, merge checklist.
+version: 2.0.0
 author: Hermes Agent
 license: MIT
 category: software-development
@@ -13,413 +14,37 @@ metadata:
 
 # spec-kit-review
 
-**Phase**: 3.5 (Pre-implement optional gate) / 5.5 (Post-implement optional gate)
-
-**Purpose**: Provides quality checks at two points in the workflow, plus a
-third mode for reviewing already-closed features without altering history:
-
-1. **Pre-implement** (after tasks.md, before code): Verify spec/plan/tasks are coherent and internally consistent. READ-ONLY — outputs a report, no file changes.
-
-2. **Post-implement** (after tests green, before close): Review code quality — does the implementation match the constitution? Does it fulfill the spec? Are there deviations, quality issues, or technical debt introduced?
-
-3. **Closed-review** (feature is already closed): Same checks as post-implement but does NOT update history.md. If issues are found, offers to add refactoring tasks to tasks.md and reopen the feature.|
-
-**Prerequisites**:
-- Pre-implement mode: `spec.md` + `plan.md` + `tasks.md` must exist
-- Post-implement mode: `spec.md` + implemented code + passing tests
-
-**Artifacts**: None (read-only analysis output)
-
-**Routing**: Load this skill when the user says "review [feature]", "analyze [feature]", or "quality check [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-**Task Persona**: Adopt the mindset of a thorough code auditor. Check every artifact against every other — spec vs plan vs tasks vs code. Use web search to research best patterns and practices when evaluating architecture or implementation quality. Every finding must be actionable and backed by evidence. Does this hold up under scrutiny?
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Determine mode
-```
-DETECT current artifacts:
-  IF close.md or implementation-summary.md EXISTS:
-    MODE = closed-review (post-close code quality check)
-    NOTE: "Feature [feature] is closed. Review will NOT update history.md."
-
-  IF tasks.md exists AND no implementation code exists:
-    MODE = pre-implement (cross-artifact consistency check)
-
-  IF tests have passed AND writeable source code exists AND no close.md:
-    MODE = post-implement (code quality review)
-
-  IF both pre-implement and post-implement conditions match:
-    ASK user: "Run pre-implement review (spec/plan/tasks), post-implement review (code quality), or both?"
-
-  IF mode is still undetermined:
-    ASK user: "Cannot auto-detect mode. Which review? (pre-implement / post-implement / closed-review)"
-```
-
----
-
-## Pre-Implement Mode: Cross-Artifact Consistency
-
-### Step 1: Validate prerequisites
-```
-IF specs/[feature]/spec.md NOT EXISTS:
-  ERROR: "Run spec-kit-specify first"
-IF specs/[feature]/plan.md NOT EXISTS:
-  WARN: "No plan.md — analysis limited to spec only"
-IF specs/[feature]/tasks.md NOT EXISTS:
-  WARN: "No tasks.md — cannot verify task coverage"
-```
-
-### Step 2: Load artifacts
-From **spec.md**:
-- Functional Requirements (FR-###)
-- Success Criteria (SC-###)
-- User Stories
-- Edge Cases
-
-From **plan.md** (IF EXISTS):
-- Architecture/Stack choices
-- Data Model references
-- Constitutional Gates
-- Technical constraints
-
-From **tasks.md** (IF EXISTS):
-- Task IDs
-- Descriptions
-- Phase grouping
-- Parallel markers [P]
-- File path references
-
-From **constitution.md** (IF EXISTS):
-- Principle names
-- MUST/SHOULD statements
-
-From **bugs.md** (bugfix mode only, IF EXISTS):
-- Bug IDs (BUG-###)
-- Bugfix tasks (BF-###)
-- Severity levels
-- Requires Clarification flags
-
-### Step 3: Build semantic models
-Create internal representations:
-- **Requirements inventory**: FR-### with imperative-phrase slug
-- **User story inventory**: Discrete actions with acceptance criteria
-- **Task coverage mapping**: Task → Requirement mapping
-- **Constitution rule set**: Principles and normative statements
-
-### Step 4: Detection passes
-
-**A. Duplication Detection**
-- Identify near-duplicate requirements
-- Mark lower-quality phrasing for consolidation
-
-**B. Ambiguity Detection**
-- Flag vague adjectives (fast, scalable, secure, intuitive, robust)
-- Flag unresolved placeholders (TODO, TKTK, ???, )
-
-**C. Underspecification**
-- Requirements with verbs but missing object or measurable outcome
-- User stories missing acceptance criteria alignment
-- Tasks referencing undefined files/components
-
-**D. Constitution Alignment**
-- Any requirement or plan element conflicting with MUST principles
-- Missing mandated sections or quality gates
-
-**E. Naming Conventions** (pre-implement)
-- Consistent naming patterns across spec, plan, and tasks
-- File paths in tasks follow project conventions
-- Terminology consistent between spec and plan
-
-**F. Documentation Completeness** (pre-implement)
-- Are all required spec sections present (FRs, edge cases, success criteria)?
-- Does plan.md document architecture decisions?
-- Are there TODOs or placeholders that should be resolved before coding?
-
-**G. User-Defined Custom Gates** (pre-implement)
-**H. Coverage Gaps** (only if tasks.md exists)
-- Requirements with zero associated tasks
-- Tasks with no mapped requirement/story
-- Success Criteria requiring buildable work not in tasks
-
-**I. Inconsistency**
-- Terminology drift (same concept named differently)
-- Data entities in plan but absent in spec
-- Task ordering contradictions
-
-**J. Bugfix Coverage (bugfix mode only)**
-- Bugs with no corresponding bugfix task (BF-###)
-- Bugfix tasks not referencing a plan bugfix section
-- Bugfix tasks without verification/regression test tasks
-- Unclear mapping between bug and fix approach
-
-### Step 5: Severity assignment
-Use heuristic:
-- **CRITICAL**: Violates constitution MUST, or requirement with zero coverage blocking baseline
-- **HIGH**: Duplicate/conflicting requirement, ambiguous security/performance attribute
-- **MEDIUM**: Terminology drift, missing non-functional task coverage
-- **LOW**: Style/wording improvements, minor redundancy
-
-### Step 6: Produce pre-implement report
-OUTPUT:
-
-```
-# Pre-Implement Review: [Feature]
-
-## Findings Table
-
-| ID | Category | Severity | Location | Summary | Recommendation |
-|----|----------|----------|----------|---------|----------------|
-| A1 | Duplication | HIGH | spec.md:L120-134 | Two similar requirements... | Merge phrasing |
-...
-
-## Coverage Summary Table
-
-| Requirement | Has Task? | Task IDs | Notes |
-|-------------|-----------|----------|-------|
-| FR-001 | Yes | T001, T002 | |
-| FR-002 | No | --- | Missing coverage |
-
-## Constitution Alignment Issues
-[If any]
-
-## Unmapped Tasks
-[If any]
-
-## Uncovered Bugs (bugfix mode)
-[If any]
-
-## Metrics
-- Total Requirements: N
-- Total Tasks: N
-- Coverage %: X%
-- Ambiguity Count: N
-- Duplication Count: N
-- Critical Issues: N
-```
-
-### Step 7: Next actions (pre-implement)
-```
-IF CRITICAL issues exist:
-  - Recommend resolving before spec-kit-implement
-  - Suggest explicit remediation commands
-  - In bugfix mode: Recommend fixing bug coverage gaps before implementing fixes
-
-IF only LOW/MEDIUM:
-  - User may proceed
-  - Provide improvement suggestions
-```
-
----
-
-## Post-Implement Mode: Code Quality Review
-
-### Step 1: Validate prerequisites
-```
-IF specs/[feature]/spec.md NOT EXISTS:
-  ERROR: "Run spec-kit-specify first — cannot review without requirements"
-IF no implementation code detected:
-  ERROR: "No implementation found — run spec-kit-implement first"
-```
-
-### Step 2: Load context
-```
-LOAD specs/[feature]/spec.md (REQUIRED)
-LOAD specs/[feature]/constitution.md (IF EXISTS)
-LOAD specs/[feature]/plan.md (IF EXISTS)
-LOAD specs/[feature]/tasks.md (IF EXISTS)
-
-CAPTURE git diff or file list showing what was implemented
-```
-
-### Step 3: Code quality checks
-
-**A. Architecture & Design**
-- Does the code structure follow the plan's architecture?
-- Are there architectural violations (layers bypassed, circular dependencies)?
-- Is the code in the correct locations per the plan?
-
-**B. Spec Fulfillment**
-- For each FR-### in spec.md: does the implementation satisfy it?
-- For each success criterion: is it demonstrably met?
-- Are there edge cases from the spec that are unhandled?
-
-**C. Constitution Alignment**
-- Does the code respect MUST principles from constitution.md?
-- Are there quality gates or standards that were skipped?
-
-**D. Naming Conventions** (post-implement)
-- Does the code follow project naming conventions?
-- Are file/module/function names consistent with plan.md?
-- Public API names match spec terminology?
-
-**E. Documentation Completeness** (post-implement)
-- Are there README, API docs, or inline docs that need updating?
-- If this feature adds or changes a public interface, is it documented?
-- Are there changelog entries or migration notes needed?
-
-**F. User-Defined Custom Gates** (post-implement)
-**G. Code Quality**
-- Naming conventions — consistent and descriptive?
-- Error handling — are failures caught and reported appropriately?
-- Duplication — are there copy-paste patterns that should be extracted?
-- Complexity — are there functions/modules that are too complex?
-- Security — obvious vulnerabilities (hardcoded secrets, injection vectors)?
-
-**H. Test Quality** (if tests exist)
-- Do tests actually test the behaviors described in spec.md?
-- Are there tests for edge cases from the spec?
-- Are tests meaningful (assert behavior, not implementation)?
-
-### Step 4: Severity assignment
-Same heuristic as pre-implement mode.
-
-### Step 5: Produce post-implement report
-```
-# Post-Implement Review: [Feature]
-
-## Spec Fulfillment
-
-| FR-ID | Status | Notes |
-|-------|--------|-------|
-| FR-001 | ✅ Fulfilled | Implemented as specified |
-| FR-002 | ⚠️ Partial | Missing error handling for edge case |
-| FR-003 | ❌ Missing | Not implemented |
-
-## Constitution Alignment
-[If any violations]
-
-## Code Quality Findings
-
-| ID | Category | Severity | File | Finding | Suggestion |
-|----|----------|----------|------|---------|------------|
-| Q1 | Duplication | MEDIUM | src/auth.py:45-60 | Repeated validation logic | Extract to helper |
-...
-
-## Metrics
-- Requirements fulfilled: N/Total
-- Code quality issues: N (Critical/High/Medium/Low)
-- Constitution violations: N
-- Test coverage adequacy: Satisfactory / Needs improvement / Not assessed
-```
-### Step 6: Next actions — deviation resolution (post-implement)
-
-For each deviation found between code and spec/plan during post-implement review:
-
-```
-FOR each FR-### or plan section where code differs from spec/plan:
-  PRESENT the discrepancy to the user:
-    "FR-NNN in spec.md says: [original requirement]
-     Implementation does: [what code actually does]
-     
-     Options:
-     1. Update spec/plan to match implementation (intentional deviation — document it)
-     2. Keep spec/plan as-is — change code to match (create a bugfix task)
-     3. Skip for now (flag for Phase 6 close to resolve)"
-
-  WAIT for user decision before proceeding to the next discrepancy.
-
-  IF user picks 1:
-    PATCH spec.md or plan.md to reflect what was implemented
-    ADD note: "(Updated by post-implement review)"
-    NOTE: "spec.md updated — deviation documented."
-    These spec/plan patches will be committed by Phase 6 (summarize/close).
-
-  IF user picks 2:
-    ADD bug to bugs.md: "BUG-NNN: Implementation does not match spec FR-NNN"
-    NOTE: "Bug logged — run 'bugfix [feature]' to align implementation with spec."
-
-  IF user picks 3:
-    NOTE: "Deferred to Phase 6 close."
-```
-
-### Step 7: Next actions (non-deviation)
-
-```
-IF mode == closed-review:
-  PRESENT findings to user
-  IF CRITICAL or HIGH issues exist:
-    PROMPT: "N issues found. Options:
-      1. Add refactoring tasks to tasks.md (no reopen)
-      2. Add tasks and reopen the feature (reopen [feature])
-      3. Note for future work, no changes"
-    IF user picks 1 or 2:
-      APPEND refactoring tasks to tasks.md for each issue
-      NOTE: "Refactoring tasks added to tasks.md."
-    IF user picks 2:
-      NOTE: "Feature needs reopening. Run 'reopen [feature]' to start the fix loop."
-    IF user picks 3:
-      NOTE: "Issues noted for future work. No changes made."
-  ELSE (only LOW/MEDIUM):
-    NOTE: "Minor issues found. No code changes needed."
-
-ELSE (normal pre/post-implement):
-  IF CRITICAL issues exist:
-    - Block: Resolve before closing feature
-    - Recommend adding bugs to bugs.md
-    - Proceed to bugfix cycle
-
-  IF only LOW/MEDIUM:
-    - User may proceed to close
-    - Note improvement suggestions for future
-```
-
-### Append to history.md and Commit
-
-```text
-IF mode == closed-review:
-  NOTE: "Review on closed feature — history.md not updated."
-ELSE:
-  Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-  - Phase: Phase 3.5 or Phase 5.5 (mode-dependent) — Review
-  - Artifact: review report
-  - Scope: review findings
-  - Message: `"spec(review): [feature] review findings"`
-```
-
-## Completion
-
-Report:
-- Mode used: Pre-implement / Post-implement / Both
-- Findings count by severity
-- Coverage percentage (pre-implement)
-- Spec fulfillment status (post-implement)
-- Overall recommendation: Proceed / Fix critical issues first
-
-## Next Skills
-
-- Pre-implement mode: Propose `spec-kit-implement` when all CRITICAL issues resolved
-- Post-implement mode: Propose `spec-kit-summarize` to close the feature
-- Closed-review mode: Propose `reopen [feature]` if issues need fixing
-- Either mode: Propose `spec-kit-specify` or `spec-kit-plan` to fix issues found
-- In bugfix mode: Propose `spec-kit-tasks` to add missing bugfix tasks
-
-**Re-running this skill**:
-1. Re-run the relevant detection passes based on mode
-2. COMPARE results against previous run
-3. Report only changes/new findings
-4. Preserve previous report for comparison
-
-## Prerequisite Enforcement
-
-Pre-implement:
-- **BLOCKED** if: `spec-kit-specify` has not been run (spec.md required)
-- **WARN** if: plan.md or tasks.md missing — analysis limited to what exists
-
-Post-implement:
-- **BLOCKED** if: `spec-kit-specify` has not been run (spec.md required)
-- **BLOCKED** if: No implementation code detected
-- **WARN** if: constitution.md missing — cannot check constitutional alignment
-
-Closed-review:
-- **BLOCKED** if: `spec-kit-specify` has not been run (spec.md required)
-- **BLOCKED** if: No implementation code detected
-- **NOTE**: tasks.md will be modified only with user approval
-
-## Key Constraint
-
-**READ-ONLY on source code** — This skill does NOT modify source code files. It only outputs a report.
-**Exception**: In closed-review mode, may append refactoring/remediation tasks to `tasks.md` with user approval.
+**Phase**: 3.5 (pre-implement) / 5.5 (final — **mandatory before close**) / closed-review · **Persona**: senior architect and last reviewer before merge — structural problems, spec drift, broken rules, security; not a style checker.
+**Purpose**: pre-implement = does spec/plan/tasks hold together and fit the codebase (report). **Final** = does the code do what the spec says, obey the rules, is it good, is it mergeable → `review-final.md` round whose verdict gates the close. Both include a **devil's advocate** pass.
+**Full procedure**: `spec-kit/references/skills/spec-kit-review.md` · template `spec-kit/templates/review-final-template.md`.
+
+## Before reviewing
+- Preflight checks 1 and 4 (`spec-kit/references/preflight.md`). Mode: close doc → closed-review; tasks.md and no code → pre-implement; all tasks `[X]`, no open bug → **final**; open bugs → refuse ("bugfix first"); unclear → **ASK**.
+- SIZE from spec.md (`spec-kit/references/sizing.md`): S skips the pre-implement review and the stack research; M runs the lite pre-implement; L requires it in full. Evidence and the acceptance round are checked the same way at every size.
+- **Author check** (`spec-kit/references/evidence.md`): `Implemented-by` (history.md implement entries, or the tasks.md header when history is off) = you → *self-review*; for the final review prefer the other agent, else a **fresh-context sub-agent** (procedure + feature path + base only; no transcript).
+- Final review: read the code and the spec **before** `decisions.md` so the author's reasoning does not anchor you; then every assumption is a review item.
+
+## Pre-implement (3.5)
+1. Load spec, plan, tasks, constitution, the epic's cross-feature rules and the modules' design docs when the project keeps them; requirement ↔ task coverage; the Security & Privacy table answered in the plan.
+2. M (lite): underspecification, coverage gaps, codebase fit, design soundness. L: + duplication, ambiguity, naming, completeness, inconsistency, best practice (research the stack).
+3. **Devil's advocate**: the strongest case against the plan + a simpler alternative; a pre-mortem ("three months later it failed — why?"); abuse cases per new seam (authz, tenant crossover, input, data exposure, logging); the riskiest assumptions in decisions.md. ≤ 5 objections, each answered: accepted / rebutted with evidence / deferred. L: run it as a separate sub-agent (different model when available).
+4. Report + commit `spec(review): [feature] review findings`. CRITICAL → resolve before implement.
+
+## Final (5.5) — one `## Round N` appended, **exceptions only**
+1. Inputs: spec, plan, tasks, data-model, contracts, constitution, `specs/merge-checklist.md` (missing → from `spec-kit/templates/merge-checklist-template.md`, **ASK** to confirm), AGENTS.md / rule files, `git diff ...HEAD`, `evidence/`, bugs.md, acceptance.md.
+2. Mechanical: `mcp_spec_kit_diff_scan(feature)` → `evidence/final-diff-scan.txt`; every checklist command → `evidence/final-.txt`; `ci:` for the reviewed commit.
+3. **§1** — one coverage line (FR n/N, SC, edge cases, acceptance round PASS @ sha, frozen unchanged) + rows ONLY for ⚠️ / ❌ / ↔ / 👤. Missing = CRITICAL; ↔ → **WAIT** (patch spec, log a bug, or defer). Manual / deferred ACs unconfirmed → 👤.
+4. **§2** — every applicable constitution MUST, checklist P-item, AGENTS.md rule, epic cross-feature rule, design-doc invariant and **spec Security & Privacy row** verdicted with `path:line`; violated MUST = HIGH (CRITICAL if security / data / non-negotiable).
+5. **§3** — findings on the changed code: architecture, error chains, security, data integrity, concurrency, duplication, complexity, API surface, tests (behaviour not implementation; fixtures match `probe:` files; RED/GREEN files per phase). Stack research: M/L.
+6. **§4 Devil's advocate** — try to break it with concrete inputs (another tenant's id, empty/stale period, concurrent edit, failing dependency, unauthorized role); "would this test still pass if the code were wrong?"; argue the opposite of the verdict. L: separate sub-agent. ≤ 5 objections, each answered; unanswered blocks READY for L.
+7. **§5** checklist table with evidence files. **Verdict**: CRITICAL/HIGH or blocking ❌ → `NOT READY`; no defect but owner confirmations pending → `AWAITING-OWNER`; MEDIUM / non-blocking only → `READY-WITH-FOLLOWUPS`; else `READY`. Write `**Verdict**:` and `**Reviewed-commit**:`.
+8. NOT READY → bugs for each CRITICAL/HIGH (`mcp_spec_kit_next_id`), confirm with the user → `bugfix [feature]`, new round. AWAITING-OWNER → ask the owner; their quoted answer → specs-only Round N+1 (no code change ⇒ not stale). §6: PR description incl. "strongest objections and how they were answered".
+
+## Severity
+CRITICAL / HIGH / MEDIUM only; a finding must harm correctness, security, performance, maintainability or testability — style and taste → delete. A broken explicit project rule is never a nitpick.
+
+## Done when
+- [ ] Pre: report, history entry when on (`Phase 3.5`), commit. Final: round with Verdict + Reviewed-commit, §2 rules verdicted, §4 objections answered, §5 evidence; `mcp_spec_kit_lint_artifacts` → 0 errors; history entry when on (`Phase 5.5`), commit `spec(review): [feature] final review (verdict: X)`. Closed-review: report only, no history entry.
+
+## Next
+Pre → `spec-kit-implement`. Final READY / READY-WITH-FOLLOWUPS → `spec-kit-summarize`. AWAITING-OWNER → the owner, then Round N+1. NOT READY → `bugfix [feature]`.
diff --git a/src/skills/spec-kit-specify.md b/src/skills/spec-kit-specify.md
index 4c104fd..ed20539 100644
--- a/src/skills/spec-kit-specify.md
+++ b/src/skills/spec-kit-specify.md
@@ -13,88 +13,28 @@ metadata:
 
 # spec-kit-specify
 
-**Task Persona**: Adopt the mindset of a curious detail-gatherer. Your job is to extract every relevant detail from the user before writing anything. Ask clarifying questions. Probe edge cases. Challenge vague statements. A complete spec answers WHAT and WHY — the HOW comes later. Every requirement must be testable.
-
-**Phase**: 1
-
-**Purpose**: Create or update a feature specification at `specs/[feature]/spec.md`. Defines **WHAT** users need and **WHY** — the feature, refactoring, or enhancement in full detail. Captures functional requirements (FR-###), user scenarios, success criteria, entities, and edge cases. 
-
-**No implementation details, no code, no technology choices.** The spec describes what the system should do, not how to build it. Architecture decisions, data models, and technical approach belong in the Plan phase.
-
-**When NOT to use**: For tiny unambiguous changes (typo fix, rename), skip straight to implementation.
-
-**Routing**: Load this skill when the user says "create a spec for [feature]" or "specify [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-
-**Artifacts**:
-- `specs/[feature]/spec.md`
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Validate prerequisites
-```
-IF specs/constitution.md NOT EXISTS:
-  BLOCK: "No constitution found. Project setup is mandatory — run spec-kit-constitution first."
-  HALT
-```
-
-### Parse user description
-- Extract: actors, actions, data, constraints
-- If empty: ERROR "No feature description provided"
-
-### Generate short name
-2-4 word action-noun format: "user-auth", "oauth2-api-integration"
-
-### Create feature directory
-```
-DETERMINE prefix (next sequential number: 001, 002...)
-CREATE: specs/[###]-[short-name]/
-```
-
-### Generate spec.md
-Copy `spec-kit/templates/spec-template.md` → `specs/[feature]/spec.md`
-
-Populate with:
-- **User Scenarios**: P1/P2/P3 with Given/When/Then
-- **Functional Requirements**: FR-001, FR-002... — testable, technology-agnostic
-- **Success Criteria**: Measurable outcomes
-- **Key Entities**: Domain objects only (no implementation)
-- **Edge Cases**: Error conditions, boundaries
-
-### Apply constraints
-- MAX 3 `[NEEDS CLARIFICATION]` markers
-- NO implementation details (tech stack, frameworks, APIs)
-- Prioritize: scope > security > UX > technical
-
-
-### Note on commits
-Each skill commits its own artifacts immediately. See `spec-kit/references/auto-commit.md`.
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 1 — Specify
-- Artifact: `specs/[feature]/spec.md`
-- Scope: `specs/[feature]/spec.md`
-- Message: `"spec(phase-1): [feature] spec"`
-
-### Done When
-- [ ] spec.md created with FR-### requirements numbered sequentially
-- [ ] No existing content deleted; modifications minimal (additive-safe)
-- [ ] history.md entry appended
-- [ ] Committed
-
-## Completion
-- Feature directory path, spec file path
-- Propose: `spec-kit-clarify` or `spec-kit-plan`
-
-## Common Pitfalls
-1. **Implementation details in spec**: Focus on user value. Move architecture decisions to the Plan phase.
-2. **Too many `[NEEDS CLARIFICATION]` markers**: Keep to 3 max. If more, the feature scope is too vague — clarify with the user first.
-3. **Over-specifying**: For simple features, a single paragraph + 2-3 FRs is enough. Don't force full template on trivial changes.
-
-## Prerequisite Enforcement
-**BLOCKED** if: constitution.md does not exist.
+**Phase**: 1 · **Persona**: curious detail-gatherer — WHAT and WHY, every requirement testable; the HOW comes later.
+**Purpose**: create `specs/[feature]/spec.md` — user scenarios, FR-###, AC-### (Given/When/Then + verify level), Security & Privacy, success criteria, edge cases. No technology choices.
+**Full procedure**: `spec-kit/references/skills/spec-kit-specify.md` · **Not for**: typo / rename / config value.
+
+## Before writing
+- `spec-kit/references/preflight.md`. **BLOCK** if `spec.md` exists → `bugfix` / `reopen`.
+- Do not load `spec-kit-workflow` (routing only).
+
+## Steps
+1. Parse the description into actors, actions, data, constraints; empty → error.
+2. Name: 2–4 words action-noun + next number → `specs/NNN-short-name/` (MCP: `mcp_spec_kit_init_feature`).
+3. Copy `spec-kit/templates/spec-template.md`. Fill stories (P1/P2/P3), FR-### (testable, technology-agnostic), **Security & Privacy table** (every row answered — "None — because …" is valid), SC-###, entities, edge cases.
+4. **ACs** (`spec-kit/references/acceptance.md`): every scenario and important edge case → `**AC-###** (FR-…) Given/When/Then — Verify: `; every FR named by ≥ 1 AC; ids `mcp_spec_kit_next_id(kind="AC")`.
+5. ≤ 3 `[NEEDS CLARIFICATION]` markers — more → ask first. Priority: scope > security > UX > technical.
+6. `epics_dir` kept (`specs/git-conventions.md`) → `**Epic**: ` in the header (ASK which, or none); the epic must be reviewed (`[epics_dir]//review.md` GO) — its `features.md` row gets this spec dir and size now (add the row if missing, with approval).
+7. **Size — always ASK** (`spec-kit/references/sizing.md`): score the signals, offer S/M/L with the recommendation first "(Recommended)" + reason + what each produces. Write `**Size**: X — `; ruling in `decisions.md` (unattended → assumption).
+8. Size S (single bugfix / small enhancement): the spec is a few lines — 1–3 FRs, 1–2 ACs, one Security & Privacy line. After the user confirms it: auto-chain `spec-kit-plan` → `spec-kit-tasks`, ONE commit `spec(phase-1-3): [feature] spec, plan, tasks`.
+
+## Done when
+- [ ] spec.md written; FR/AC ids ascending; Security & Privacy filled; `**Size**:` set from the user's answer.
+- [ ] MCP: `mcp_spec_kit_update_artifact(spec.md)` · `mcp_spec_kit_advance_phase(from_phase=1)` · `mcp_spec_kit_lint_artifacts` → 0 errors.
+- [ ] history.md entry, then commit (preflight commit procedure): `spec(phase-1): [feature] spec`.
+
+## Next
+Markers remain → `spec-kit-clarify`; else `spec-kit-plan`. S: plan + tasks chained → `spec-kit-implement`. L: plan, then the pre-implement review is required.
diff --git a/src/skills/spec-kit-summarize.md b/src/skills/spec-kit-summarize.md
index 9d951d4..f60f8e7 100644
--- a/src/skills/spec-kit-summarize.md
+++ b/src/skills/spec-kit-summarize.md
@@ -1,7 +1,8 @@
 ---
 name: spec-kit-summarize
-description: Load when the user says 'spec-kit summarize [feature]', 'speckit summarize [feature]', 'spec-kit close [feature]', 'speckit close [feature]', "summarize [feature]", "close [feature]", or "implementation summary for [feature]" — Phase 6 mandatory close with spec health score.
-version: 1.1.0
+description: >
+  Load when the user says 'spec-kit summarize [feature]', 'speckit summarize [feature]', 'spec-kit close [feature]', 'speckit close [feature]', "summarize [feature]", "close [feature]", or "implementation summary for [feature]" — Phase 6 mandatory close: spec health score, ADRs written/updated, AGENTS.md kept current.
+version: 2.0.0
 author: Hermes Agent
 license: MIT
 category: software-development
@@ -13,402 +14,31 @@ metadata:
 
 # spec-kit-summarize
 
-**Phase**: 6 (Summary / Close — Mandatory)
-
-**Task Persona**: Adopt the mindset of a thorough code auditor. Verify every claim against actual code — check spec.md, plan.md, and the git diff together. Use web search to research best patterns and practices when evaluating architecture decisions. Describe exactly what changed, why, and whether it matches the spec. No filler, no fluff. Detail is proportionate to actual work done.
-
-**Purpose**: When implementation is complete and testing is done, produce either a full `implementation-summary.md` or a lightweight `close.md`. Computes spec health score (0-100%), patches spec.md/plan.md for intentional deviations. **Mandatory** before a feature can be marked complete.
-
-**When NOT to use**: For mid-stream alignment — use `spec-kit-refresh` instead.
-
-**Routing**: Load this skill when the user says "summarize [feature]" or "close [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Git Commit Guidelines
-See `spec-kit/references/auto-commit.md`. Commits use `--no-verify`. Branch guard handled by preflight.md.
-
-
-**When to run**:
-- **After bugfix loop completes** (all bugs verified) — suggested as mandatory close (user decides when to run it)
-- User says: "Summarize [feature]" — full gap analysis
-- User says: "Close [feature]" — lightweight close
-
-**Prerequisites**: `spec-kit-implement` must have been run (tasks.md exists)
-**Artifacts**:
-- `specs/[feature]/implementation-summary.md` (full gap analysis report)
-- `specs/[feature]/close.md` (lightweight close document)
-- `specs/[feature]/spec.md` (auto-updated to reflect intentional deviations)
-- `specs/[feature]/plan.md` (auto-updated to reflect intentional deviations)
-
-## Execution
-
-### Determine Mode
-```
-IF user explicitly says "close [feature]":
-  USE lightweight close mode → close-template.md
-  NOTE: "Lightweight close — captures key decisions and state without deep gap analysis."
-
-ELIF user explicitly says "summarize [feature]":
-  USE full summary mode → implementation-summary-template.md
-  RUN all steps below
-
-ELIF all bugs in bugs.md have Status: verified:
-  NOTE: "All bugs verified. Suggest running 'close [feature]' or 'summarize [feature]' to complete Phase 6 (mandatory)."
-  PROMPT user for which mode: full summary or lightweight close
-  USE the mode they selected
-
-ELSE:
-  USE full summary mode (default)
-
-OUTPUT RULE — applies to both modes:
-  The length and detail of the summary MUST be proportional to the actual
-  code changes made, not to the size of spec.md or tasks.md.
-  
-  GIT DIFF determines depth:
-    - Few files changed → short, precise summary of what was touched
-    - Many files / complex changes → thorough description per file/area
-    - Single bugfix → one paragraph covering root cause + fix
-  
-  Always produce a precise, factual description of what code was changed
-  and why. Avoid generic filler text. Every sentence should reflect a real
-  change visible in the diff.
-```
-
-### Load artifacts and detect TDD mode
-```
-LOAD specs/[feature]/spec.md, plan.md, tasks.md
-LOAD data-model.md, contracts/, research.md, quickstart.md, clarify.md (IF EXISTS)
-LOAD bugs.md (IF EXISTS), constitution.md (IF EXISTS)
-
-SCAN tasks.md for `> **TDD**: Bypassed by user request`
-  IF found: SET tdd_bypassed = true
-  IF not found: SET tdd_bypassed = false
-```
-
-### Analyze tasks.md completion
-```
-SCAN all tasks:
-  COUNT total tasks
-  COUNT completed tasks (marked [X])
-  COUNT incomplete tasks (marked [ ])
-  IDENTIFY remaining work from incomplete tasks
-
-IF all tasks are complete:
-  SET all task markers to [X]
-  WRITE updated tasks.md
-```
-
-### Analyze bugs.md status
-```
-IF bugs.md EXISTS:
-  SCAN all bugs:
-    COUNT total bugs
-    COUNT verified
-    COUNT resolved
-    COUNT open
-
-  IF all bugs verified or resolved:
-    SET any open bugs to Status: verified
-    WRITE updated bugs.md
-```
-
-### Compare code against spec and plan (git diff)
-*Skip in lightweight close mode*
-```
-RUN: git diff {branch_source} --name-status
-  OR: git log --oneline --name-only HEAD..{branch_source}
-  (branch_source from specs/git-conventions.md, default: main)
-  CAPTURE list of files changed, added, deleted
-
-FOR each file changed:
-  MATCH to task descriptions in tasks.md
-  MATCH to functional requirements in spec.md (FR-###)
-  MATCH to architecture/data-model sections in plan.md
-
-IDENTIFY:
-  - Files that correspond to planned tasks → mark as implemented
-  - Files that have NO corresponding task or requirement → flag as "unplanned change"
-  - Requirements/FRs that have NO implementing files → flag as "gap — not implemented"
-  - Plan sections (data-model entities, contracts) with no corresponding code → flag as "gap — deferred"
-```
-
-### Build gap analysis
-*Skip in lightweight close mode*
-```
-FOR EACH requirement/story/entity/contract in spec.md and plan.md:
-  VERDICT:
-    ✅ Resolved  — implemented as planned (code exists, tests pass)
-    ✅ Resolved  — intentional deviation (code differs from plan, rationale documented)
-    ⚠️ Acknowledged — deferred (not critical, tracked for future)
-    ❌ Not Done  — missing with no documented reason (should be added to bugs.md or new spec)
-
-FOR each gap marked "❌ Not Done":
-  RECOMMEND: add a bug to bugs.md or create a follow-up spec
-  WRITE: "Missing implementation: [requirement] — see implementation-summary.md gap analysis"
-
-FOR each gap marked "⚠️ Acknowledged":
-  NOTE: Reason for deferral, who decided, under what constraint
-```
-
-### Step 5.5: Detect previous close (reopen scenario)
-```
-IF specs/[feature]/close.md or specs/[feature]/implementation-summary.md EXISTS:
-  LOAD previous health score from existing close document
-  NOTE: "Previous spec health was N%. This close will append a new section,
-         preserving the original close data."
-  SET previous_health = N
-  SET reopen_mode = true
-ELSE:
-  SET previous_health = None
-  SET reopen_mode = false
-```
-
-### Step 6: Compute Spec Health Score
-*Skip in lightweight close mode*
-```
-COUNT resolved: number of items with verdict ✅ Resolved
-COUNT acknowledged: number of items with verdict ⚠️ Acknowledged
-COUNT not_done: number of items with verdict ❌ Not Done
-COUNT total = resolved + acknowledged + not_done
-
-IF total == 0:
-  SET spec_health = 100  (no requirements to compare — trivially aligned)
-ELSE:
-  spec_health = round((resolved + acknowledged) / total * 100)
-
-INTERPRET:
-  100%: Artifacts fully aligned — no action needed
-  80-99%: Minor gaps tracked — acceptable
-  50-79%: Significant drift — recommend spec-kit-refresh before refactoring
-  <50%: Artifacts are misleading — run spec-kit-refresh before proceeding
-```
-
-### Step 7: Patch spec artifacts for intentional deviations
-
-For each gap marked `✅ Resolved — intentional deviation`:
-```
-IDENTIFY the section of spec.md or plan.md that no longer reflects reality
-  
-CASE: FR requirement wording differs from implementation
-  → patch spec.md: update requirement text to match actual behavior, keeping original intent
-  → ADD note: "(Updated by implementation summary — see close.md or implementation-summary.md)"
-
-CASE: Architecture/design detail differs from implementation
-  → patch plan.md: update the relevant section to reflect what was built
-  → ADD note: "(Updated by implementation summary — see close.md or implementation-summary.md)"
-
-CASE: Data model entity or contract differs
-  → patch plan.md or data-model.md: reflect current schema/contract
-  → ADD note: "(Updated by implementation summary — see close.md or implementation-summary.md)"
-```
-
-**User confirmation**: Present each proposed patch as:
-```
-PROPOSE: "Update spec.md FR-XXX from [old] to [new]? (reason: [rationale])"
-WAIT for user approval before applying.
-```
-
-If user rejects a proposed patch → mark that artifact as `⚠️ needs review` in the Spec State table (not auto-updated).
-
-### Step 8: Collect implementation details
-```
-IDENTIFY:
-  - Files changed (from plan file paths, tasks, and git diff)
-  - Dependencies added
-  - Architecture decisions made during implementation
-  - Deviations from plan (with rationale — why they deviated)
-  - Test results (pass/fail counts)
-  - Known limitations or deferred work
-```
-
-### Step 9: Generate output document
-
-**Full mode** (summarize):
-```
-IF reopen_mode AND specs/[feature]/implementation-summary.md EXISTS:
-  APPEND to existing specs/[feature]/implementation-summary.md:
-    - New section: "## Reopened Summary ([ISO date])"
-    - Updated Spec Health Score
-    - "Previous health: N% -> Current health: M%"
-    - New gap analysis entries (additive only)
-    - NOTE: "Original summary preserved above."
-ELSE:
-  COPY spec-kit/templates/implementation-summary-template.md -> specs/[feature]/implementation-summary.md
-
-Populate with:
-- Spec Health Score at top (from Step 6)
-- **Previous vs Current**: IF previous_health exists: "Previous health: N% -> Current health: M%"
-- Spec Health Scoring table
-- All gap analysis sections
-- Spec Artifact Refresh section listing what was patched (from Step 7)
-- Spec State table
-```
-
-**Lightweight mode** (close):
-```
-IF reopen_mode:
-  APPEND to existing `specs/[feature]/close.md`:
-    - A new section header: "## Close (Reopened — [ISO date])"
-    - Updated Spec Health Score from Step 6
-    - "Previous health: N% → Current health: M%"
-    - Updated Artifact State for artifacts changed during reopen
-    - Key decisions made during reopen
-    - NOTE: "Original close preserved above. This section documents the reopened cycle only."
-
-ELSE (first close):
-  COPY `spec-kit/templates/close-template.md` → `specs/[feature]/close.md`
-
-Populate with:
-- Spec Health Score (from Step 6, or simplified "100%" if skipped)
-- Intent Alignment: Yes/Partially/No
-- Artifact State: quick status of each artifact
-- Key Decisions: notable decisions made
-- Spec Health Calculation breakdown (if available)
-```
-
-**Reopen conflict check** (before writing either mode):
-```
-IF reopen_mode AND any requirement status changed from ✅/⚠️ to a worse status:
-  For each changed requirement:
-    PROMPT user: "FR-XXX was [original status] in previous close, now [new status].
-                  This is a regression. How should I document it?
-                  1. Add as new entry (preserves original close — recommended)
-                  2. Update the original close entry (overwrite)"
-  WAIT for user response before writing.
-```
-
-### Step 10: Update or create bugs from gaps
-*Skip in lightweight close mode*
-```
-FOR each "❌ Not Done" gap:
-  IF bugs.md EXISTS:
-    APPEND a new bug entry:
-    ### BUG-NNN: Missing: [requirement description]
-    - Severity: [major/minor]
-    - Description: Specified in spec.md but not implemented (see implementation-summary.md)
-    - Requires Clarification: [ ] no / [ ] yes
-    - Status: open
-    WRITE updated bugs.md (append to end)
-  PROMPT user: "N gaps found with ❌ Not Done — bugs added to bugs.md. Run 'bugfix [feature]' when ready."
-```
-
-### Step 11: Report completion
-```bash
-REPORT:
-  - Mode: Full summary / Lightweight close
-  - TDD mode: Active / Bypassed by user
-  - Output: specs/[feature]/implementation-summary.md or specs/[feature]/close.md
-  - Spec Health: N%
-  - Task completion: N/Total
-  - Bug resolution: verified/total
-  - Artifacts patched: spec.md [yes/no], plan.md [yes/no]
-  - Gap analysis (full mode): N resolved, N acknowledged, N not done
-  - New bugs created (if any gap was ❌ Not Done)
-```
-
-### Step 12: Append to history.md and Step 13: Commit (combined)
-
-**Order is critical: history.md FIRST, then commit.**
-
-1. **Append to history.md**:
-   Append to `specs/[feature]/history.md` (create if missing):
-   - Phase: Phase 6 — Complete
-   - Artifact: `implementation-summary.md` or `close.md`, plus patched artifacts
-   - Spec Health: N%
-
-2. **PRE-COMMIT GUARD**:
-   READ `specs/[feature]/history.md` — confirm the close/summary entry is recorded.
-   If missing: BLOCK — must append before commit.
-
-3. **Commit**:
-   Follow `spec-kit/references/auto-commit.md`:
-   - Scope: `implementation-summary.md` or `close.md`, plus patched `spec.md`, `plan.md`, `data-model.md`
-   - Message: `"spec(phase-6): [feature] summary (health: N%)"`
-
-## Gap Analysis Detail
-
-The Gap Analysis section answers the key question: **"Does the code match what was planned?"**
-
-Sources for comparison:
-- **spec.md**: Functional Requirements (FR-###), User Stories, Success Criteria
-- **plan.md**: Data model entities, API contracts, architecture decisions
-- **tasks.md**: Task descriptions and file paths
-- **git diff / git log**: Actual files changed on the branch
-
-Verdict definitions:
-| Verdict | Meaning | Follow-up |
-|---------|---------|-----------|
-| ✅ Resolved | Implemented as planned, OR intentionally different with documented rationale | No action needed (spec/plan auto-updated in Step 7) |
-| ⚠️ Acknowledged | Deferred by user; not implemented but tracked | Record reason; revisit if needed |
-| ❌ Not Done | Missing with no documented reason | Create bug entry in bugs.md |
-
-## State Transition
-
-After this skill completes, the feature enters **Complete** state:
-- All tasks marked [X]
-- All bugs marked verified
-- Unknown gaps resolved or acknowledged via gap analysis
-- Spec/plan artifacts patched to reflect intentional deviations
-- Summary (full or close) captures final state
-- Bugs created for ❌ Not Done gaps (if any)
-- No further phases required unless user initiates a new cycle
-
-## Phase State Detection
-
-| Artifacts Present | Interpretation |
-|:-----------------|:-------------|
-| `implementation-summary.md` exists | Feature complete — full summary generated |
-| `close.md` exists | Feature closed — lightweight close document |
-| `implementation-summary.md` or `close.md` + all bugs verified | Feature complete and verified |
-| `spec.md` or `plan.md` patched (diff from prior commit) | Artifacts reconciled with code |
-| `implementation-summary.md` with open gaps (❌) | Summary generated but gaps remain — new bugs created |
-| `implementation-summary.md` with open tasks | Partial summary (run again after completion) |
-
-## Routing Commands
-
-- "Summarize [feature]" — loads this skill, generates full implementation summary
-- "Close [feature]" — loads this skill, generates lightweight close document
-- "Implementation summary for [feature]" — same as summarize
-- "Status of [feature]" — checks if summary exists, reports state
-
-## Mandatory Close (User-Initiated)
-
-After the bugfix loop completes (all bugs in bugs.md marked Status: verified), the workflow suggests Phase 6 (Summarize/Close) — the user decides when to run it:
-
-```text
-CHECK: All bugs in bugs.md have Status: verified
-
-ACTION:
-  1. Suggest the user run Phase 6: "'close [feature]' or 'summarize [feature]'?"
-  2. WAIT for user choice: full summary ('summarize') or lightweight close ('close')
-  3. Run the chosen mode
-  4. Present output to user
-
-BLOCKER: A feature CANNOT enter Complete state without Phase 6 completing.
-  - User says "feature is done" or tries to start a new feature
-  - CHECK: implementation-summary.md or close.md exists?
-  - IF NOT: Block with "Complete Phase 6 first: run 'summarize [feature]' or 'close [feature]'"
-```
-
-**Note**: The mandatory close is enforced by the workflow orchestrator (`spec-kit-workflow`). When `spec-kit-test` marks the last bug as verified, it should suggest "All bugs verified — run 'close [feature]' to complete."
-
-## Done When
-
-- [ ] Output generated: implementation-summary.md (full) or close.md (lightweight)
-- [ ] Spec health score computed and included
-- [ ] All tasks marked complete in tasks.md
-- [ ] All bugs marked verified in bugs.md
-- [ ] ✅ Resolved deviations patched into spec.md and plan.md (with user approval)
-- [ ] ❌ Not Done gaps converted to new bug entries in bugs.md (if any, full mode only)
-- [ ] Report delivered to user with spec health score and artifact state
-- **Commit**: `$COMMIT_HASH` (auto — `git log` for details)
-
-## Next Skills
-
-- Feature is now **Complete** — no further phases needed
-- Propose to the user: Run `spec-kit-workflow` to start a new feature cycle
-- Propose to the user: Run `spec-kit-specify` to add new features
-- Propose to the user: Run `spec-kit-refresh` if artifacts show drift (for manual code changes)
-- Propose to the user: Run `bugfix [feature]` if new gaps were added as bugs
+**Phase**: 6 (mandatory close) · **Persona**: auditor and archivist — verify every claim against spec, plan and the diff; leave the decision record and agent context true; detail proportional to the diff.
+**Purpose**: `close.md` (S/M: "close"; L: "summarize" = full gap table) **+ `change-record.md`** (the auditor's page); spec health; approved deviation patches; regenerate the plan's Current Design; ADRs that pass the bar; AGENTS.md kept current. Not complete without this phase.
+**Full procedure**: `spec-kit/references/skills/spec-kit-summarize.md` (gap analysis, health, ADR bar, AGENTS.md sync, reopen) · **Not for**: mid-stream alignment → `spec-kit-refresh`.
+
+## Before writing
+- `spec-kit/references/preflight.md`. Requires `tasks.md`. Load spec, plan, tasks, bugs, constitution, data-model, contracts, research, clarify, `history.md`, `evidence/`, `decisions.md`, `acceptance.md`, `review-final.md`.
+- **Gate**: latest `review-final.md` round READY / READY-WITH-FOLLOWUPS and not stale — else **BLOCK** ("run the final review"; AWAITING-OWNER → get the owner's answer, Round N+1). Open bug → **BLOCK**.
+- Mode: "close" / "summarize" as said; else S/M → close, L → summarize. Reopen (close doc exists) → APPEND a dated section.
+
+## Steps
+1. Tasks: count, mark done ones `[X]` only. Bugs: count; **never change a status**; `claimed` without `Verified-by` → *Unverified claims*.
+2. **Evidence table** (`spec-kit/references/evidence.md`): acceptance/regression `output:`/`ci:`, a `probe:` per seam, the final review's verdict + reviewer label. No oracle → ❌ unverified.
+3. Gaps: M → exceptions only; L → every FR / story / entity / contract. Health = (resolved + acknowledged) / total. Follow-ups from the review → *Open questions*.
+4. Deviations → propose each spec/plan patch; **WAIT**; rejected → ⚠️ needs review. Regenerate `plan.md` → `## Current Design` (≤ 1 page, what is BUILT).
+5. **ADRs**: harvest (decisions.md rulings, plan Rounds, research, review findings, deviations); apply the ADR bar; per candidate propose new / supersede / append-evidence (`mcp_spec_kit_next_id(kind="ADR")`, project template else `spec-kit/templates/adr-template.md`); **WAIT** per ADR; update the index. Fill *Architecture Decisions* — "none met the bar" is a valid row.
+6. **AGENTS.md** (+ CLAUDE.md / rule files): statements the diff or new ADRs make wrong (commands, layout, boundaries, versions, conventions, debt, ADR list) → targeted patches; **WAIT**; never rewrite.
+6a. **Runbooks + changelog** (only what git-conventions keeps: `runbooks_dir`, `changelog`): runbook statements the diff makes wrong (commands, settings, endpoints, procedures) → targeted patches, **WAIT**; one *Unreleased* line in the changelog (Keep a Changelog: Added / Changed / Fixed, one sentence, the ticket) — no narrative.
+6b. **Design doc + epic row** (only when `specs/git-conventions.md` sets `design_dir` / `epics_dir`; else skip in one line): for each module in plan.md `**Modules**:` → the `[design_dir]/[module].md` sections the diff makes wrong (components, flow, seams, invariants, debt) → targeted patches + a change-log line; **WAIT** per patch; a module without a doc → say so, never create one here (`spec-kit-design`). `**Epic**:` in spec.md → set this feature's row in `[epics_dir]/[epic]/features.md` (status closed, PR, health, ADRs) and the epic's row in `[epics_dir]/README.md` when `epics_index: on`; last row → suggest `close epic`.
+7. **`change-record.md`** from `spec-kit/templates/change-record-template.md`: ticket, branch/PR, size, what/why, Security & Privacy impact (from spec), data/config changes, implemented-by, reviewed-by (agent + human PR reviewer or `pending`), verification, decisions, deployment approval (or `pending`), rollback, follow-ups; **Timeline** = one row per `history.md` entry (history on) or `spec-kit/scripts/spec-kit-history.sh [feature]` run now on the branch (history off — before the squash).
+8. ❌ Not Done gaps → new `open` bugs. Write `close.md` from `spec-kit/templates/close-template.md`.
+
+## Done when
+- [ ] close.md + change-record.md written (no `pending` field left blank); health computed; no bug status changed; design doc / epic row patched or "none kept" recorded.
+- [ ] MCP: `mcp_spec_kit_close_feature` · `mcp_spec_kit_lint_artifacts` → 0 errors.
+- [ ] history.md entry when on (`Phase 6`, health %, ADRs), then ONE commit: close doc, change record, patched spec/plan/data-model, ADRs + index, AGENTS.md, runbooks, changelog line, design doc, epic + index rows — `spec(phase-6): [feature] close (health: N%)`.
+
+## Next
+Feature **Complete**. Propose the PR (description drafted by the final review; the human reviewer's name goes into the change record when known), `spec-kit-specify` for the next feature, `bugfix [feature]` if gaps became bugs.
diff --git a/src/skills/spec-kit-tasks.md b/src/skills/spec-kit-tasks.md
index b66e697..6fadb97 100644
--- a/src/skills/spec-kit-tasks.md
+++ b/src/skills/spec-kit-tasks.md
@@ -13,102 +13,23 @@ metadata:
 
 # spec-kit-tasks
 
-**Task Persona**: Adopt the mindset of a system architect and philosopher. Every requirement must become concrete, executable work. Break down the design into granular, ordered tasks — each one maps to a requirement and produces a verifiable deliverable. No gaps, no assumptions.
-
-**Phase**: 3
-
-**Purpose**: Create `specs/[feature]/tasks.md` — an executable task list. Tests generated first, then implementation tasks. No mandatory 1:1 mapping between tests and tasks. User may explicitly bypass TDD.
-
-**When NOT to use**: For one-step changes (single file edit) — just implement directly.
-
-**Routing**: Load this skill when the user says "generate tasks for [feature]" or "break down [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
-
-
-**Artifacts**: `specs/[feature]/tasks.md`
-
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Execution
-
-### Validate prerequisites
-```
-IF specs/[feature]/plan.md NOT EXISTS: ERROR "Run spec-kit-plan first"
-IF specs/[feature]/spec.md NOT EXISTS: ERROR "Run spec-kit-specify first"
-```
-
-### Load context
-```
-LOAD specs/[feature]/plan.md, spec.md, data-model.md, contracts/
-
-IF bugfix mode (reopened bugfix):
-  NOTE: "Bugfix mode — tasks.md already exists with completed tasks. Will append new bugfix tasks only."
-  LOAD existing specs/[feature]/tasks.md
-  LOAD bugs.md, plan.md bugfix sections
-ELSE:
-  LOAD spec-kit/templates/tasks-template.md
-  COPY spec-kit/templates/tasks-template.md → specs/[feature]/tasks.md
-```
-
-### Determine TDD mode
-```
-ASK user: "Generate test tasks (TDD) or skip tests?"
-IF skip:
-  SET tdd_bypassed = true
-  ADD header to tasks.md: "> **TDD**: Bypassed by user request"
-```
-
-### Generate test tasks first (TDD mode)
-For each phase, tests BEFORE implementation:
-```
-Phase N:
-  T001 [TEST] Write tests for login          — tests/test_auth.py
-  T002        Implement login                 — src/auth.py
-```
-
-Rules:
-- All test tasks for a phase come first
-- No mandatory 1:1: one test can cover multiple tasks, one task can have multiple tests
-- Group tests by phase boundary, not implementation granularity
-- Mark test tasks with `[TEST]`
-
-### Map requirements to tasks
-```
-For each FR-###: IDENTIFY implementing tasks
-For each User Story: MAP scenarios to test tasks, entities to model tasks
-```
-
-### Map bugfix tasks (bugfix mode)
-```
-For each open bug: CREATE BF-### task, include test task to verify fix
-```
-
-**Additive-safe**: Insert new bugfix tasks BEFORE the final `## Dependencies & Execution Order` section. Never delete existing tasks. You may update task status fields (e.g. mark tasks as completed). If a new bugfix task has the same ID as an existing one, ask the user how to resolve. The `## Dependencies` and `## Verification` sections (if present) must remain as the last sections — never insert anything after them.
-
-### Generate task breakdown
-Organize by phase: Setup → Foundational → User Stories → Polish.
-Format: `T### [P] [US#] Description — file/path.ext`
-
-### Document dependencies
-Phase dependencies, parallel execution opportunities.
-
-### Note on commits
-Report: task count, phases, TDD mode, parallel tasks, bugfix tasks
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 3 — Tasks
-- Artifact: `specs/[feature]/tasks.md`
-- Scope: `specs/[feature]/tasks.md`
-- Message: `"spec(phase-3): [feature] tasks"`
-
-## Completion
-
-## Common Pitfalls
-1. **Missing file paths**: Every task needs an exact file path — otherwise the implement skill can't execute it.
-2. **Forcing 1:1 test-to-task**: Integration tests cover multiple tasks. Edge case tests cover one function. Let the test structure follow the behavior, not the task IDs.
-3. **Not asking about TDD bypass**: Always ask the user at task generation time. Don't assume.
-
-## Prerequisite Enforcement
-**BLOCKED** if: plan.md or spec.md does not exist.
+**Phase**: 3 · **Persona**: tech lead turning design into ordered, verifiable work — every task has a file path.
+**Purpose**: `specs/[feature]/tasks.md` — tests first per phase, then code.
+**Full procedure**: `spec-kit/references/skills/spec-kit-tasks.md` · **Not for**: one-step changes.
+
+## Before writing
+- `spec-kit/references/preflight.md`. **BLOCK** if `plan.md` or `spec.md` is missing. Load plan, spec, data-model, contracts. `tasks.md` exists and not bugfix mode → **BLOCK**; bugfix mode → append only.
+
+## Steps
+1. Copy `spec-kit/templates/tasks-template.md`. **ASK**: TDD or skip tests? Skip → header `> **TDD**: Bypassed by user request`. Never assume.
+2. S → one flat list; M/L → phases Setup/Foundational → stories → Polish. `T### [P] [US#] [TEST] [AC-###] [SEAM] Description — path`.
+3. Every FR and story → tasks. Every AC with level unit/integration/component/e2e → a `[TEST] [AC-###]` task at the plan's test file, test NAME carrying the id; command/probe ACs → a task writing the check. Every seam from the plan → `[SEAM]` on the task that touches it (`spec-kit/references/evidence.md`).
+4. Bugfix mode: per open bug a `BF-###` task + its verifying test, inserted before `## Dependencies & Execution Order`; never delete tasks.
+5. Ids: `mcp_spec_kit_next_id(kind="T"|"BF")` (no MCP: highest + 1). Dependencies and parallel opportunities in one short section.
+
+## Done when
+- [ ] Every task has a path; markers set; TDD answered. MCP: `mcp_spec_kit_update_artifact(tasks.md)` · `mcp_spec_kit_advance_phase(from_phase=3)` · `mcp_spec_kit_lint_artifacts` → 0 errors.
+- [ ] history.md entry, then commit (`spec-kit/references/preflight.md` procedure): `spec(phase-3): [feature] tasks` (bugfix: `… bugfix tasks (BUG-NNN, …)`).
+
+## Next
+L → `spec-kit-review` (pre-implement, required). M → `spec-kit-review` lite, then `spec-kit-implement`. S → one commit `spec(phase-1-3)` then `spec-kit-implement`. Bugfix mode → `spec-kit-implement` automatically.
diff --git a/src/skills/spec-kit-test.md b/src/skills/spec-kit-test.md
index 13354b0..5219f7d 100644
--- a/src/skills/spec-kit-test.md
+++ b/src/skills/spec-kit-test.md
@@ -1,6 +1,6 @@
 ---
 name: spec-kit-test
-description: Load when the user says 'spec-kit test [feature]', 'speckit test [feature]', 'spec-kit bug [feature]', 'speckit bug [feature]', 'spec-kit log [feature]', 'speckit log [feature]', "test [feature]", "run tests for [feature]", "log bugs for [feature]", or "bug [feature]" — Phase 5 bug tracking and manual testing.
+description: Load when the user says 'spec-kit accept [feature]', 'speckit accept [feature]', "accept [feature]", "run acceptance for [feature]", 'spec-kit test [feature]', 'speckit test [feature]', 'spec-kit bug [feature]', 'speckit bug [feature]', 'spec-kit log [feature]', 'speckit log [feature]', "test [feature]", "run tests for [feature]", "log bugs for [feature]", or "bug [feature]" — Phase 5 bug tracking and manual testing.
 version: 1.1.0
 author: Hermes Agent
 license: MIT
@@ -13,86 +13,28 @@ metadata:
 
 # spec-kit-test
 
-**Task Persona**: Adopt the mindset of a QA engineer. Your primary deliverable is a detailed, structured bugs.md. Every bug must have: clear steps to reproduce, expected vs actual behavior, severity, environment context. Vague bug reports are worse than no report — they waste time. Be systematic, be thorough, be precise.
+**Phase**: 5 · **Persona**: QA engineer — steps, observed vs expected, severity; a vague bug report is worse than none.
+**Purpose**: log user-reported bugs in `bugs.md`; mark bugs verified **only with an oracle**; **accept mode** runs the acceptance criteria and logs every failure for the loop. Log, then STOP — never fix here.
+**Full procedure**: `spec-kit/references/skills/spec-kit-test.md` · status rules `spec-kit/references/evidence.md`.
 
-**Phase**: 5 (Testing)
+## Before writing
+- `spec-kit/references/preflight.md`. **ERROR** if `spec.md` is missing. `bugs.md` missing → `spec-kit/templates/bugs-template.md`; exists → summary, **ASK**: add, bugfix, or verify?
 
-**Purpose**: Log user-discovered bugs in `bugs.md` and orchestrate the bugfix loop. User reports bugs in natural language; agent formats them into structured entries.
+## Log a bug
+1. Id `mcp_spec_kit_next_id(kind="BUG")`. Entry `### BUG-NNN: summary` — Severity, Area, Description (observed vs expected), Steps, Actual, Expected, Requires Clarification, Plan Ref (empty), **Status: open**.
+2. Insert before the `---` preceding `## Summary`; add the Summary row; fix counts. Confirm each: "Logged BUG-NNN — correct?"
+3. 0 open → suggest `final review [feature]`; > 0 → `bugfix [feature]`. **Never fix directly.**
 
-**When NOT to use**: During implementation or before the full regression run (Step 7 of implement) completes.
+## Accept mode — one round (`spec-kit/references/acceptance.md` §5–6)
+1. Commands = `specs/merge-checklist.md` `acceptance_*` (missing → add from `spec-kit/templates/merge-checklist-template.md`, **ASK** once). COMMIT = HEAD.
+2. Run `acceptance_fast` (full unit + integration + component = the regression); `acceptance_e2e` with this feature's e2e specs only if `acceptance_e2e_ready` exits 0 (else deferred); command/probe ACs → `evidence/acceptance-r-AC-###.txt` (`RESULT: PASS|FAIL`). Console → `evidence/acceptance-r.txt`.
+3. `mcp_spec_kit_acceptance_status(feature, results, round=N)` → append `## Round N` to `acceptance.md` (`spec-kit/templates/acceptance-template.md`): Result, Commit, counts, matrix.
+4. FAIL → per failing/missing AC and regression: existing bug → back to `open` ("failed again in round N"); else new bug (Area `AC-###`, Steps = Given/When, Actual = first failing assertion, Source: round N) — no per-bug confirmation in the loop.
+5. **Stop and ASK** when: round = `acceptance_max_rounds` (5); same ACs + same assertion two rounds running; the fix needs a spec or frozen-test change; STOPPED; the run cannot execute twice. Else hand to `bugfix [feature]` (then `accept` again). PASS → final review.
+6. Commit `spec(phase-5): [feature] acceptance round N (RESULT a/b)` — acceptance.md, evidence, bugs.md.
 
-**Routing**: Load this skill when the user says "test [feature]". If loaded directly, load spec-kit-workflow first to check prerequisites.
+## Verify a bug
+Only with an oracle: the user's quoted words, a green `ci:` on that commit, or `review:`. Else refuse: "claimed, not verified." Set `Status: verified` + `Verified-by:`.
 
-## Pre-flight
-Load and follow `spec-kit/references/preflight.md` before any action in this skill.
-
-## Git Commit Guidelines
-See `spec-kit/references/auto-commit.md`. Commits use `--no-verify`. Branch guard handled by preflight.md.
-
-
-**Artifacts**: `specs/[feature]/bugs.md`
-
-## Safety Block: Log Before Fix
-
-**Rule**: ALWAYS write the bug to bugs.md first. HALT after logging. Do NOT fix, plan, or read source code. Only proceed when user says "bugfix [feature]".
-
-## Execution
-
-### Validate prerequisites
-```
-IF specs/[feature]/spec.md NOT EXISTS: ERROR "Run spec-kit-specify first"
-```
-
-### Check for existing bugs.md
-```
-IF bugs.md EXISTS:
-  LOAD, report current summary
-  ASK: "Add new bugs, continue bugfixing, or mark bugs as verified?"
-ELSE:
-  COPY spec-kit/templates/bugs-template.md → bugs.md
-```
-
-### User reports bugs — agent formats them
-User describes in natural language. Agent structures into:
-```
-### BUG-NNN: [Summary]
-- **Severity**: critical/major/minor/trivial
-- **Description**: observed vs expected
-- **Steps to Reproduce**: [numbered steps]
-- **Requires Clarification**: [ ] no / [ ] yes
-- **Status**: open
-```
-
-**Smart insert**: INSERT the new bug entry BEFORE the `---` separator that precedes `## Summary`. Then UPDATE the Summary table: add a row for the new bug, increment counts, and correct the open/in-progress/resolved/verified tallies. Never place new bugs after `---` or inside `## Summary`.
-
-After each bug, confirm: "Logged BUG-NNN: [summary] — correct?"
-
-### Bug status validation
-When user finishes logging → count open bugs. If 0, feature complete. If >0, suggest "bugfix [feature]".
-
-### Mark bugs as verified
-```
-FIND bug → SET Status: verified → REPORT
-```
-
-### Completion check
-```
-IF all bugs verified:
-  REPORT: "All bugs verified — run 'close [feature]' to complete."
-```
-
-### Append to history.md and Commit
-
-Follow the **Shared Commit Procedure** in `spec-kit/references/preflight.md`:
-- Phase: Phase 5 — Testing
-- Artifact: `specs/[feature]/bugs.md`
-- Scope: `specs/[feature]/bugs.md`
-- Message: `"spec(phase-5): [feature] bug log"`
-
-## Common Pitfalls
-1. **Fixing before logging**: Procedural lock. Log first, fix later. Violating this causes workflow corruption.
-2. **Setting bugs to resolved/verified preemptively**: Only the user marks a bug verified — after they test the fix.
-3. **Skipping confirmation**: After each bug entry, confirm with user. They may have additional details.
-
-## Prerequisite Enforcement
-**ERROR** if: spec.md does not exist.
+## Done when
+- [ ] Bugs confirmed with the user (loop-logged bugs carry their round); ids ascending; Summary counts match (`mcp_spec_kit_lint_artifacts` → 0 errors). history.md entry, then commit (`spec-kit/references/preflight.md` procedure): `spec(phase-5): [feature] bug log`.
diff --git a/src/skills/spec-kit-workflow.md b/src/skills/spec-kit-workflow.md
index 08c2bff..460285b 100644
--- a/src/skills/spec-kit-workflow.md
+++ b/src/skills/spec-kit-workflow.md
@@ -1,6 +1,7 @@
 ---
 name: spec-kit-workflow
-description: Load when the user says 'spec-kit bugfix [feature]', 'speckit bugfix [feature]', 'spec-kit fix [feature]', 'speckit fix [feature]', 'spec-kit reopen [feature]', 'speckit reopen [feature]', 'spec-kit implement [feature]', 'speckit implement [feature]', 'spec-kit plan [feature]', 'speckit plan [feature]', 'spec-kit close [feature]', 'speckit close [feature]', 'spec-kit specify [feature]', 'speckit specify [feature]', 'spec-kit status [feature]', 'speckit status [feature]', or any 'spec-kit ...' or 'speckit ...' workflow routing command. Also triggers on natural phrases: "fix bugs in [feature]", "bugfix [feature]", "bugfixing [feature]", "continue bugfixing", "reopen [feature]", "implement [feature]", "plan [feature]", "close [feature]", "create a spec", "specify [feature]", "what phase is [feature] in". Routes to the correct phase skill.
+description: >
+  Load when the user says 'spec-kit bugfix [feature]', 'speckit bugfix [feature]', 'spec-kit fix [feature]', 'speckit fix [feature]', 'spec-kit reopen [feature]', 'speckit reopen [feature]', 'spec-kit implement [feature]', 'speckit implement [feature]', 'spec-kit plan [feature]', 'speckit plan [feature]', 'spec-kit close [feature]', 'speckit close [feature]', 'spec-kit specify [feature]', 'speckit specify [feature]', 'spec-kit status [feature]', 'speckit status [feature]', or any 'spec-kit ...' or 'speckit ...' workflow routing command. Also triggers on natural phrases: "fix bugs in [feature]", "bugfix [feature]", "bugfixing [feature]", "continue bugfixing", "reopen [feature]", "implement [feature]", "plan [feature]", "close [feature]", "create a spec", "specify [feature]", "what phase is [feature] in". Routes to the correct phase skill.
 version: 1.1.0
 author: Hermes Agent
 license: MIT
@@ -13,254 +14,29 @@ metadata:
 
 # Spec Kit Workflow Orchestrator
 
-**Load this skill when the user says: "bugfix [feature]", "reopen [feature]", "implement [feature]", "plan [feature]", "specify [feature]", "close [feature]", "create a spec", or any phase-routing command.**
+**Persona**: router, not executor — check prerequisites, derive the phase, dispatch, enforce guardrails.
+**Load for**: `bugfix`, `quickfix`, `reopen`, `accept`, `status` / "what phase is X in", and any `spec-kit …` command whose phase is unclear. Phase skills (`spec-kit-specify`, `spec-kit-clarify`, `spec-kit-plan`, `spec-kit-tasks`, `spec-kit-review`, `spec-kit-implement`, `spec-kit-test`, `spec-kit-summarize`, `spec-kit-refresh`, `spec-kit-constitution`) trigger themselves — do not load this skill for them.
+**Full procedure**: `spec-kit/references/skills/spec-kit-workflow.md` (bugfix / quickfix / reopen rules, guardrail table).
 
-**Task Persona**: Adopt the mindset of a workflow orchestrator. Your job is routing, not execution. Check prerequisites, validate state, and dispatch to the correct phase skill. Guardrails are your responsibility — enforce them before passing control.
+## Before routing
+- Preflight checks 1 and 4 (`spec-kit/references/preflight.md`). Feature named but `specs/[feature]/` missing → **BLOCK**, list specs. `specs/constitution.md` missing → route `spec-kit-constitution`, stop (once per session).
+- Phase: `mcp_spec_kit_get_next_actions(feature)` / `mcp_spec_kit_list_features()`; no MCP: spec → plan → tasks → `[X]` tasks (implementing) → bugs open (bugfix loop) → all verified → acceptance PASS (ACs) → final review READY → close doc (complete); close doc + open bug = reopened.
 
-This skill does NOT execute phases itself. It routes requests to the correct phase skill based on artifact state and trigger phrases. If you loaded this skill because the user said "bugfix", read the "Bugfix Routing" section below — do NOT start with spec-kit-specify.
+## Routes
+| State | Route |
+|---|---|
+| all tasks `[X]`, spec has ACs, no fresh PASS round | **accept** → `spec-kit-test` (accept mode) |
+| no open bug, acceptance PASS (or no ACs), no fresh READY review | **final review** → `spec-kit-review` |
+| final review READY / READY-WITH-FOLLOWUPS, fresh | **must close** → `spec-kit-summarize` |
+| close doc with ⚠️/❌ artifact rows | warn "drift — run refresh" |
 
-## Pre-flight: Project Readiness
+Inject constitution principles as guidance (not gates) when routing.
 
-Load and follow `spec-kit/references/preflight.md` before any routing action. Preflight handles branch guardrails (checks #1, #4), mode detection (#2), unlogged bug check (#3), git conventions (#4 renamed), workflow load check (#5), and history.md readiness (#6).
+## Bugfix loop
+`bugfix [feature]`: closed feature → say "use `reopen`". Every open bug needs a **Plan Ref** (else `spec-kit-plan` first). *Requires Clarification* → `spec-kit-clarify` first. Then **auto-chain** `spec-kit-plan` → `spec-kit-tasks` → `spec-kit-implement`; review only on request. `quickfix [feature]` (explicit opt-in): plan section + task + fix in one commit, documents still written.
+- `accept [feature]` (also automatic after implement when spec.md has ACs): accept round → FAIL → auto-chain `bugfix` → accept again; no prompt between rounds; stop conditions → **ASK** (`spec-kit/references/acceptance.md`). PASS → final review. Never auto-close.
+- Size (`spec-kit/references/sizing.md`): S auto-chains specify → plan → tasks; M lite pre-implement review; L full pre-implement review required.
+- `reopen [feature]`: needs a close doc; bugfix branch per `specs/git-conventions.md`; the close appends.
 
-> **Note**: If you already have preflight loaded from a prior skill call, you do not need to reload it. Re-run checks #1 and #4 as a quick sanity check, then proceed directly to routing.
-
-Additionally, for any command that references a specific feature:
-
-```text
-IF feature name is provided (e.g., "003-user-auth"):
-  IF specs/[feature]/ directory NOT EXISTS:
-    BLOCK: "Feature [feature] not found in specs/. Available specs: [list directories]"
-    SUGGEST: "Create it with 'Create a spec for [description]'"
-```
-
-## Workflow Phases (in order)
-
-|| Phase | Skill | Purpose | Prerequisite |
-||:------|:------|:--------|:-------------|
-|| 0 | `spec-kit-constitution` | Project principles | None |
-|| 1 | `spec-kit-specify` | Feature spec | Constitution |
-|| 1.5 | `spec-kit-clarify` | Iterative clarification | Spec |
-|| 2 | `spec-kit-plan` | Technical plan | Spec + Constitution |
-|| 3 | `spec-kit-tasks` | Task breakdown | Plan |
-|| 3.5 | `spec-kit-review` | Quality gate (optional) | Tasks |
-|| 4 | `spec-kit-implement` | Execute tasks | Tasks |
-|| 5 | `spec-kit-test` | Testing & bug tracking | Implement (or spec for bugfix loop) |
-|| **6** | **`spec-kit-summarize`** | **Implementation summary / close** | **Implement + Test** |
-|| — | **`spec-kit-refresh`** | **Lightweight artifact refresh** | **Any (standalone)** |
-|| — | **Bugfix loop** | Test → [Clarify] → Plan → Tasks → [Review] → Implement → Test → **Close** (bugs.md with open bugs) |
-|| — | **Quickfix** | Trivial bugfix: Plan section + tasks entry + fix in one batch commit (user opt-in, docs still exist) | bugfix sub-round with explicit "quickfix [feature]" |
-
-> **Important**: Phase 6 (Close/Summarize) is **mandatory** before a feature can enter Complete state. After the bugfix loop finishes (all bugs verified), the user is prompted to run Phase 6.
-
-## Routing Logic
-
-Each skill BLOCKS if prerequisites are not met:
-- `spec-kit-constitution`: No prerequisites (phase 0)
-- `spec-kit-specify`: Requires `constitution.md`
-- `spec-kit-clarify`: Requires `spec.md`
-- `spec-kit-plan`: Requires `spec.md` + `constitution.md`
-- `spec-kit-tasks`: Requires `plan.md` + `spec.md`
-- `spec-kit-review`: Requires `spec.md` (at minimum — richer analysis if plan.md/tasks.md also exist)
-- `spec-kit-implement`: Requires `tasks.md`
-- `spec-kit-test`: Requires `spec.md` (or existing implementation)
-  Bugfix prerequisite: `bugs.md` with at least one open bug
-- `spec-kit-summarize`: Requires `tasks.md`
-- `spec-kit-refresh`: No prerequisites (standalone)
-
-### New Feature
-- User says: "Create a spec for [description]"
-- Propose routing to: `spec-kit-specify`
-
-### Existing Feature
-- User says: "What phase is [feature] in?"
-- Check `specs/[feature]/` directory structure
-- **Drift detection**: If `implementation-summary.md` or `close.md` exists, check its Spec State table. If any artifact shows ⚠️ or ❌ status, warn: "Artifact drift detected — run 'refresh [feature]' before proceeding."
-- Report current phase and propose next available action
-
-### Advance Phase
-- User says: "Plan [feature]"
-- Propose routing to: `spec-kit-plan`
-
-### Clarify Ambiguities (Optional)
-- User says: "Clarify [feature]"
-- When: Only if spec has ambiguities or user explicitly asks
-- Propose routing to: `spec-kit-clarify`
-
-### Constitution
-- User says: "Create constitution"
-- Propose routing to: `spec-kit-constitution`
-
-### Review (Optional — Pre-implement or Post-implement)
-- User says: "Analyze [feature]", "Review [feature]", or "Quality check [feature]"
-- When: Before implementation (cross-artifact consistency) OR after code + tests (code quality review)
-- Propose routing to: `spec-kit-review`
-- NOTE: This skill auto-detects whether to run pre-implement or post-implement mode based on available artifacts
-
-### Implement
-- User says: "Implement [feature]"
-- Propose routing to: `spec-kit-implement`
-
-### Reopen (Closed Feature Bugfix)
-- User says: "Reopen [feature]" or "reopen [feature]"
-- **Purpose**: Fix bugs in a previously closed feature. Routes through bugfix flow, then updates close.md.
-- **Prerequisites**: `close.md` or `implementation-summary.md` must exist
-- **Full reopen flow**: See `spec-kit-summarize` — the reopen routing and branch creation logic is defined there. This skill only validates prerequisites and dispatches.
-- **Conflict rule**: If the new close assessment contradicts the original close (same requirement went from ✅ to ❌), prompt the user to resolve before proceeding.
-
-### Summarize / Close (Phase 6 — Mandatory)
-- User says: "Summarize [feature]" or "Implementation summary for [feature]"
-- Route to: `spec-kit-summarize` (full mode)
-- User says: "Close [feature]" or "Complete [feature]"
-- Route to: `spec-kit-summarize` (lightweight close mode)
-
-### Block: Feature cannot be done without Phase 6
-```text
-WHEN user says "[feature] is done" or tries to start a new feature for the same project:
-  IF implementation-summary.md or close.md does NOT exist:
-    BLOCK: "Cannot mark [feature] complete — Phase 6 (Close/Summarize) is mandatory."
-    PROMPT: "Run 'close [feature]' or 'summarize [feature]' first."
-  ELSE:
-    ALLOW: Feature is Complete
-```
-
-### Refresh Artifacts
-- User says: "Refresh [feature]" or "Sync spec for [feature]" or "Align artifacts for [feature]"
-- Route to: `spec-kit-refresh`
-- When: Manual code changes, mid-stream alignment, or artifacts flagged as outdated
-- Standalone — no prerequisites
-
-## Phase Detection
-
-Check for artifacts to determine current phase:
-
-|| Artifacts Present | Current Phase |
-||:-----------------|:-------------|
-|| `constitution.md` only | Ready to Specify |
-|| `spec.md` exists | Specified |
-|| `clarify.md` exists | Clarifying/Clarified |
-|| `plan.md` exists | Planning/Planned |
-|| `tasks.md` exists | Tasking/Tasked |
-|| `tasks.md` with completions | Implementing |
-|| `bugs.md` with open bugs | Testing (bugfix loop) |
-|| `bugs.md` all verified | Testing complete — **must close** |
-|| `implementation-summary.md` exists | Summarized — complete |
-|| `close.md` exists | Closed — complete |
-|| `close.md` + `bugs.md` with open bugs | **Reopened (bugfix in progress)** |
-|| All tasks complete + all bugs verified + (implementation-summary.md or close.md) | **Complete** |
-
-> **Drift detection**: When entering any phase for an existing feature that has `implementation-summary.md` or `close.md`, read its Spec State / Artifact State table. If any artifact is `⚠️ needs review` or `❌ outdated`, emit a warning: "Artifact drift detected — spec/plan may not reflect current code. Run 'refresh [feature]' to reconcile."
-
-## Bugfix Routing
-
-### Start bugfix loop
-- User says: "bugfix [feature]" or "fix bugs in [feature]"
-- LOAD `specs/[feature]/bugs.md`
-- IF `specs/[feature]/close.md` or `specs/[feature]/implementation-summary.md` EXISTS:
-    NOTE: "Feature [feature] was previously closed. Use 'reopen [feature]' to explicitly reopen it."
-    SUGGEST: "Reopen creates a bugfix branch and auto-creates bugs.md if needed."
-    ROUTE to: reopen flow
-- **Plan Ref enforcement** — for each bug with Status: open or in-progress:
-  - CHECK for a **Plan Ref** entry
-  - IF any open bug lacks a Plan Ref:
-    - REPORT: "BUG-NNN lacks a Plan Ref. A plan section must address this bug before implementation."
-    - SUGGEST: Route through `spec-kit-plan` first
-    - REQUIRE: User confirms before proceeding without Plan Refs
-- FOR each bug with Status: open or in-progress:
-  - IF Requires Clarification checkbox "yes" is checked: ROUTE to `spec-kit-clarify` first, then auto-chain to plan → tasks → implement
-  - ELSE: ROUTE to `spec-kit-plan` directly
-- AFTER plan → AUTOMATICALLY route to `spec-kit-tasks`
-- AFTER tasks → AUTOMATICALLY route to `spec-kit-implement`
-- DEFAULT route: `spec-kit-plan` → `spec-kit-tasks` → `spec-kit-implement` (automatic chain, no user choice)
-- NOTE: Review is optional — only run if user explicitly asks for it
-- **TDD during bugfix**: `spec-kit-implement` enforces RED→GREEN per bugfix task.
-
-### New bugs discovered during a fix round
-See `spec-kit-implement` ("New bugs discovered during fix" section) for the full rules on logging mid-round bugs and the bugfix vs quickfix mode choice. Key routing summary:
-
-```text
-IF the current bugfix round is still in progress (BF-### tasks not all verified):
-  New bugs are logged by spec-kit-test — do NOT start a new round yet.
-  The current round completes normally.
-
-AFTER the current round completes and all original BF-### tasks are verified:
-  IF bugs.md has NEW open bugs:
-    User chooses: "bugfix [feature]" (full sequence) or "quickfix [feature]" (batched).
-```
-
-### Bugfix loop completion — user decides when to close
-After all bugs in bugs.md have Status: verified:
-```text
-  SUGGEST: "All N bugs verified. Ready to close? Say 'close [feature]' to
-            generate a close document, or 'add bug' to log more bugs."
-  DO NOT auto-trigger close. The user decides when to advance.
-  The close is MANDATORY before the feature can be marked complete.
-```
-
-### Test phase
-- User says: "Test [feature]"
-- Propose routing to: `spec-kit-test`
-- NOTE: `spec-kit-test` logs bugs to `bugs.md` then STOPS. It does NOT auto-chain to implement. User must say "bugfix [feature]" to start the fix loop.
-
-### Verify bug
-- User says: "Verify [BUG-ID] in [feature]"
-- Propose routing to: `spec-kit-test` (to mark bug as verified)
-
-## Usage Examples
-
-- "Create a spec for user authentication"
-- "What phase is 003-user-auth in?"
-- "Plan the implementation for 003-user-auth"
-- "Clarify ambiguities in 003-user-auth"
-- "Generate tasks for 003-user-auth"
-- "Analyze 003-user-auth for issues"
-- "Implement 003-user-auth"
-- "Test 003-user-auth"
-- "bugfix 003-user-auth"
-- "reopen 003-user-auth" (for closed features)
-- "Verify BUG-001 in 003-user-auth"
-- "Bug status 003-user-auth"
-- "Summarize 003-user-auth" (full summary)
-- "Close 003-user-auth" (lightweight close)
-- "Refresh 003-user-auth" (artifact alignment only)
-
-## Phase Guardrails — STRICT
-
-You MUST determine the current phase before any tool call. Each phase has strict limits:
-
-| Phase | Allowed to Write | Code-Editing Tools | Detect By |
-|-------|-----------------|-------------------|-----------|
-| **Constitution** | `constitution.md` only | BLOCKED | `specs/constitution.md` exists, no `spec.md` |
-| **Specify** | `spec.md` only | BLOCKED | `specs/NNN-name/spec.md` exists, no `plan.md` |
-| **Clarify** | `clarify.md`, `spec.md` (amend) | BLOCKED | `clarify.md` exists |
-| **Plan** | `plan.md`, `research.md`, `data-model.md`, `contracts/*`, `quickstart.md` | BLOCKED | `plan.md` exists, no `tasks.md` |
-| **Tasks** | `tasks.md` only | BLOCKED | `tasks.md` exists, no completions |
-| **Review** | `tasks.md` only (closed-review mode, user approval) | BLOCKED | User says "review", "analyze", or "quality check" |
-| **Implement** | source code, `tasks.md` (completions), `bugs.md` (mark resolved) | ALLOWED | `tasks.md` with pending tasks |
-| **Test** | `bugs.md` only | BLOCKED | `bugs.md` with open bugs |
-| **Reopen** | `bugs.md` (create if missing), source code (fix loop) | ALLOWED (same as bugfix) | `close.md` exists, user says "reopen" |
-| **Summarize / Close** | `implementation-summary.md`, `close.md`, `spec.md` (patch deviations), `plan.md` (patch deviations), `tasks.md` (finalize), `bugs.md` (finalize) | BLOCKED | `implementation-summary.md` and `close.md` both missing |
-| **Refresh** | `spec.md`, `plan.md`, `data-model.md`, `contracts/*` (per-item approval) | BLOCKED | User says "refresh" |
-
-> **Bugfix loop**: reuses Plan, Tasks, and Implement — same permissions, just with `bugs.md` as additional input context.
-> **Summarize/Close** gains `spec.md` and `plan.md` write access to patch intentional deviations.
-> **Refresh** is read-only on code but can update spec artifacts with per-item user approval.
-
-### Enforcement Rules
-- `write_file`/`patch`/`terminal` for builds → **ONLY** during Implement (including bugfix loop implementations)
-- Writing to spec artifacts (`spec.md`, `plan.md`, `tasks.md`, `bugs.md`) → only during their respective phase
-- **Summarize/Close exception**: May patch `spec.md` and `plan.md` to reconcile intentional deviations (with user approval per change)
-- **Refresh exception**: May patch `spec.md`, `plan.md`, `data-model.md`, `contracts/*` with per-item user approval
-- Unknown phase → ASK the user
-- User asks for code outside Implement → REFUSE, suggest correct phase
-
-### Mandatory Close Enforcement
-
-```text
-Pre-Work Self-Check addition:
-  5. Am I starting a NEW feature or marking an existing one complete?
-     IF yes → Does specs/[feature]/contain either implementation-summary.md or close.md?
-       IF no → Is bugs.md all verified?
-         IF yes → BLOCK: Phase 6 required. Run 'close [feature]' first.
-         IF no → OK, feature not ready for close yet.
-```
+## Guardrails
+- Code-editing tools only in Implement (incl. bugfix). Spec artifacts only in their phase; summarize/close and refresh patch spec/plan with approval. Unknown phase → **ASK**. Code requested outside Implement → refuse, name the phase. Not done without a close doc.
diff --git a/src/skills/spec-kit/SKILL.md b/src/skills/spec-kit/SKILL.md
index 8ae9fc8..04c5010 100644
--- a/src/skills/spec-kit/SKILL.md
+++ b/src/skills/spec-kit/SKILL.md
@@ -1,114 +1,58 @@
 ---
 name: spec-kit
-description: Spec-Driven Development (SDD) workflow for Hermes Agent. Load via 'spec-kit' or 'speckit' prefix commands or natural language phrases (e.g. 'spec-kit bugfix [feature]', 'speckit bugfix [feature]', 'spec-kit implement [feature]', 'speckit implement [feature]', "bugfix [feature]", "implement [feature]", "plan [feature]").
+description: Spec-Driven Development (SDD) for Hermes Agent — the overview, conventions and project layout. Load for "how does spec-kit work", "spec-kit conventions", "spec-kit help". Phase commands ('spec-kit specify|plan|tasks|implement|test|review|close [feature]', 'speckit …', "implement [feature]", "plan [feature]") load their own phase skill; routing commands (bugfix, quickfix, reopen, accept, status) load spec-kit-workflow.
+version: 2.1.0
+author: Hermes Agent
+license: MIT
 category: software-development
+metadata:
+  hermes:
+    tags: [spec-kit, sdd, overview]
+    related_skills: [spec-kit-workflow, spec-kit-constitution, spec-kit-specify, spec-kit-clarify, spec-kit-plan, spec-kit-tasks, spec-kit-review, spec-kit-implement, spec-kit-test, spec-kit-summarize, spec-kit-refresh]
 ---
 
 # Spec-Driven Development (SDD)
 
-Spec-driven development for Hermes Agent. Specifications drive code, not the other way around.
-
-**For phase routing (bugfix, implement, plan, reopen, close), load `spec-kit-workflow` instead.** The workflow skill handles all routing decisions based on artifact state and trigger phrases. This skill only documents the overall workflow, conventions, and project structure.
-
-## ⚠️ Critical Approach Rule: Read First, Build Second
-
-**ALWAYS read the source repository design documents before implementing a skill or template that mirrors an existing system.** This prevents creating simplified approximations instead of faithful implementations.
-
-When a user asks to implement parity with an existing system:
-1. Read the actual source design docs, templates, and workflows FIRST
-2. Analyze all commands, templates, and their exact structures
-3. Only then build or update templates
-
-## Core Workflow
+Specifications drive code. Every phase is a one-screen skill with a full procedure under
+`spec-kit/references/skills/.md`, loaded on demand. Routing (bugfix, quickfix, reopen,
+accept, status) is `spec-kit-workflow`; phase skills trigger themselves.
 
 ```text
-Constitution → Specify → Clarify (opt) → Plan → Tasks → Implement → Test
-                                                                      │
-                                                                      └── bugfix loop ──┐
-                                                                ┌──────────────────────┘
-                                                                ▼
-                                                          [Clarify] → Plan → Tasks → [Review] → Implement → Test → Close (mandatory)
-```
-
-| Mode | Trigger | Behavior |
-|------|---------|----------|
-| **specify** (default) | "Create a spec for [feature]" | Full forward phase sequence, manual transitions |
-| **bugfix** | "bugfix [feature]" | Auto-chains Plan→Tasks→Implement, prompts to close |
-| **reopen** | "Reopen [feature]" | Creates bugfix branch from closed feature, preserves original close |
-
-**Constitution is mandatory** in every mode. **Phase 6 (Close) is mandatory** to mark a feature complete.
-
-## Phase Reference
-
-Load `spec-kit-workflow` for the full routing table, prerequisite checks, phase detection, and guardrails.
-
-| Phase | Skill | Purpose |
-|-------|-------|---------|
-| 0 — Constitution | `spec-kit-constitution` | Project principles (brownfield/free-text/wizard) |
-| 1 — Specify | `spec-kit-specify` | Functional requirements, user scenarios |
-| 1.5 — Clarify | `spec-kit-clarify` | Resolve ambiguities in the spec |
-| 2 — Plan | `spec-kit-plan` | Architecture, data flow, module boundaries |
-| 3 — Tasks | `spec-kit-tasks` | Executable task breakdown with TDD flag |
-| 3.5 — Review | `spec-kit-review` | Pre/post implement quality check (optional) |
-| 4 — Implement | `spec-kit-implement` | Phase-level TDD execution |
-| 5 — Test | `spec-kit-test` | Bug tracking and manual testing |
-| 6 — Close | `spec-kit-summarize` | Spec health score, gap analysis, deviation patching |
-| — Refresh | `spec-kit-refresh` | Standalone artifact reconciliation |
-
-## AGENTS.md Conventions
-
-**Put in AGENTS.md**: which skills are available, active spec directories, project-specific context (tech stack, build commands), project conventions.
-
-**Keep out of AGENTS.md**: trigger phrase lists, routing tables, workflow mechanics, phase diagrams, bugfix loop details. Routing belongs in skill files.
-
-## Workflow Tracking
-
-Every spec directory maintains `specs/NNN-name/history.md` — an append-only process log. Each phase skill appends one entry on completion:
-
-```markdown
-## [ISO_TIMESTAMP] | Phase N → [Name] → Complete
-- **Skill**: [skill-name]
-- **Artifacts**: [files created/updated]
-- **Notes**: [key decisions, user input, deviations]
+Constitution → Specify (size S/M/L, ACs, Security & Privacy) → [Clarify] → Plan → Tasks → [Review 3.5]
+  → Implement (RED/GREEN + probes, every tier) → Accept loop → Test → Final review 5.5 (+ devil's advocate)
+  → Close (close.md + change-record.md, ADRs, AGENTS.md)            bugfix loop: Plan → Tasks → Implement → Accept
 ```
 
-**Phase detection shortcut**: Read `history.md` last `→ Complete` line instead of scanning directory artifacts. See `references/history-tracking.md` for the full design.
-
-## Template Path Convention
-
-All skills reference templates as `spec-kit/templates/-template.md` — NOT bare paths like `templates/.md`. This ensures correct resolution regardless of Hermes profile or working directory.
-
-## Project Structure
-
-```text
-src/
-  skills/                # Skill source files (12 .md + umbrella directory)
-    spec-kit/SKILL.md    # This file
-  templates/             # Template source files (13 templates, all *-template.md)
-  references/            # Reference files (5: preflight, auto-commit, etc.)
-scripts/
-  install.sh             # Copies src/* to ~/.hermes/skills/
+| Phase | Skill | Produces |
+|-------|-------|----------|
+| 0 | `spec-kit-constitution` | `specs/constitution.md` (brownfield / free-text / wizard) |
+| 1 · 1.5 | `spec-kit-specify` · `spec-kit-clarify` | `spec.md` (FR, AC, Security & Privacy, size), `clarify.md`, `decisions.md` |
+| 2 · 3 | `spec-kit-plan` · `spec-kit-tasks` | `plan.md` (+ research / data-model / contracts / quickstart by tier), `tasks.md` |
+| 3.5 · 5.5 | `spec-kit-review` | pre-implement report (M lite, L full) · `review-final.md` — the merge gate |
+| 4 | `spec-kit-implement` | code, `evidence/` (RED/GREEN/probes), one commit per phase |
+| 5 | `spec-kit-test` | `bugs.md`; accept mode → `acceptance.md` rounds |
+| 6 | `spec-kit-summarize` | `close.md`, **`change-record.md`**, ADRs, AGENTS.md patches |
+| — | `spec-kit-refresh` | spec/plan reconciled with the code mid-stream |
+| — | `spec-kit-epic` · `spec-kit-design` | optional, only when `epics_dir` / `design_dir` are set: an epic (many features, one goal — **time**) run as E1 specify → E2 plan → E3 breakdown into features → E3.5 review + devil's advocate → build → E6 close · a living module design doc (how a part works now — **space**); feature closes patch both |
+
+**Mandatory**: constitution once per project; size asked at specify; the final review; the close.
+
+## Conventions
+- **Record** (`spec-kit/references/history-tracking.md`): `history: large` by default — size L keeps `history.md` (one fixed-field entry per phase, appended before every commit via `mcp_spec_kit_append_history` / `spec-kit/scripts/spec-kit-log.sh`, guarded by `mcp_spec_kit_history_guard`); S/M do not, and the close builds the timeline from git (`spec-kit/scripts/spec-kit-history.sh`). `**History**: on|off` in a spec overrides. Either way `change-record.md` carries the timeline that survives the squash-merge. Messages: `spec-kit/references/commits.md`.
+- **Evidence** (`spec-kit/references/evidence.md`): the agent's word is never evidence; probes per seam, RED/GREEN files every tier, `ci:`/`user`/`review:` verify.
+- **Size** (`spec-kit/references/sizing.md`): S / M / L — leaner workflow and shorter artifacts (S = a bugfix or small enhancement: a few-line spec, 1–2 ACs, one commit for spec+plan+tasks); evidence and the acceptance round never shrink.
+- **Additive only**: no spec artifact is ever rewritten (`spec-kit/references/preflight.md`).
+- **Decisions**: questions the user would want to decide → `decisions.md` (ruling quotes them; assumption otherwise); design choices stay in plan.md.
+- Templates: `spec-kit/templates/-template.md`. Git: `specs/git-conventions.md` (`feat/NNN-name`, `bug/NNN-name`, reopen suffix `-bugfixing`).
+- AGENTS.md carries: available skills, active spec dirs, build commands, project conventions — not routing tables or phase mechanics.
+- **Scale**: a small project keeps no `design_dir` / `epics_dir` / `adr_dir` and the close has nothing to patch; a platform sets all three. Document roles: spec = one feature · epic = what and in what order · design doc = how it works now · ADR = why · AGENTS.md = where things are and what never to do.
+
+## MCP server (optional, stateless)
+`spec-kit-mcp-server/server.py` derives the phase from `specs//` on every call and validates: `mcp_spec_kit_get_next_actions` (phase card — re-read after compaction), `mcp_spec_kit_advance_phase` (only from the owning phase skill), `mcp_spec_kit_next_id`, `mcp_spec_kit_lint_artifacts` (before every commit), `mcp_spec_kit_acceptance_freeze` / `mcp_spec_kit_acceptance_status`, `mcp_spec_kit_diff_scan`, `mcp_spec_kit_close_feature`, `mcp_spec_kit_timestamp`, `mcp_spec_kit_append_history`, `mcp_spec_kit_history_guard`, `mcp_spec_kit_init_feature`, `mcp_spec_kit_get_feature_state`, `mcp_spec_kit_list_features`, `mcp_spec_kit_project_status`, `mcp_spec_kit_project_set_constitution`, `mcp_spec_kit_reopen_feature`, `mcp_spec_kit_update_artifact`, `mcp_spec_kit_auto_detect_features`. Bugs are file-based (`bugs.md`) — no bug tools. Setup: `spec-kit-mcp-server/README.md`; enable by adding to `~/.hermes/config.yaml`:
+
+```yaml
+mcp_servers:
+  spec-kit:
+    command: 
+    args: ["~/.hermes/skills/spec-kit/mcp-server/server.py"]
 ```
-
-Skills and templates are maintained in the project directory and installed via `./scripts/install.sh`. Do not edit files in `~/.hermes/skills/` directly.
-
-## Git Branch Naming
-
-Default patterns (customise via `specs/git-conventions.md`):
-- Forward development: `{feature_prefix}/NNN-short-name` (default: `feat/`)
-- Bugfix: `{bugfix_prefix}/NNN-short-name` (default: `bug/`)
-- Reopen: `{original_prefix}/NNN-short-name{reopen_suffix}` (default: `-bugfixing`)
-
-During the bugfix loop, all work happens on the existing feature branch. Post-close branch management (squash/merge) follows the project's git workflow.
-
-## Available Templates
-
-Installed via `./scripts/install.sh` — see `src/templates/` for the full list: spec, plan, tasks, constitution, bugs, data-model, research, history, implementation-summary, close, AGENTS, git-conventions, gitignore (13 total).
-
-## References
-
-- `references/preflight.md` — Pre-action self-check (branch, mode, workflow, history)
-- `references/auto-commit.md` — Standard commit patterns across all phases
-- `references/history-tracking.md` — Process history design rationale
-- `references/constitution-principles.md` — 12 principles × 3 options with pros/cons
-- `references/constitution-tables.md` — Wizard tables and brownfield detection data
diff --git a/src/templates/AGENTS-template.md b/src/templates/AGENTS-template.md
index f4e7666..89e3fa5 100644
--- a/src/templates/AGENTS-template.md
+++ b/src/templates/AGENTS-template.md
@@ -4,13 +4,15 @@ This project uses spec-driven development via Hermes Agent's spec-kit skills.
 Skills: constitution, specify, clarify, plan, tasks, implement, test, review, summarize, refresh, workflow
 
 Development modes:
-  - **Specify** (default): Constitution → Specify → [Clarify] → Plan → Tasks → Implement → Test → Close
-  - **Bugfix**: Test → [Clarify] → Plan → Tasks → Implement → Test → Close (auto-chains inner loop)
+  - **Specify** (default): Specify → [Clarify] → Plan → Tasks → [Review] → Implement → Test → Final review → Close
+  - **Bugfix**: Test → [Clarify] → Plan → Tasks → Implement → Test → Final review → Close (auto-chains inner loop)
+  - **Size tiers** (declared in spec.md): S = short spec/plan/tasks, auto-chained; M = default; L = full artifacts + pre-implement review
 
 Key behaviors:
-  - Constitution is mandatory — specify and plan block without it
-  - Phase 6 (Close/Summarize) is mandatory to complete a feature
-  - All spec artifacts are batch-committed when Phase 4 begins (not per design phase)
+  - Constitution (`specs/constitution.md`) is project setup, checked once; the final review enforces its rules
+  - Each design phase commits its own artifacts; implementation commits once per phase
+  - The final review (`review-final.md`) must say READY on the current code before close
+  - Phase 6 (Close/Summarize) is mandatory; it writes/updates ADRs and keeps this file current
   - Implementation uses phase-level TDD: all tests RED first, all code GREEN, then commit
   - TDD can be bypassed at user request during task generation
   - Spec health score (0-100%) computed at close
@@ -18,7 +20,8 @@ Key behaviors:
 
 Artifact paths:
   - Constitution: `specs/constitution.md`
-  - Features: `specs/NNN-name/{spec,plan,tasks,bugs,close}.md`
+  - Features: `specs/NNN-name/{spec,plan,tasks,bugs,review-final,close}.md`
+  - Merge checklist: `specs/merge-checklist.md` · ADRs: [docs/adr/]
 
 Load `spec-kit-workflow` to start. Natural language triggers route to the correct phase.
 
diff --git a/src/templates/acceptance-template.md b/src/templates/acceptance-template.md
new file mode 100644
index 0000000..f82764e
--- /dev/null
+++ b/src/templates/acceptance-template.md
@@ -0,0 +1,23 @@
+# Acceptance: [FEATURE NAME]
+
+> One `## Round N` per acceptance run, appended, never edited. The gate reads the LATEST
+> round: `**Result**: PASS` on a commit with no later code change. Procedure:
+> `spec-kit/references/acceptance.md`.
+
+## Round 1 — [YYYY-MM-DD HH:MM UTC] — [agent]
+
+**Result**: PASS | FAIL | STOPPED
+**Commit**: [short sha of HEAD when the run started]
+**Counts**: pass N · fail N · missing N · deferred N · manual N · regressions N
+**Runs**: fast `output:evidence/acceptance-r1.txt` · e2e [ran: specs … / deferred: stack down] · command/probe [evidence/acceptance-r1-AC-###.txt]
+
+| AC | FRs | Level | Outcome | Tests (result) | Bug |
+|----|-----|-------|---------|----------------|-----|
+| AC-001 | FR-001 | integration | ✅ pass | RulesTests.AC001_rules_are_stored | — |
+| AC-002 | FR-002 | unit | ❌ fail | OverdueTests.AC002_… — `Expected true, got false` | BUG-004 (new) |
+| AC-003 | FR-001, FR-002 | e2e | ⏸ deferred | — (stack down) | — |
+| AC-005 | FR-001 | manual | 👤 manual | — | — |
+
+**Regressions** (failing tests without an AC id): [names → BUG-NNN / none]
+**Frozen tests changed**: [paths → STOPPED / none]
+**Next**: [PASS → final review · FAIL → bugfix chain, round 2 · STOPPED → asked the user: …]
diff --git a/src/templates/adr-template.md b/src/templates/adr-template.md
new file mode 100644
index 0000000..7e3b5de
--- /dev/null
+++ b/src/templates/adr-template.md
@@ -0,0 +1,34 @@
+# NNNN — [Decision title: what is decided, in one line]
+
+> **Status:** ADR — Proposed | Accepted | Superseded by NNNN · **Date:** YYYY-MM-DD · **Deciders:** [roles; quote the ruling if a human decided]
+> **Origin:** specs/[###-feature-name]/ — [decisions.md ruling N / plan.md Round N / research D-n / review finding]
+
+
+
+## Context
+
+[The forces: the problem, the constraints, what made a decision necessary. Cite `path:line`
+for code facts. Two to six sentences.]
+
+## Decision
+
+[One paragraph, imperative: "X is done by Y; Z is not used." Name the boundary it sets.]
+
+## Alternatives considered
+
+- **[Alternative]** — rejected because [concrete reason].
+
+## Consequences
+
+- + [what becomes easier / safer]
+- − [what it costs; what it rules out]
+- Follow-ups: [work this decision creates, if any]
+
+## Evidence
+
+[Where the decision is visible in the repo: files, tests, architecture tests, config.]
+
+## Related
+
+[ADRs this amends or supersedes, the feature spec, docs.]
diff --git a/src/templates/bugs-template.md b/src/templates/bugs-template.md
index 4dfd21d..baf6e40 100644
--- a/src/templates/bugs-template.md
+++ b/src/templates/bugs-template.md
@@ -21,7 +21,9 @@
 - **Expected Result**: [What should happen]
 - **Requires Clarification**: [ ] no / [ ] yes (if yes, run spec-kit-clarify before plan)
 - **Plan Ref**: [Populated by plan phase — reference to plan.md fix section]
-- **Status**: [open/in-progress/resolved/verified]
+- **Status**: [open/in-progress/claimed/verified/superseded]
+- **Evidence**: [set with `claimed` — `output:`, `probe:` under specs/[feature]/evidence/]
+- **Verified-by**: [set with `verified` — `user` / `ci:` / `review:`; never the implementing agent's own word]
 
 ### BUG-002: [Short descriptive title]
 
@@ -35,7 +37,9 @@
 - **Expected Result**: [What should happen]
 - **Requires Clarification**: [ ] no / [ ] yes
 - **Plan Ref**: [Populated by plan phase]
-- **Status**: [open/in-progress/resolved/verified]
+- **Status**: [open/in-progress/claimed/verified/superseded]
+- **Evidence**: [output:/probe: files]
+- **Verified-by**: [user / ci: / review:]
 
 *New bugs are inserted here — before the `---` separator below.*
 
@@ -51,5 +55,7 @@
 **Total Bugs**: N
 **Open**: N
 **In Progress**: N
-**Resolved**: N
-**Verified**: N
+**Claimed** (agent says fixed, awaiting an oracle): N
+**Verified** (user / CI / other-agent review): N
+
+> Status rules: `spec-kit/references/evidence.md`. Legacy `resolved`/`fixed` read as `claimed`.
diff --git a/src/templates/change-record-template.md b/src/templates/change-record-template.md
new file mode 100644
index 0000000..fd6b8bc
--- /dev/null
+++ b/src/templates/change-record-template.md
@@ -0,0 +1,30 @@
+# Change Record: [FEATURE NAME]
+
+> One page, written at close, kept with the feature. The auditor reads this file first: what
+> changed, why, who decided, how it was verified, who approved, how to roll it back
+> (ISO/IEC 27001 A.8.25/A.8.26/A.8.29/A.8.32). Pending fields are written as `pending`, never left blank.
+
+| Field | Value |
+|-------|-------|
+| **Feature / ticket** | specs/[###-feature-name]/ · [ADO/Jira id] |
+| **Branch → base** | [feat/NNN-name] → [dev] · PR [link / pending] |
+| **Size / risk tier** | S | M | L — [reason from spec.md] |
+| **What changed** | [2–3 sentences; layers touched; the seams] |
+| **Why** | [the requirement, in one line] |
+| **Security & Privacy impact** | [from spec.md § Security & Privacy — authorization, personal data, new surface, secrets; "none — because …"] |
+| **Data / schema / config changes** | [migrations, settings, infra; reversible?] |
+| **Implemented by** | [agents / humans — history.md entries, or the tasks.md `**Implemented-by**:` line] |
+| **Reviewed by** | review: / self-review (fresh context) · human PR reviewer: [name / pending] |
+| **Verification** | acceptance round N PASS @  · `ci:` · probes: [n] · manual checks: [who, what, quoted] |
+| **Decisions** | rulings D-… (by [user]) · assumptions still unconfirmed: [ids / none] · ADRs: [NNNN / none] |
+| **Deployment approval** | [who / pipeline run / pending] |
+| **Rollback** | [revert PR / redeploy previous artefact / data rollback steps; "forward-only because …"] |
+| **Known follow-ups** | [MEDIUM findings, deferred ACs, open bugs by id / none] |
+
+## Timeline
+
+History on: one row per `history.md` entry. History off: `spec-kit/scripts/spec-kit-history.sh [feature]` on the branch before the squash (date · author · subject) — this page is what survives:
+
+| Date | Phase | By | Commit | Evidence |
+|------|-------|----|--------|----------|
+| | | | | |
diff --git a/src/templates/close-template.md b/src/templates/close-template.md
index 13df784..9b405c2 100644
--- a/src/templates/close-template.md
+++ b/src/templates/close-template.md
@@ -1,28 +1,44 @@
-[Close: FEATURE NAME]
+# Close: [FEATURE NAME]
 
-**Feature**: specs/[###-feature-name]/
-**Spec Health**: N%
-**TDD Mode**: Active / Bypassed by user
+**Feature**: specs/[###-feature-name]/ · **Date**: [DATE] · **Size**: S | M | L · **Mode**: close | summarize
+**Spec Health**: N% = (resolved + acknowledged) / total · **TDD**: active / bypassed
+**Change record**: `change-record.md` (the auditor's page — ticket, risk, approvals, rollback, timeline)
 
-## Intent Alignment
-- Code matches spec intent: Yes / Partially / No
-- Deviations: [1-2 sentences describing key differences between spec and code]
+## Evidence
+
+| Gate | Oracle | Reference |
+|------|--------|-----------|
+| Acceptance / regression | ci: / output:evidence/acceptance-r.txt | round N PASS @  / ❌ unverified |
+| External seams | probe: per seam | [list] |
+| Bugs | Verified-by per bug | N verified · N claimed-unverified (listed below) |
+| Final review | READY / READY-WITH-FOLLOWUPS @  · review: / self-review | review-final.md Round N |
 
 ## Artifact State
 
 | Artifact | Status |
 |----------|--------|
-| `spec.md` | ✅ current / ⚠️ needs review / ❌ outdated |
-| `plan.md` | ✅ current / ⚠️ needs review / ❌ outdated |
-| `tasks.md` | ✅ all complete / ⚠️ N remaining |
-| `bugs.md` | ✅ all verified / ⚠️ N open |
-| `implementation-summary.md` | ✅ complete / ❌ not generated |
-
-## Key Decisions
-- **[Decision]**: [Rationale]
-
-## Spec Health Calculation
-- Resolved (implemented as planned or intentionally deviated): N
-- Acknowledged (deferred with documented reason): N
-- Not Done (missing without documented reason): N
-- **Spec Health** = (resolved + acknowledged) / total * 100 = N%
+| `spec.md` / `plan.md` / `data-model.md` / `contracts/` | ✅ current / ⚠️ needs review / ❌ outdated — [patched at close: …] |
+| `tasks.md` · `bugs.md` | ✅ all done · ✅ all verified / ⚠️ N claimed-unverified |
+| `plan.md` Current Design | regenerated |
+
+## Gaps *(M: exceptions only · L "summarize": every FR / story / entity / contract)*
+
+| Item | Planned | Actual | Verdict | Rationale / follow-up |
+|------|---------|--------|---------|------------------------|
+| [FR-00N] | | | ✅ resolved / ⚠️ acknowledged / ❌ not done → BUG-NNN | |
+
+Unverified claims: [bug ids / none]. Open questions / future work: [follow-ups from the final review].
+
+## Architecture Decisions
+
+> "None met the ADR bar" is a valid row — omitting the section is not.
+
+| Decision | Source | ADR bar (why / why not) | Action | ADR |
+|----------|--------|-------------------------|--------|-----|
+| | decisions.md D-n / plan Round n / review Q-n | cross-feature / hard to reverse / re-litigable / contradicts ADR NNNN — or feature-local | new / supersedes NNNN / evidence appended / feature-local | docs/adr/NNNN-….md |
+
+**ADR index**: updated / n/a · **AGENTS.md**: [updated — sections / no change needed — why]
+
+## Reopened — [YYYY-MM-DD] *(appended on reopen, original close above untouched)*
+
+Previous health N% → M%. [what changed; new gaps; decisions]
diff --git a/src/templates/decisions-template.md b/src/templates/decisions-template.md
new file mode 100644
index 0000000..13080d3
--- /dev/null
+++ b/src/templates/decisions-template.md
@@ -0,0 +1,12 @@
+# Decisions and Assumptions: [FEATURE NAME]
+
+> Every question the workflow could not put to a human is an **assumption**, not a ruling.
+> Record it here with the alternative not taken; a reviewer reads this file first. A real
+> ruling quotes the user's words. Append only; close lists the assumptions still unconfirmed.
+
+| ID | Date (UTC) | Kind | Phase | Question | Taken | Alternative not taken | Source |
+|----|------------|------|-------|----------|-------|------------------------|--------|
+| D-001 | [timestamp] | assumption | [Phase N] | [the ASK that had no human answer] | [what the agent did] | [what it did not do] | agent:[name] |
+| D-002 | [timestamp] | ruling | [Phase N] | [the question put to the user] | [what was decided] | — | user: "[quoted words]" |
+
+**Kinds**: `assumption` (no human answered — to be confirmed or reversed), `ruling` (a human decided; quote them), `reversed` (a later entry overturns an earlier one — name it).
diff --git a/src/templates/design-doc-template.md b/src/templates/design-doc-template.md
new file mode 100644
index 0000000..7d188a6
--- /dev/null
+++ b/src/templates/design-doc-template.md
@@ -0,0 +1,51 @@
+# [Module name] — design
+
+> **Status:** current · **Owner:** [team / name] · **Last patched:** [DATE] by [feature]
+> A living description of how this part of the system works **now** (≤ 3–4 pages). Patched in
+> place by every feature close that changes it — never copied to `-v2`. Decisions live in ADRs;
+> this page describes the result. (ISO/IEC 27001 A.8.27 — the architecture an auditor reads.)
+
+> `system.md` (the reserved name): replace *Components* with the container table (service / store / external system · technology · owner · trust boundary) and *Data flow* with the context diagram; every module doc links here.
+
+## Purpose and boundary
+
+[What this module is for; what it owns; what it explicitly does not do. Which services /
+projects / directories it is.]
+
+## Components
+
+| Component | Path | Responsibility |
+|-----------|------|----------------|
+
+## Data flow
+
+[Entry → processing → storage / response, in prose or one diagram. Name the request/event
+that starts it and where it ends.]
+
+## Seams and contracts
+
+| Seam | Kind (DB function / HTTP contract / message / file / service) | Contract | Owner |
+|------|------|----------|-------|
+
+## Invariants and security
+
+- Authorization / tenant boundary: [how another tenant's data is kept out — the filter, the policy]
+- Personal data handled: [what, where, retention] · Never logged: [what]
+- [other invariants: idempotency, ordering, money/rounding, time zones]
+
+## Testing
+
+[Harnesses that cover it: unit / integration / contract / e2e; golden files; probes against real data]
+
+## Known debt
+
+- [item — ticket / ADR]
+
+## Decisions
+
+| ADR | Title | Status |
+|-----|-------|--------|
+
+## Change log *(one line per feature close that patched this page)*
+
+- [DATE] [feature] — [what changed in the design]
diff --git a/src/templates/epic-features-template.md b/src/templates/epic-features-template.md
new file mode 100644
index 0000000..a4da0c4
--- /dev/null
+++ b/src/templates/epic-features-template.md
@@ -0,0 +1,20 @@
+# Features: [EPIC NAME]
+
+**Epic**: epic.md · **Plan**: plan.md · **Order**: [#1 → #2 → (#3 ∥ #4) → …]
+
+> Stage E3 — the epic's "tasks" are features. One row per single-spec feature, ordered; every
+> EAC covered by ≥ 1 feature. Rows are added before a spec exists and patched by
+> `spec-kit-specify` (spec dir, size) and by every feature close (status, PR, health, ADRs).
+
+| # | Feature | Spec dir | Size | Depends on | Modules | EACs | Status | PR | Health | ADRs | Note |
+|---|---------|----------|------|------------|---------|------|--------|----|--------|------|------|
+| 1 | [short name — one sentence of intent] | — | M? | — | [reader] | EAC-001 | planned | — | — | — | |
+| 2 | | — | | #1 | | | planned | | | | |
+
+**Status values**: planned · specified · implementing · closed · dropped (reason in Note)
+
+## EAC coverage
+
+| EAC | Features | Verified by (filled at epic close) |
+|-----|----------|------------------------------------|
+| EAC-001 | #1, #2 | |
diff --git a/src/templates/epic-plan-template.md b/src/templates/epic-plan-template.md
new file mode 100644
index 0000000..0176a0d
--- /dev/null
+++ b/src/templates/epic-plan-template.md
@@ -0,0 +1,42 @@
+# Epic plan: [EPIC NAME]
+
+**Epic**: epic.md · **Date**: [DATE] · **Modules**: [names as in `design_dir` — the design docs this epic changes]
+
+> Stage E2. HOW across features — the architecture the single features will implement
+> piece by piece. Line-level design belongs to each feature's plan.md.
+
+## Current state
+
+[What exists today, from the module design docs and the code — 5–10 lines with paths. What
+is wrong or missing that the goal needs.]
+
+## Target architecture
+
+[Components, boundaries, data flow at the end of the epic. Which modules change how; which
+stay. One diagram or ≤ 1 page of prose.]
+
+## Seams and contracts
+
+| Seam | Today | After the epic | Owner feature |
+|------|-------|----------------|---------------|
+
+## Cross-feature decisions
+
+| ID | Decision | Alternatives rejected | Why | ADR |
+|----|----------|------------------------|-----|-----|
+| ED-001 | | | | — / NNNN |
+
+## Sequencing constraints and parallelism
+
+[What must come first (shared infrastructure, a seam, a migration); what can run in parallel;
+what can be dropped last if time runs out.]
+
+## Rollout, migration, rollback
+
+[Feature flags, data migration order, how the epic can stop halfway without harm, how to roll
+back the whole thing.]
+
+## Risks
+
+| Risk | Impact | Mitigation | Owner |
+|------|--------|------------|-------|
diff --git a/src/templates/epic-review-template.md b/src/templates/epic-review-template.md
new file mode 100644
index 0000000..e6f428b
--- /dev/null
+++ b/src/templates/epic-review-template.md
@@ -0,0 +1,43 @@
+# Epic review: [EPIC NAME]
+
+> One `## Round N` per run, appended. Stage E3.5 (before the first feature is specified) and
+> E6 (at close). Verdict gates the next stage.
+
+## Round 1 — [YYYY-MM-DD] — E3.5 pre-build — [review: | self-review (fresh context: yes/no)]
+
+**Verdict**: GO | GO-WITH-CHANGES | NO-GO
+
+### 1. Coverage and scope
+EAC → features: [n/N covered; uncovered: …] · features without an EAC: [scope creep?] ·
+non-goals respected: [yes / which row violates] · size realism: [rows likely bigger than their size]
+
+### 2. Fit and rules
+Constitution, existing ADRs, module design docs (current state is true?), cross-feature rules
+consistent and checkable: [findings with path / § references]
+
+### 3. Sequencing and risk
+First feature delivers something testable: [yes/no] · hidden dependency: [...] · the plan's risks
+have owners: [...]
+
+### 4. Devil's advocate *(separate sub-agent for 5+ features; different model when available)*
+
+| # | Objection (concrete) | Answer | Outcome |
+|---|----------------------|--------|---------|
+| O1 | strongest case against doing this epic at all; the simplest alternative that delivers ~80 % | | accepted → change / rebutted (evidence) / deferred |
+| O2 | pre-mortem: six months later the epic failed or was abandoned — why? | | |
+| O3 | abuse case at system level (new trust boundary, tenant path, data export) | | |
+| O4 | riskiest assumption in epic.md / ED-… — what if it is wrong? | | |
+| O5 | | | |
+
+### 5. Findings
+| ID | Severity | Where | Finding | Fix |
+|----|----------|-------|---------|-----|
+
+### 6. Outcome
+Changes applied to epic.md / plan.md / features.md: [list] · open rulings for the owner: [list]
+
+## Round N — [YYYY-MM-DD] — E6 close review
+
+**Verdict**: CLOSED | NOT-DONE
+EAC verified: [each with evidence — feature ACs, probe, user's quoted words] · dropped scope: [rows + why] ·
+design docs patched: [list] · ADRs: [list] · devil's advocate at close: "what does the goal look like unmet?" — [answer]
diff --git a/src/templates/epic-template.md b/src/templates/epic-template.md
new file mode 100644
index 0000000..840d4fc
--- /dev/null
+++ b/src/templates/epic-template.md
@@ -0,0 +1,53 @@
+# Epic: [EPIC NAME]
+
+**Id**: [NNN-short-name — NNN = the tracker's epic number (ADO / Jira) when one exists, else the next free number] · **Tracker**: [ADO Epic #NNN / link / none] · **Status**: specified | planned | broken-down | reviewed | building | closed · **Owner**: [name] · **Opened**: [DATE]
+**Goal**: [one sentence — the outcome, not the feature list]
+
+> Stage E1 of `spec-kit-epic`. An epic is a body of work in *time*: many single-spec features
+> towards one goal. This file is the epic's spec: WHAT and WHY. HOW across features is
+> `plan.md`; the ordered features are `features.md`; reviews append to `review.md`.
+
+## Problem and users *(why now)*
+
+[Who has the problem, what it costs them today, why this programme now. 3–6 lines; a reader
+should be able to say "no" to it.]
+
+## Success metrics *(post-launch, lagging — measured after the epic closes)*
+
+| Metric | Today | Target | Measured how / when |
+|--------|-------|--------|---------------------|
+
+## Alternatives considered
+
+| Alternative | Why not (or: why not yet) |
+|-------------|---------------------------|
+| Do nothing | |
+| [smaller / different approach] | |
+
+## Scope
+
+- **In**: [bounded list] · **Out (non-goals)**: [explicit — what a reader would assume is in, but is not]
+- Stakeholders / owners of a ruling: [who decides scope, who accepts]
+
+## Epic acceptance criteria *(the done-when — measurable, verifiable at the end)*
+
+- **EAC-001** [outcome, e.g. "every Analyze tab serves from the reader; no V2 request reaches a V1 reporting SP"] — Verify: [feature ACs AC-… of NNN / probe / command / user]
+- **EAC-002** [outcome] — Verify: […]
+
+## Cross-feature rules
+
+Rules every feature in this epic must obey — the reviews check them like constitution MUSTs.
+
+- [e.g. "No new reader rollup without a golden file"] · [e.g. "V1 is frozen — ADR 0012"]
+
+## Security & Privacy at epic level *("None — because …" is valid)*
+
+| Question | Answer |
+|----------|--------|
+| New trust boundary, tenant path or external surface the epic introduces | |
+| Personal data the epic starts to collect, display, export or log | |
+| Secrets, dependencies, infrastructure the epic adds | |
+
+## Assumptions and open questions
+
+- [assumption — to be confirmed by …] · [NEEDS CLARIFICATION: …] *(max 3)*
diff --git a/src/templates/epics-index-template.md b/src/templates/epics-index-template.md
new file mode 100644
index 0000000..aa15f57
--- /dev/null
+++ b/src/templates/epics-index-template.md
@@ -0,0 +1,8 @@
+# Epics
+
+> The roadmap page: one row per epic under this directory, maintained by `spec-kit-epic`
+> (`epics_index: on` in git-conventions.md). Status: specified · planned · broken-down ·
+> reviewed · building · closed.
+
+| Id | Epic | Status | Owner | Tracker | Features (closed / planned) | Opened | Closed |
+|----|------|--------|-------|---------|-----------------------------|--------|--------|
diff --git a/src/templates/git-conventions-template.md b/src/templates/git-conventions-template.md
index 5864df9..b5271e0 100644
--- a/src/templates/git-conventions-template.md
+++ b/src/templates/git-conventions-template.md
@@ -42,16 +42,42 @@ style: conventional-commits    # conventional-commits | custom
 | Operation | Message |
 |-----------|---------|
 | Constitution | `spec(phase-0): constitution for {PROJECT}` |
-| Batch (start implement) | `spec: {feature} spec artifacts (spec, plan, tasks)` |
+| Spec + plan + tasks (size S) | `spec(phase-1-3): {feature} spec, plan, tasks` |
 | Implement phase | `feat: {feature} Phase {N} - {Phase Name}` |
 | Regression umbrella | `fix: {feature} BF-REGRESSION-001 - fix regressions` |
 | Bugfix (per task) | `fix: {feature} BF-{###} - description` |
 | Bug log | `spec(phase-5): {feature} bug log` |
+| Acceptance round | `spec(phase-5): {feature} acceptance round {N} ({RESULT} {a}/{b})` |
+| Final review | `spec(review): {feature} final review (verdict: {VERDICT})` |
 | Close/Summary | `spec(phase-6): {feature} summary (health: {N}%)` |
 | Refresh | `spec(refresh): {feature} reconcile artifacts` |
 
 ---
 
+## Documentation locations
+
+Used by the close (ADRs, AGENTS.md) and by the final review (merge checklist). Omit a key to
+use the default.
+
+```
+adr_dir: docs/adr               # default: first existing of docs/adr, docs/decisions, doc/adr, adr
+adr_index: docs/adr/README.md   # the ADR list to update; default: README.md / index.md in adr_dir
+agents_file: AGENTS.md          # the agent context file kept current at close (also CLAUDE.md if it restates it)
+merge_checklist: specs/merge-checklist.md
+history: large                  # always | large | never — keep specs//history.md: large = size L only (default); spec.md `**History**: on|off` overrides
+design_dir: docs/design         # living module design docs (design-doc-template.md); ABSENT → plan.md's Current Design is the only design, nothing else is created
+epics_dir: specs/epics          # epics as specs/epics/NNN-name/{epic,plan,features,review}.md (NNN = tracker epic id, e.g. ADO); ABSENT → every feature is its own epic
+epics_index: on                 # on | off — keep [epics_dir]/README.md, the roadmap table (one row per epic), maintained by spec-kit-epic
+changelog: CHANGELOG.md         # Keep-a-Changelog file the close adds an Unreleased line to; ABSENT → no changelog step
+runbooks_dir: docs/runbooks     # operational docs the close checks for statements the diff made wrong; ABSENT → skipped
+```
+
+A small project leaves `design_dir` and `epics_dir` out: the close then has nothing to patch
+and nothing is ever created unprompted. A platform sets both; `spec-kit-design` and
+`spec-kit-epic` create the documents, the feature close keeps them true.
+
+---
+
 ## Merge behaviour
 
 ```
diff --git a/src/templates/gitignore-template.md b/src/templates/gitignore-template.md
index 89e9ef1..2af0481 100644
--- a/src/templates/gitignore-template.md
+++ b/src/templates/gitignore-template.md
@@ -3,6 +3,10 @@
 # Spec artifacts (specs/) are documentation and SHOULD be committed.
 # Add project-specific ignores below.
 
+# spec-kit: the MCP server derives state from the files and persists nothing;
+# a legacy state.json here is ignored and only causes merge conflicts.
+specs/.spec-kit/
+
 # Python
 __pycache__/
 *.py[cod]
diff --git a/src/templates/history-template.md b/src/templates/history-template.md
index edbc53a..a0b501b 100644
--- a/src/templates/history-template.md
+++ b/src/templates/history-template.md
@@ -1,7 +1,12 @@
-[Process History: FEATURE NAME]
+# Process History: [FEATURE NAME]
 
-## [TIMESTAMP] | Phase N → [Phase Name] → Complete
-- **Skill**: [skill-name]
-- **Artifacts**: [list of created/updated files]
-- **Commit**: [commit hash from `git rev-parse HEAD`, or "N/A" if no git commit]
-- **Notes**: [key decisions, deviations, user input summary]
+> Append-only record. One entry per phase / bugfix / regression / close. Format and rules:
+> `spec-kit/references/history-tracking.md`. Append with `mcp_spec_kit_append_history` or
+> `spec-kit/scripts/spec-kit-log.sh` — never type the timestamp yourself.
+
+## [UTC ISO timestamp] | Phase 1 | spec-kit-specify | [agent]
+- Artifacts: spec.md
+- Tests: none
+- Evidence: none
+- Commit: spec(phase-1): [feature] spec
+- Note: [≤ 25 words]
diff --git a/src/templates/implementation-summary-template.md b/src/templates/implementation-summary-template.md
deleted file mode 100644
index b6efac3..0000000
--- a/src/templates/implementation-summary-template.md
+++ /dev/null
@@ -1,118 +0,0 @@
-[Implementation Summary: FEATURE NAME]
-
-**Feature**: specs/[###-feature-name]/
-**Created**: [DATE]
-**Status**: [Complete / In Progress]
-**Spec Health**: N%
-**TDD Mode**: Active / Bypassed by user
-
-## Spec Health Scoring
-
-| Category | Count |
-|----------|-------|
-| ✅ Resolved (implemented or intentionally deviated with rationale) | N |
-| ⚠️ Acknowledged (deferred with documented reason) | N |
-| ❌ Not Done (missing without documented reason) | N |
-| **Spec Health** | **N%** |
-
-> Formula: `(resolved + acknowledged) / (resolved + acknowledged + not_done) * 100`
-> - **100%**: Artifacts fully aligned with code — no action needed
-> - **80-99%**: Minor gaps tracked but not blocking — acceptable
-> - **50-79%**: Significant drift — recommend running `spec-kit-refresh` before refactoring
-> - **<50%**: Artifacts are misleading — run `spec-kit-refresh` before proceeding
-
-## Overview
-
-[Brief summary of what was implemented — 2-3 sentences]
-
-## What Was Implemented
-
-### Core Features
-| User Story / Requirement | Status | Notes |
-|--------------------------|--------|-------|
-| [US1: description] | [Implemented / Partial / Not Started] | [key files changed, decisions made] |
-| [FR-001: description] | [Implemented / Partial / Not Started] | [key files changed, decisions made] |
-| ... | | |
-
-### Architecture & Design
-- **Architecture type**: [single project / web app / etc.]
-- **Language / Runtime**: [e.g., Python 3.11, Node 20]
-- **Key Dependencies**: [list added dependencies]
-- **Data Model**: [entities created / modified]
-- **Contracts**: [APIs, schemas defined]
-
-## Files Changed
-
-| File | Change Type | Description |
-|------|------------|-------------|
-| `path/to/file.ext` | created / modified / deleted | Brief purpose |
-| ... | | |
-
-## Test Coverage
-
-| Type | Passing | Notes |
-|------|---------|-------|
-| Unit tests | N | [frameworks used] |
-| Integration tests | N | [what's covered] |
-| E2E tests | N | [scope] |
-| Contract tests | N | [if applicable] |
-
-## Known Issues & Bugs
-
-| Bug ID | Severity | Status | Summary |
-|--------|----------|--------|---------|
-| BUG-001 | minor | resolved | [short description] |
-| BUG-002 | critical | verified | [short description] |
-
-## Gap Analysis — Plan vs Implementation
-
-This section compares what was specified/planned with what was actually implemented. Each gap is either **resolved** (intentional, with rationale) or **acknowledged** (deferred, tracked for future).
-
-| Category | Planned | Actual | Verdict | Notes / Rationale |
-|----------|---------|--------|---------|-------------------|
-| [FR-001] | [description] | [what was built] | ✅ Resolved | [rationale if different] |
-| [US2 user story] | [acceptance criteria] | [actual behavior] | ✅ Resolved | [test outcome] |
-| [Data model entity] | [planned entity/field] | [actual entity/field] | ⚠️ Acknowledged | [deferred — not critical, tracked for later] |
-| [API contract] | [planned endpoint] | [actual endpoint] | ❌ Not Done | [not implemented, should be in bugs.md] |
-| ... | | | ✅ Resolved / ⚠️ Acknowledged / ❌ Not Done | |
-
-### Resolved Deviations
-- **[Aspect]**: Planned X, built Y because [reason]. Spec should be updated to reflect Y.
-- ...
-
-### Acknowledged Gaps (Deferred)
-- **[Aspect]**: Planned X, not built. Reason: [scope cut, ran out of time, not needed]. Track as future work.
-- ...
-
-## Spec Artifact Refresh
-
-The following spec artifacts were **automatically updated** to reflect intentional deviations found during gap analysis:
-
-| Artifact | Change | Rationale |
-|----------|--------|-----------|
-| `spec.md` | [FR-XXX: updated requirement wording to match actual behavior] | Code intentionally deviated from spec — spec brought in line |
-| `plan.md` | [architecture section updated] | Implementation used a different data structure than planned |
-| *(none)* | *All artifacts already aligned* | *No changes needed* |
-
-> If artifacts show `⚠️ needs review` or `❌ outdated`, they were NOT auto-updated because the drift requires user judgment. Run `spec-kit-refresh` to reconcile them manually.
-
-## Decisions Made
-
-| Decision | Rationale | Alternatives Considered |
-|----------|-----------|------------------------|
-| [choice made] | [why] | [what else was considered] |
-
-## Open Questions / Future Work
-
-- [anything deferred, known limitations, future improvements]
-
-## Spec State
-
-| Artifact | Status | Action Needed |
-|----------|--------|---------------|
-| `spec.md` | ✅ up-to-date / ⚠️ needs review / ❌ outdated | [update to match actual implementation] |
-| `plan.md` | ✅ up-to-date / ⚠️ needs review / ❌ outdated | [update architecture to match what was built] |
-| `tasks.md` | ✅ all complete / ⚠️ N remaining | [mark incomplete or close] |
-| `bugs.md` | ✅ all verified / ⚠️ N open | [resolve or defer remaining] |
-| `data-model.md` | ✅ up-to-date / ⚠️ needs review | [sync with actual schema] |
-| `contracts/` | ✅ up-to-date / ⚠️ needs review | [sync with actual API contracts] |
diff --git a/src/templates/merge-checklist-template.md b/src/templates/merge-checklist-template.md
new file mode 100644
index 0000000..f05caa3
--- /dev/null
+++ b/src/templates/merge-checklist-template.md
@@ -0,0 +1,59 @@
+# Merge Checklist
+# Checklist version: 1
+
+Copy to `specs/merge-checklist.md` and edit. `spec-kit-review` (final mode) runs every
+command below, saves each output under `specs/[feature]/evidence/final-.txt`, and
+judges every item. A failing **blocking** item makes the verdict NOT READY.
+
+Empty command → the item is judged by reading the diff. Remove items that do not apply;
+add the project's own (they are the project rules the final review enforces).
+
+---
+
+## Commands
+
+```
+base_branch:   main                        # defaults to branch_source in git-conventions.md
+build:         [e.g. dotnet build -warnaserror | npm run build]
+test:          [the FULL suite, e.g. dotnet test | npm test -- --watch=false]
+lint:          [e.g. npm run lint]
+format_check:  [e.g. dotnet format --verify-no-changes | npm run prettier:diff]
+extra:         [any other command that must pass, e.g. architecture tests]
+
+# Acceptance loop (spec-kit/references/acceptance.md) — results must be JUnit XML or TRX
+acceptance_fast:          [the FULL unit + integration + component suites writing results, e.g.
+                           dotnet test --logger "trx;LogFileName=acc.trx" && npm test -- --reporter=junit --outputFile=test-results/acc.xml]
+acceptance_fast_results:  [comma-separated globs, e.g. **/TestResults/acc.trx, test-results/acc.xml]
+acceptance_e2e:           [ONE feature's specs only — {specs} is replaced, e.g.
+                           npx cypress run --spec {specs} --reporter junit --reporter-options mochaFile=test-results/e2e-[hash].xml]
+acceptance_e2e_results:   [e.g. test-results/e2e-*.xml]
+acceptance_e2e_ready:     [exit 0 when the stack is up, e.g. curl -sf http://localhost:4200 >/dev/null]
+acceptance_max_rounds:    5
+```
+
+## Generic gate (always checked)
+
+| # | Item | Blocking |
+|---|------|----------|
+| G1 | Branch merges cleanly into the base (`diff_scan` merge-conflict check) | yes |
+| G2 | Build passes with no NEW warnings in changed files | yes |
+| G3 | Full test suite passes; CI run on the reviewed commit recorded as `ci:` when a pipeline exists | yes |
+| G4 | Lint / format clean | yes |
+| G5 | No secrets, keys, certificates, backups or `.env` files in the diff (`diff_scan`) | yes |
+| G6 | No conflict markers, focused tests, debugger statements (`diff_scan`) | yes |
+| G7 | New TODO/FIXME carry a ticket reference or are removed | no |
+| G8 | Every changed file is in scope (`diff_scan` unplanned-change list explained) | yes |
+| G9 | Schema/data migrations are included, ordered, and reversible or explicitly one-way | yes |
+| G10 | Public API / contract changes are intentional and documented (breaking → called out) | yes |
+| G11 | New dependencies: licence and version policy respected, lock file updated | yes |
+| G12 | Config / infrastructure / environment changes documented for deploy | yes |
+| G13 | User-facing docs, runbooks, AGENTS.md touched where the change makes them wrong | no |
+| G14 | Commit messages follow `specs/git-conventions.md` | no |
+| G15 | PR description drafted (what / why / how verified / risks / rollback) | no |
+
+## Project rules (edit — these are this project's non-negotiables)
+
+| # | Item | Blocking |
+|---|------|----------|
+| P1 | [e.g. "Module X must not reference module Y"] | yes |
+| P2 | [e.g. "No new URLs in the frozen config file"] | yes |
diff --git a/src/templates/plan-template.md b/src/templates/plan-template.md
index 093f07b..ab73c65 100644
--- a/src/templates/plan-template.md
+++ b/src/templates/plan-template.md
@@ -1,53 +1,60 @@
 # Implementation Plan: [FEATURE]
 
-**Branch**: [###-feature-name] | **Date**: [DATE] | **Spec**: [link]
+**Branch**: [###-feature-name] | **Date**: [DATE] | **Spec**: spec.md | **Size**: [S | M | L]
+**Modules**: [module names as in `design_dir` — the design docs the close will patch; delete when the project keeps none]
 
-**Input**: Feature specification from /specs/[###-feature-name]/spec.md
+> Size S: keep Summary, Current Design, the Technical Context lines that matter, Seams,
+> Acceptance Test Strategy, Rounds — delete the rest; no research / data-model / contracts /
+> quickstart unless the plan cannot be understood without one.
 
 ## Summary
 
-[Extract from feature spec: primary requirement + technical approach from research]
+[Primary requirement + technical approach in a few sentences.]
+
+## Current Design
+
+> **Regenerated, never appended** — what is BUILT, ≤ 1 page; rewritten by the close (and by
+> refresh). The rounds below are the dated history.
+
+[Until the first close: "Not yet built — see the sections below."]
 
 ## Technical Context
 
-- **Language/Version:** [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
-- **Primary Dependencies:** [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
-- **Storage:** [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
-- **Testing:** [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
-- **Target Platform:** [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
-- **Project Type:** [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
-- **Performance Goals:** [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
-- **Constraints:** [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
-- **Scale/Scope:** [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
+Language/version · primary dependencies · storage · testing · target platform · performance
+goals · constraints · scale — only the lines that matter; `NEEDS CLARIFICATION` where unknown.
+
+## Constitution Check *(advisory gate)*
+
+[Simplicity, anti-abstraction, integration-first — violations justified in Complexity Tracking.]
 
-## Constitution Check
+## External Seams
 
-**GATE:** Must pass before Phase 0 research. Re-check after Phase 1 design.
+| Seam | Kind (DB function / HTTP contract / message / file / service) | Probe (what to query before writing the fixture) |
+|------|------|------|
 
-[Insert specific gates from constitution: Simplicity, Anti-Abstraction, etc.]
+## Acceptance Test Strategy
 
-## Project Structure
+| AC | Level | Harness | Test file | Needs | Result source |
+|----|-------|---------|-----------|-------|---------------|
+| AC-001 | integration | [e.g. WebApplicationFactory + Testcontainers] | [path] | Docker | TRX / JUnit path |
 
-### Documentation (this feature)
+## Design *(M / L)*
 
-specs/[###-feature-name]/
-├── plan.md              # This file
-├── research.md          # Phase 0 output
-├── data-model.md        # Phase 1 output
-├── quickstart.md         # Phase 1 output
-└── contracts/           # Phase 1 output (API specs)
+Architecture, data flow, module boundaries, error handling, project structure decision.
+Details in `research.md` (decision → rationale → alternatives), `data-model.md`, `contracts/`,
+`quickstart.md` — only those the feature needs.
 
-### Source Code
+## Complexity Tracking *(only if the Constitution Check has violations)*
 
-[Select and document the structure: Single Project / Web App / Mobile+API]
+| Violation | Why needed | Simpler alternative rejected because |
+|-----------|-----------|--------------------------------------|
 
-**Structure Decision:** [Document the selected structure]
+## Rounds (ADR log)
 
-## Complexity Tracking
+> One dated section per bugfix / reopen round, appended, never edited. At close, rounds that
+> pass the ADR bar become project ADRs.
 
-Fill ONLY if Constitution Check has violations that must be justified.
+### Round 1 — [YYYY-MM-DD] — [BUG-NNN, …] — supersedes: [§ or "nothing"]
 
-| Violation | Why Needed | Simpler Alternative Rejected Because |
-| :--- | :--- | :--- |
-| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
-| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
\ No newline at end of file
+- **Context**: [what was wrong, bug ids] · **Decision**: [what changes] ·
+  **Consequences**: [what else moves] · **Plan Ref**: [the bugs.md Plan Ref value]
diff --git a/src/templates/review-final-template.md b/src/templates/review-final-template.md
new file mode 100644
index 0000000..aef19be
--- /dev/null
+++ b/src/templates/review-final-template.md
@@ -0,0 +1,62 @@
+# Final Review: [FEATURE NAME]
+
+> Merge-readiness review — phase 5.5, mandatory before close. One `## Round N` per run,
+> appended, never edited. The close reads the LATEST round's Verdict and Reviewed-commit; a
+> code commit after that sha makes the round stale. **Exceptions only**: the full AC → test
+> matrix is in acceptance.md, the FR → task map in tasks.md — do not repeat them here.
+
+## Round 1 — [YYYY-MM-DD] — [review: | self-review by  (fresh context: yes/no)]
+
+**Verdict**: READY | READY-WITH-FOLLOWUPS | AWAITING-OWNER | NOT READY
+**Reviewed-commit**: [short sha of HEAD when the review ran]
+**Base**: [branch] @ [merge-base sha] · **Size**: S | M | L · **Implemented-by**: [agent, from the history.md implement entries]
+**Counts**: CRITICAL N · HIGH N · MEDIUM N · checklist failures N · awaiting owner N
+
+### 1. Spec conformance
+
+Coverage: FR [n/N] ✅ · SC [n/N] ✅ · edge cases [n/N] ✅ · acceptance round [N] PASS @ [sha] (frozen tests unchanged).
+Rows for everything NOT ✅:
+
+| ID | Requirement (short) | Verdict | Code / evidence | Why |
+|----|---------------------|---------|-----------------|-----|
+| [FR-00N] | … | ⚠️ partial / ❌ missing / ↔ deviates / 👤 awaiting owner | `path:line` · test | |
+
+Contracts / data model vs code: [matches / differs — how]. Unplanned behaviour: [list / none].
+
+### 2. Constitution, project rules, Security & Privacy
+
+| Rule (source §) | Verdict | Evidence (`path:line`) |
+|-----------------|---------|------------------------|
+| [constitution MUST / merge-checklist P-item / AGENTS.md rule / spec Security & Privacy row] | ✅ / ❌ / n/a — why | |
+
+### 3. Findings (code quality, best practice, tests)
+
+| ID | Severity | Category | `path:line` | Finding | Fix |
+|----|----------|----------|-------------|---------|-----|
+| Q1 | CRITICAL / HIGH / MEDIUM | architecture / errors / security / data / concurrency / duplication / complexity / API / tests | | | |
+
+Stack practice checked: [per framework the diff leans on — follows / deviates (source)] *(skip for S)*.
+Tests: [prove §1 behaviour, not implementation; fixtures match `probe:` files; RED + GREEN file per phase].
+
+### 4. Devil's advocate *(M: same reviewer, separate pass · L: separate sub-agent, code before decisions.md)*
+
+| # | Objection (concrete input / scenario that breaks it) | Author's answer | Outcome |
+|---|------------------------------------------------------|-----------------|---------|
+| O1 | | | accepted → BUG-NNN / rebutted (evidence) / deferred (follow-up) |
+
+≤ 5 objections. An unanswered objection blocks READY for size L.
+
+### 5. Merge checklist
+
+| # | Item | Result | Evidence |
+|---|------|--------|----------|
+| G1 | Merges cleanly | ✅ / ❌ | output:evidence/final-diff-scan.txt |
+| G2 | Build | | output:evidence/final-build.txt |
+| G3 | Full tests · `ci:` | | output:evidence/final-test.txt |
+| … | | | |
+
+### 6. Outcome
+
+- Bugs logged (CRITICAL / HIGH / blocking): [BUG-NNN, … / none] · Follow-ups (MEDIUM): [list / none]
+- Awaiting the owner: [SC-00N manual check … / deviation FR-00N ruling … / none] → a specs-only Round N+1 turns AWAITING-OWNER into READY
+- PR description: what / why / how verified (evidence + ci) / risks / rollback / strongest objections and how they were answered
diff --git a/src/templates/spec-template.md b/src/templates/spec-template.md
index 831b4e8..3381dd5 100644
--- a/src/templates/spec-template.md
+++ b/src/templates/spec-template.md
@@ -1,85 +1,57 @@
 # Feature Specification: [FEATURE NAME]
 
-**Feature Branch**: [###-feature-name]
-**Created**: [DATE]
-**Status**: Draft
-**Input**: User description: "[USER DESCRIPTION]"
+**Feature Branch**: [###-feature-name] · **Created**: [DATE] · **Status**: Draft
+**Size**: [S | M | L] — [one-line reason; `spec-kit/references/sizing.md`]
+**Epic**: [NNN-epic-name — the epic directory under `epics_dir`; delete the line when the project keeps none]
+**History**: [on | off — only to override the project default (`history:` in git-conventions, default large = L only); delete otherwise]
+**Input**: "[USER DESCRIPTION]"
 
-## User Scenarios & Testing *(mandatory)*
+> Size S (a single bugfix or a small enhancement): **a few lines** — one sentence of intent,
+> 1–3 FRs, 1–2 ACs, one Security & Privacy line, 1 SC. Delete every other section.
 
-### User Story 1 - [Brief Title] (Priority: P1)
+## User Scenarios *(mandatory)*
 
-[Describe this user journey in plain language]
+### User Story 1 - [Title] (Priority: P1)
 
-**Why this priority:** [Explain the value and why it has this priority level]
+[The journey in plain language.] **Why this priority:** [value]. **Independent test:** [how].
 
-**Independent Test:** [Describe how this can be tested independently - e.g., "Can be fully tested by [specific action] and delivers [specific value]"]
+**Acceptance Criteria** (`spec-kit/references/acceptance.md` — lowest level that proves it):
+- **AC-001** (FR-001) Given [state], When [action], Then [outcome] — Verify: unit | integration | component
+- **AC-002** (FR-002) Given [state], When [action], Then [outcome] — Verify: e2e ([why no lower level can prove it])
 
-**Acceptance Scenarios:**
-- Given [initial state], When [action], Then [expected outcome]
-- Given [initial state], When [action], Then [expected outcome]
+### User Story 2 - [Title] (Priority: P2)
 
-### User Story 2 - [Brief Title] (Priority: P2)
-
-[Describe this user journey in plain language]
-
-**Why this priority:** [Explain the value and why it has this priority level]
-
-**Independent Test:** [Describe how this can be tested independently]
-
-**Acceptance Scenarios:**
-- Given [initial state], When [action], Then [expected outcome]
-
-### User Story 3 - [Brief Title] (Priority: P3)
-
-[Describe this user journey in plain language]
-
-**Why this priority:** [Explain the value and why it has this priority level]
-
-**Independent Test:** [Describe how this can be tested independently]
-
-**Acceptance Scenarios:**
-- Given [initial state], When [action], Then [expected outcome]
-
-[Add more user stories as needed, each with an assigned priority]
+[…] **Acceptance Criteria:** - **AC-003** (FR-003) Given …, When …, Then … — Verify: [level]
 
 ## Edge Cases
 
-- What happens when [boundary condition]?
-- How does system handle [error scenario]?
+- [boundary condition] · [error scenario] — an edge case that matters is an AC too.
 
 ## Requirements *(mandatory)*
 
-### Functional Requirements
-
-- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"]
-- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
-- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
-- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
-- **FR-005**: System MUST [behavior, e.g., "log all security events"]
+- **FR-001**: System MUST [specific, testable capability]
+- **FR-002**: Users MUST be able to [key interaction]
+- **FR-003**: System MUST [behaviour] [NEEDS CLARIFICATION: …] *(max 3 markers)*
 
-Example of marking unclear requirements:
+**Key entities**: **[Entity]** — [what it represents, key attributes, relations] (domain only).
 
-- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
-- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
+## Security & Privacy *(mandatory — "None — because …" is a valid answer)*
 
-### Key Entities
+| Question | Answer |
+|----------|--------|
+| Authorization / tenant boundary — who may do this, and how is another tenant's data kept out? | |
+| Personal data — collected, displayed, exported or logged? retention? | |
+| New external surface — endpoint, file upload, integration, secret, dependency? | |
+| Input reaching a sensitive operation — validated where? | |
+| Audit / logging — what must be recorded, what must never be logged? | |
 
-- **[Entity 1]**: [What it represents, key attributes without implementation]
-- **[Entity 2]**: [What it represents, relationships to other entities]
+The pre-implement review checks this table; the final review verdicts it under §2.
 
 ## Success Criteria *(mandatory)*
 
-### Measurable Outcomes
-
-- **SC-001**: [Measurable metric, e.g., "Users can complete account creation in under 2 minutes"]
-- **SC-002**: [Measurable metric, e.g., "System handles 1000 concurrent users without degradation"]
-- **SC-003**: [User satisfaction metric, e.g., "90% of users successfully complete primary task on first attempt"]
-- **SC-004**: [Business metric, e.g., "Reduce support tickets related to [X] by 50%"]
+- **SC-001**: [measurable outcome, e.g. "a 1 000-row import completes in < 10 s"]
+- **SC-002**: [user or business metric]
 
 ## Assumptions
 
-- [Assumption about target users, e.g., "Users have stable internet connectivity"]
-- [Assumption about scope boundaries, e.g., "Mobile support is out of scope for v1"]
-- [Assumption about data/environment, e.g., "Existing authentication system will be reused"]
-- [Dependency on existing system/service, e.g., "Requires access to the existing user profile API"]
\ No newline at end of file
+- [target users, scope boundaries, environment, dependencies on existing services]
diff --git a/src/templates/tasks-template.md b/src/templates/tasks-template.md
index 5885d5c..68a202c 100644
--- a/src/templates/tasks-template.md
+++ b/src/templates/tasks-template.md
@@ -1,130 +1,33 @@
 # Tasks: [FEATURE NAME]
 
-**Input**: Design documents from /specs/[###-feature-name]/
-**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/
+**Input**: plan.md, spec.md (+ data-model.md, contracts/ when present) · **TDD**: active
+*(or `> **TDD**: Bypassed by user request`)*
 
-**Organization**: Tasks grouped by user story to enable independent implementation and testing of each story.
+**Format**: `- [ ] T### [P] [US#] [TEST] [AC-###] [SEAM] Description — exact/file/path.ext`
+- `[P]` parallel (different files, no dependency) · `[US#]` user story
+- `[TEST]` written and run RED before the phase's code (RED and GREEN files saved under `evidence/`, every size — `spec-kit/references/evidence.md`)
+- `[AC-###]` on a `[TEST]` task: the test proves that criterion; its NAME carries the id (`AC003_…` / `'AC-003 …'`); frozen after RED
+- `[SEAM]` touches an external seam — starts with a read-only probe saved as `evidence/-probe-.txt`; the fixture matches its shape
 
-**Format**: `[ID] [P?] [Story] Description`
+> Size S: one flat list, tests first. M / L: phases below; every FR and AC maps to a task.
 
-- **[P]**: Can run in parallel (different files, no dependencies)
-- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
-- Include exact file paths in descriptions
+## Phase 1: Setup / Foundational
 
-**Path Conventions**
+- [ ] T001 [SEAM] Probe + fixture for [seam] — tests/fixtures/[seam].json
+- [ ] T002 [P] [TEST] [AC-001] [behaviour] — tests/[area]/[file].spec.ts
 
-- Single project: `src/`, `tests/` at repository root
-- Web app: `backend/src/`, `frontend/src/`
-- Mobile: `api/src/`, `ios/src/` or `android/src/`
-- Paths shown below assume single project — adjust based on plan.md structure
+## Phase 2: User Story 1 — [Title] (P1)
 
-## Phase 1: Setup (Shared Infrastructure)
+**Goal**: [what this story delivers] · **Independent test**: [how]
 
-**Purpose**: Project initialization and basic structure
+- [ ] T003 [US1] [TEST] [AC-002] … — tests/…
+- [ ] T004 [US1] Implement … — src/…
 
-- [ ] T001 Create project structure per implementation plan
-- [ ] T002 Initialize [language] project with [framework] dependencies
-- [ ] T003 [P] Configure linting and formatting tools
+## Phase N: Polish
 
----
-
-## Phase 2: Foundational (Blocking Prerequisites)
-
-**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
-
-**CRITICAL**: No user story work can begin until this phase is complete
-
-- [ ] T004 Setup database schema and migrations framework
-- [ ] T005 [P] Implement authentication/authorization framework
-- [ ] T006 [P] Setup API routing and middleware structure
-- [ ] T007 Create base models/entities that all stories depend on
-- [ ] T008 Configure error handling and logging infrastructure
-- [ ] T009 Setup environment configuration management
-
-**Checkpoint**: Foundation ready — user story implementation can now begin in parallel
-
----
-
-## Phase 3: User Story 1 - [Title] (Priority: P1) :star: MVP
-
-**Goal**: [Brief description of what this story delivers]
-
-**Independent Test**: [How to verify this story works on its own]
-
-### Implementation for User Story 1
-
-- [ ] T010 [P] [US1] Create [Entity1] model in src/models/[entity1].py
-- [ ] T011 [P] [US1] Create [Entity2] model in src/models/[entity2].py
-- [ ] T012 [US1] Implement [Service] in src/services/[service].py (depends on T010, T011)
-- [ ] T013 [US1] Implement [endpoint/feature] in src/[location]/[file].py
-- [ ] T014 [US1] Add validation and error handling
-- [ ] T015 [US1] Add logging for user story 1 operations
-
-**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
-
----
-
-## Phase 4: User Story 2 - [Title] (Priority: P2)
-
-**Goal**: [Brief description of what this story delivers]
-
-**Independent Test**: [How to verify this story works on its own]
-
-### Implementation for User Story 2
-
-- [ ] T016 [P] [US2] Create [Entity] model in src/models/[entity].py
-- [ ] T017 [US2] Implement [Service] in src/services/[service].py
-- [ ] T018 [US2] Implement [endpoint/feature] in src/[location]/[file].py
-- [ ] T019 [US2] Integrate with User Story 1 components (if needed)
-
-**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
-
----
-
-## Phase 5: User Story 3 - [Title] (Priority: P3)
-
-**Goal**: [Brief description of what this story delivers]
-
-**Independent Test**: [How to verify this story works on its own]
-
-### Implementation for User Story 3
-
-- [ ] T020 [P] [US3] Create [Entity] model in src/models/[entity].py
-- [ ] T021 [US3] Implement [Service] in src/services/[service].py
-- [ ] T022 [US3] Implement [endpoint/feature] in src/[location]/[file].py
-
-**Checkpoint**: All user stories should now be independently functional
-
----
-
-[Add more user story phases as needed, following the same pattern]
-
-## Phase N: Polish & Cross-Cutting Concerns
-
-**Purpose**: Improvements that affect multiple user stories
-
-- [ ] T0XX [P] Documentation updates in docs/
-- [ ] T0XX Code cleanup and refactoring
-- [ ] T0XX Performance optimization across all stories
-- [ ] T0XX [P] Additional unit tests in tests/unit/
-- [ ] T0XX Security hardening
-- [ ] T0XX Run quickstart.md validation
+- [ ] T0XX Docs / AGENTS.md lines the change makes wrong — docs/…
 
 ## Dependencies & Execution Order
 
-### Phase Dependencies
-
-- **Setup (Phase 1)**: No dependencies — can start immediately
-- **Foundational (Phase 2)**: Depends on Setup completion — BLOCKS all user stories
-- **User Stories (Phase 3+)**: All depend on Foundational phase completion
-- **Polish (Final Phase)**: Depends on all desired user stories being complete
-
-User stories can proceed in parallel once Foundational phase completes (if team capacity allows).
-
-### Parallel Opportunities
-
-All Setup tasks marked [P] can run in parallel
-All Foundational tasks marked [P] can run in parallel (within Phase 2)
-Once Foundational phase completes, all user stories can start in parallel
-All tasks for a user story marked [P] can run in parallel
-Different user stories can be worked on in parallel by different team members
\ No newline at end of file
+- Phase 1 blocks every story; stories run in parallel after it; Polish last.
+- [other ordering constraints]
diff --git a/user-guide.md b/user-guide.md
index eb0f4bc..60bfb34 100644
--- a/user-guide.md
+++ b/user-guide.md
@@ -6,11 +6,6 @@ task breakdown, TDD implementation, testing, and a mandatory close phase.
 Three development modes span the full feature lifecycle: forward development
 (specify), bugfix loop, and reopen for closed features.
 
-Git conventions (branch naming, commit messages, merge behaviour) are
-defined in `specs/git-conventions.md`. Copy the template from
-`spec-kit/templates/git-conventions-template.md` and customise per
-project.
-
 This guide covers installation, the core workflow, the reopen flow for closed features, and
 day-to-day usage.
 
@@ -20,7 +15,7 @@ day-to-day usage.
 
 1.  [What is Spec-Kit?](#what-is-spec-kit)
 2.  [Quick Start: Your First Feature](#quick-start-your-first-feature)
-3.  [Four Development Modes](#four-development-modes)
+3.  [Three Development Modes](#three-development-modes)
 4.  [Constitution Decision Tree](#constitution-decision-tree)
     - [Level 1: Purpose (9 options)](#level-1-purpose-9-options)
     - [Level 2: Architecture (25 options)](#level-2-architecture-25-options-across-9-purposes)
@@ -34,8 +29,9 @@ day-to-day usage.
 7.  [Branch Strategy](#branch-strategy)
 8.  [Git Commit Conventions](#git-commit-conventions)
 9.  [Spec Health Score](#spec-health-score)
-10. [Troubleshooting](#troubleshooting)
-11. [Reference Tables](#reference-tables)
+10. [MCP Server](#mcp-server)
+11. [Troubleshooting](#troubleshooting)
+12. [Reference Tables](#reference-tables)
 
 ---
 
@@ -64,13 +60,15 @@ mode).
 - Without close, features accumulate half-finished
 
 **What tools does it add?**
-- 13 spec-kit skills in `~/.hermes/skills/` — respond to `spec-kit` prefix, `speckit` prefix,
+- 11 spec-kit skills in `~/.hermes/skills/` — respond to `spec-kit` prefix, `speckit` prefix,
   and natural language phrases
   (e.g. `"speckit plan 001-user-auth"`, `"spec-kit plan 001-user-auth"`, or
   `"plan the implementation for 001-user-auth"` all trigger the same skill)
 - Templates in `~/.hermes/skills/spec-kit/templates/`
-- Reference files in `~/.hermes/skills/spec-kit/references/` (preflight checks, auto-commit patterns, history tracking)
+- Reference files in `~/.hermes/skills/spec-kit/references/` (preflight, commits, history tracking, sizing, evidence, acceptance)
 - A `specs/` directory in your project for feature artifacts
+- An optional MCP server (`mcp_spec_kit_*` tools) for deterministic state management
+  — auto-configured by install.sh, activates with `/reload-mcp`
 
 ---
 
@@ -638,7 +636,7 @@ say "bugfix [feature]" to start the fix loop.
 **Bug format**: Each bug gets an ID (BUG-NNN), severity
 (critical/major/minor/trivial), area, steps to reproduce, expected vs actual
 result, Requires Clarification flag, and status
-(open/in-progress/resolved/verified).
+(open/in-progress/claimed/verified/superseded — `claimed` is the agent's word, `verified` needs a user, CI or other-agent oracle; see Evidence of Done).
 
 **Plan Ref enforcement**: During bugfix, each open bug must have a Plan Ref
 linking to the plan section that addresses it — no Plan Ref, no implementation.
@@ -647,23 +645,51 @@ linking to the plan section that addresses it — no Plan Ref, no implementation
 supersedes specific original (buggy) tasks, append `[T###-fix]` to trace the
 relationship (e.g., `BF-001 [BUGFIX] [T051-fix] Fix validate_cluster_shape`).
 
-### Phase 5.5: Review — Post-Implement Gate (Optional)
-**Skill**: `spec-kit-review` · **Trigger**: "Review [feature]" after
-code + tests
-
-Same skill as pre-implement, auto-detects mode. Three modes total:
-- **Pre-implement** (Phase 3.5): Cross-artifact consistency check before coding
-- **Post-implement** (Phase 5.5): Code quality, spec fulfillment, test quality
-- **Closed-review**: Read-only audit of a closed feature — does not update history.md.
-  If issues found, offers to add refactoring tasks and reopen the feature.
-
-Post-implement checks:
-- Spec fulfillment (does code satisfy every FR-###?)
-- Constitution alignment
-- Architecture compliance with plan
-- Code quality (error handling, duplication, security)
-- Test quality
-- Documentation completeness
+### Phase 5.5: Final Review — Merge Gate (Mandatory)
+**Skill**: `spec-kit-review` · **Trigger**: "Final review [feature]", "Is [feature] ready
+to merge", or "Review [feature]" once every task is done and no bug is open ·
+**Artifact**: `review-final.md` (one round per run)
+
+Same skill as pre-implement, auto-detects mode (pre-implement / final / closed-review).
+The final review answers four questions and ends with a verdict:
+
+1. **Does the code do what the spec says?** Every FR, success criterion, acceptance
+   scenario and edge case → the code (`path:line`) and the test that proves it; contracts
+   and data model vs code; unplanned changes.
+2. **Does it obey the constitution and project rules?** Every applicable MUST in
+   `specs/constitution.md`, every rule in `specs/merge-checklist.md` and AGENTS.md — each
+   verdicted with evidence. This is where the constitution is enforced.
+3. **Is it good code?** Architecture, error handling, security, data integrity,
+   concurrency, duplication, complexity, API surface, current best practice; test quality.
+4. **Can it merge?** `diff_scan` (conflicts, secrets, forbidden files, focused tests,
+   TODOs) and the checklist commands (build, full tests, lint, format), outputs saved under
+   `evidence/final-*`.
+
+**Verdict**: `READY`, `READY-WITH-FOLLOWUPS` (only MEDIUM findings) or `NOT READY` (any
+CRITICAL/HIGH or failing blocking check → logged as bugs → bugfix loop → new round). The
+round records the reviewed commit; a later code commit makes it stale. The close refuses
+without a fresh READY round. Run it by the other agent, or a fresh-context sub-agent.
+
+### Acceptance criteria and the acceptance loop
+Every scenario in spec.md is an acceptance criterion with an id and a verify level:
+`**AC-003** (FR-002) Given … When … Then … — Verify: unit`. The level is the lowest that can
+prove it — unit, integration, component, e2e (with a reason), command, probe, manual (with a
+reason). The plan maps each AC to a harness and test file; its tests are ordinary `[TEST]`
+tasks tagged `[AC-003]`, written RED in the implement phase that delivers the behaviour and
+then **frozen** (checksummed) so the loop cannot pass by weakening them.
+
+After the last implement phase, `accept [feature]` runs automatically: the full unit,
+integration and component suites (this is also the regression run), this feature's own e2e
+specs only if the stack is up (otherwise deferred to the final review — the full e2e suite
+never runs in the loop), and any command/probe checks. Results (JUnit XML / TRX) map back to
+the ACs by the id in the test name. Failures become bugs, the bugfix chain runs, and the
+acceptance round repeats — until every automated AC passes, or it stops and asks after 5
+rounds, no progress, a needed spec or frozen-test change, or a run that cannot execute.
+
+### Size tiers (S / M / L)
+Specify always asks for the tier, with its recommendation first. S trims the templates and
+chains specify → plan → tasks into one commit; M is the default; L adds the full artifact
+set and a required pre-implement review. See `references/sizing.md`.
 
 ### Phase 6: Close/Summarize — Mandatory
 **Skill**: `spec-kit-summarize` · **Trigger**: "Close [feature]" or
@@ -681,6 +707,15 @@ Two modes:
 - **Lightweight close** ("close [feature]"): Quick health score, artifact
   state table, key decisions.
 
+Both modes, after the final-review gate:
+- **ADRs**: decisions harvested from decisions.md, plan rounds, research and reviews are
+  tested against the ADR bar (cross-feature, hard to reverse, real alternatives, changes an
+  existing ADR); passing ones become new / superseding / amending project ADRs (approved one
+  by one) and the ADR index is updated. The close's *Architecture Decisions* table lists
+  every candidate.
+- **AGENTS.md**: statements the change made wrong (commands, layout, boundaries, versions,
+  conventions, debt, ADR list) get targeted patches, approved one by one.
+
 **Output rule**: Length proportional to actual git changes, not spec size.
 A one-line bugfix gets one line; a multi-file feature gets thorough
 per-file coverage.
@@ -789,6 +824,87 @@ health score is compared against the original. Any requirements that
 changed status (e.g., from ✅ Resolved to ❌ Not Done) are flagged for
 user resolution.
 
+## MCP Server (Optional)
+
+An MCP server acts as a **derive-and-enforce** service. It keeps no state: on every call it
+derives the current phase from the files under `specs//` and validates against them.
+It exists for the things an agent does badly — allocating the next id, linting `bugs.md` and
+`tasks.md`, stamping real times, guarding that `history.md` was written before the commit, freezing acceptance tests — and
+to hand back a ten-line **phase card** that survives context compaction.
+
+### How it works
+
+```
+Hermes / Claude Code ─→ mcp_spec_kit_* tools ─→ MCP Server (server.py)
+                                                        ↓ reads only
+                                              specs//*.md
+```
+
+The server uses the official [mcp Python SDK](https://pypi.org/project/mcp/) (`FastMCP`) for stdio transport. Nothing is persisted; a legacy `specs/.spec-kit/state.json` is ignored and should be deleted and gitignored.
+
+### Tools provided
+
+| Tool | Purpose |
+|------|---------|
+| `mcp_spec_kit_init_feature` | Create `specs//` with a history.md header |
+| `mcp_spec_kit_get_feature_state` | Derived phase, artifacts, task/bug counts, phase card |
+| `mcp_spec_kit_get_next_actions` | Available actions + the phase card |
+| `mcp_spec_kit_advance_phase` | Validate a transition against the files (writes nothing) |
+| `mcp_spec_kit_project_status` | Constitution present?, feature count, legacy state file? |
+| `mcp_spec_kit_project_set_constitution` | Confirm `specs/constitution.md` exists |
+| `mcp_spec_kit_list_features` | Every feature's derived state |
+| `mcp_spec_kit_reopen_feature` | Check the feature is closed; return the branch hint |
+| `mcp_spec_kit_close_feature` | Validate the close (no open bugs, verified bugs have Verified-by) |
+| `mcp_spec_kit_update_artifact` | Confirm an artifact is on disk |
+| `mcp_spec_kit_auto_detect_features` | Derived state of all features |
+| `mcp_spec_kit_next_id` | Next BUG / T / BF id |
+| `mcp_spec_kit_lint_artifacts` | Schema lint of bugs.md, tasks.md, history.md, ACs, rounds |
+| `mcp_spec_kit_history_guard` | Fresh history entry since the last commit? |
+| `mcp_spec_kit_append_history` | Append a fixed-field, time-stamped, word-capped history entry |
+| `mcp_spec_kit_timestamp` | Real UTC time |
+
+### Benefits
+
+- **No drift**: nothing to keep in sync — the files are the state
+- **Enforced transitions**: `advance_phase` and `close_feature` reject moves the files do not support
+- **Mechanical hygiene**: ids, statuses, timestamps, probes, RED files and the history guard are checked by code, not by prose
+- **Backward compatible**: without the server every skill falls back to filesystem detection, `date -u` and manual id counting
+
+Bug tracking is deliberately NOT in the MCP server: `bugs.md` is the single
+source of truth and is written directly by `spec-kit-test`. The server only reads it.
+
+### Installation
+
+The install script (`./scripts/install.sh`) automatically:
+
+1. Copies `server.py` to `~/.hermes/skills/spec-kit/mcp-server/`
+2. Creates a Python venv at `~/.hermes-venv` if the `mcp` SDK is not found
+3. Runs `hermes mcp add spec-kit` to register the server in `config.yaml`
+4. Prints instructions to activate with `/reload-mcp`
+
+If `hermes mcp add` times out during connection verification, add the config
+manually to `~/.hermes/config.yaml`:
+
+```yaml
+mcp_servers:
+  spec-kit:
+    command: "/home/krzys/.hermes-venv/bin/python3"
+    args: ["/home/krzys/.hermes/skills/spec-kit/mcp-server/server.py"]
+```
+
+Then run `/reload-mcp` in Hermes and verify with `/toolsets` — the
+`mcp_spec_kit_*` tools should appear.
+
+### Skill integration
+
+When the MCP server is available (its tools exist in the Hermes toolset), skills
+defer to it for state queries and transitions. When unavailable, the same skills
+use the filesystem-based detection and routing from the table above.
+
+`spec-kit-test` logs bugs and stops in both modes; with MCP it allocates the
+BUG id with `mcp_spec_kit_next_id` and lints before committing. The user
+starts the fix loop with "bugfix [feature]".
+
 ---
 
 ## Troubleshooting
@@ -918,15 +1034,20 @@ Installed to `~/.hermes/skills/spec-kit/templates/`:
 | bugs-template.md | Phase 5 | Bug tracking |
 | implementation-summary-template.md | Phase 6 | Full summary |
 | close-template.md | Phase 6 | Lightweight close |
-| comparison-template.md | Compare | Variant comparison matrix |
-| history-template.md | Phase transitions | Append-only log entries |
+| history-template.md | Phase transitions (size L by default — `history: large`) | Append-only log entries |
+| epic-template.md · epic-plan-template.md · epic-features-template.md · epic-review-template.md · epics-index-template.md | `spec-kit epic` (opt-in `epics_dir`) | E1 specify (goal, EACs, rules) · E2 plan (target architecture, ED decisions, sequencing) · E3 breakdown (ordered features) · E3.5 / E6 reviews with devil's advocate |
+| design-doc-template.md | `spec-kit design` (opt-in `design_dir`) | Living module design: components, flow, seams, invariants, security, debt |
+| change-record-template.md | Close | The auditor's one page: ticket, risk tier, security impact, approvals, verification, rollback, timeline |
 | git-conventions-template.md | Project setup | Git branch/commit conventions |
 | gitignore-template.md | Project setup | .gitignore starter |
 | AGENTS-template.md | Project setup | Starting AGENTS.md |
-| soul-template.md | Hermes setup | Neutral persona |
 
 ### Artifact Detection (Phase Detection)
 
+When the MCP server is configured, `mcp_spec_kit_get_feature_state` derives the
+current phase, artifact status and bug counts from the files below — the same
+table, applied by code. Use it (or the table) before any write.
+
 | Artifacts present | Current phase |
 |-------------------|---------------|
 | `specs/constitution.md` only | Ready to Specify |
@@ -942,7 +1063,7 @@ Installed to `~/.hermes/skills/spec-kit/templates/`:
 | `implementation-summary.md` exists | Summarized — complete |
 | `variants/` directory with ≥2 entries | Exploring |
 | `comparison.md` exists | Compared — decision made |
-| `history.md` last entry | Current phase (fastest lookup) |
+| `history.md` last entry | Current phase (fastest lookup) — or the MCP phase card |
 
 ### Quick CLI Reference
 
@@ -964,9 +1085,14 @@ hermes -w -s spec-kit-workflow
 
 # Check installed skills
 hermes skills list | grep spec-kit
+
+# MCP server commands (if installed)
+/reload-mcp                    # Activate MCP server after install/config change
+hermes mcp status              # Check MCP server status
+mcp_spec_kit_list_features     # List all registered features via MCP
 ```
 
-|### Workflow Diagram
+### Workflow Diagram
 
 ```text
                                             ┌── Explore ───────────────┐