Skip to content

anvil v0 — Build Spec

Historical design record (2026-05-24). This document preserves Anvil's original v0 implementation target for provenance; it is not a current operational reference. Commands, defaults, hook counts, and lifecycle rules below may be superseded. Use the current architecture, CLI reference, MCP reference, hooks reference, and migration guide when operating v0.6.5 or later.

Context

anvil is the third pillar of the Fakoli plugin ecosystem (fakoli-flow = how work moves, fakoli-crew = who does the work, anvil = what is true). It's a Claude Code plugin that provides a local-first, backend-neutral, LLM-optimized project state layer that humans and multiple coding agents can coordinate around. It turns rough ideas and PRDs into reviewed, lockable, agent-ready work packets.

The product is informed by three design documents: - agentic_project_state_design_brief.md — the original vision (PRD authoring, task decomposition, claims/locks, work packets, evidence-based completion, MCP interface). - competitive_gap_analysis_agentic_project_state.md — competitive positioning, especially against CCPM and against issue-tracker-as-state patterns. - fakoli_plugin_primer_for_agentic_workflows.md — the operating model: plugin-first, with skills encoding workflow choreography, hooks enforcing rules, CLI handling pure state ops, MCP as the external surface.

Two distinct wedges define the product:

Against CCPM and issue-tracker-as-state — the "5 must-do-better" list: 1. Richer canonical state than issue text (Pydantic models + SQLite vs. issue body markdown). 2. Explicit claim/lock/lease model (not implied by assignment/labels). 3. Better LLM work packets (compact, task-specific, with constraints and non-goals). 4. Six-dimension scoring (complexity, parallelizability, context load, blast radius, review risk, agent suitability). 5. Runtime-neutral integration (Claude Code, Codex, Cursor, OpenHands, Copilot, local agents — via CLI + MCP).

Against the current Fakoli markdown-status-file model — the operating discipline: - Canonical state moves from scattered markdown into a durable SQLite database with append-only event log. - Claims are no longer conventions in agent-*-status.md files; they are enforced rows with leases and heartbeats. - File ownership becomes a real check, not a status-file comment. - Evidence is required and validated, not just claimed.

The intended outcome of v0 is a usable open-source plugin that demonstrates both wedges and integrates cleanly with fakoli-flow and fakoli-crew.

Goals

  • Plugin-first packaging following the primer's "maximum use of plugins" reference architecture.
  • Local-first by default; canonical state in SQLite under .anvil/, never in an issue tracker.
  • Skills for workflow choreography: start-prd, prd, plan, claim, execute, verify, finish, state-ops.
  • CLI binary in bin/anvil for pure state operations — called by skills, hooks, agents, humans, and external tools.
  • MCP server (FastMCP, stdio) wired via .mcp.json, exposing 13 agent-facing tools.
  • Hooks that enforce claim discipline, record file changes, and capture evidence — rules the model would otherwise forget.
  • Plugin-owned agents for state-specific roles (planner, critic, sentinel, state-keeper) that defer to fakoli-crew when it's installed.
  • Bidirectional GitHub Issues sync as an opt-in projection of canonical state.
  • Auto-generate agent/<task>-<slug> branches (optional worktrees) on claim; recorded on the Claim.
  • Soft review gate: tasks generate freely from any PRD draft; claim_task refuses while PRD is draft.
  • Hybrid LLM model: deterministic template-based PRD parser always available; LLM helpers (Anthropic provider in v0) augment.
  • Replayability: full event log in append-only JSONL; replaying from empty reconstructs canonical SQLite state exactly.
  • Integration: fakoli-flow skills read/write anvil as workflow proceeds; fakoli-crew agents consume work packets and submit evidence.

Non-Goals (v0)

  • Hosted SaaS / web dashboard.
  • Real-time collaborative editing.
  • Multi-backend sync targets beyond GitHub Issues (GitLab, Jira, Linear deferred to v0.2).
  • Multi-provider LLM abstraction beyond Anthropic (provider interface present; only one impl ships).
  • Webhook-based GitHub sync (polling-only in v0).
  • Daemon / long-running service (MCP server is the only long-running process and only per-agent-session).
  • Performance benchmarks / regression gates.
  • Bundling a single static binary (Python source ships in bin/, uv resolves deps on first run).

Architecture

Plugin layout

The plugin lives at ~/ai-code/claude-env/fakoli-plugins/plugins/anvil/:

anvil/
├── .claude-plugin/
│   └── plugin.json                # name, version, description, author, repo, license, keywords
├── README.md                       # positions against CCPM, links docs, install instructions
├── CHANGELOG.md
├── LICENSE
├── .mcp.json                       # wires bin/anvil-mcp as the MCP server
├── settings.json                   # plugin defaults (e.g. default lease duration, llm provider)
├── docs/
│   ├── prd-template.md             # the structured PRD template users author against
│   ├── architecture.md
│   ├── mcp.md
│   ├── hooks.md
│   ├── github-sync.md
│   └── integration-flow-crew.md    # how anvil plugs into fakoli-flow + fakoli-crew
├── skills/                         # workflow choreography
│   ├── start-prd/SKILL.md          # rough idea → PRD (with optional fakoli-flow:brainstorm bridge)
│   ├── prd/SKILL.md                # author/review/approve PRD
│   ├── plan/SKILL.md               # PRD → features → tasks → scores → expand → ready
│   ├── claim/SKILL.md              # agent-facing claim flow (called from execute)
│   ├── execute/SKILL.md            # claim → packet → work → submit (or hand to fakoli-flow:execute)
│   ├── verify/SKILL.md             # sentinel verification on evidence
│   ├── finish/SKILL.md             # apply + ship decision (merge/PR/keep/discard)
│   └── state-ops/SKILL.md          # general inspection: list, show, next, status, conflicts, sync
├── agents/                         # plugin-owned specialists; defer to fakoli-crew when installed
│   ├── planner.md                  # PRD → features/tasks (uses LLM if configured)
│   ├── critic.md                   # reviews work packets, plans, and code (fallback when fakoli-crew:critic absent)
│   ├── sentinel.md                 # validates evidence (fallback when fakoli-crew:sentinel absent)
│   └── state-keeper.md             # state reconciliation, sync, audit
├── hooks/
│   ├── hooks.json                  # event mappings
│   ├── detect-state.sh             # SessionStart: detect plugins + project state
│   ├── check-claim.sh              # PreToolUse on Edit/Write: warn if editing files outside claimed scope
│   ├── record-file-change.sh       # PostToolUse on Edit/Write: append to events.jsonl
│   └── capture-evidence.sh         # PostToolUse on Bash: capture test output for active claims
├── monitors/                       # optional — defer to v0.2
└── bin/
    ├── anvil                # bash wrapper → uv run python -m anvil.cli
    ├── anvil-mcp            # bash wrapper → uv run python -m anvil.mcp_server
    ├── pyproject.toml              # uv-managed Python project (Hatchling)
    ├── uv.lock                     # locked dependencies
    └── src/anvil/           # Python source
        ├── __init__.py
        ├── cli.py                  # Typer app — ~15 state-op commands
        ├── mcp_server.py           # FastMCP server — 13 agent-facing tools
        ├── config.py
        ├── clock.py                # Clock protocol + SystemClock + FrozenClock (test)
        ├── state/                  # backend, sqlite, schema, models, transitions
        ├── planning/               # template, llm, scoring, inference
        ├── context/                # packets
        ├── review/                 # gates
        ├── claims/                 # manager, stale
        ├── git_ops/                # branch, worktree
        └── sync/                   # github, client, mapping

(Full file tree is in the approved plan at ~/.claude/plans/i-need-evaulate-the-ticklish-cherny.md — this spec is the canonical reference, that plan was the brainstorm output.)

Per-project state directory

anvil init creates this inside the user's project (NOT inside the plugin):

<user-project>/.anvil/
├── config.yaml                # project-level config
├── state.db                   # SQLite — canonical state
├── events.jsonl               # append-only audit/event log
├── prd.md                     # the PRD source
├── packets/                   # generated work packets
└── snapshots/                 # opt-in periodic snapshots (created on first `anvil snapshot`)

Component responsibilities

Layer What it does
Plugin manifest Discoverability, versioning, metadata
Skills Workflow choreography — one-question-at-a-time, propose approaches, gate transitions
Agents Specialized workers; defer to fakoli-crew when installed
Hooks Enforcement the model would forget
MCP External capability surface for any agent runtime
CLI Pure state operations — CRUD + computation, no choreography
State engine Backend protocol; SQLite + JSONL impl in v0
Planning engine Template-first PRD parser; LLM helpers always optional
Context engine Renders work packets (markdown + JSON)
Review engine Pure functions enforcing transition gates
Claims manager Atomic SQLite transactions; stale detection on every op
Git ops Auto-create agent/<task>-<slug> branch on claim
Sync engine Bidirectional GitHub Issues sync (polling only)

CLI command set

anvil init                  # scaffold .anvil/ in cwd
anvil prd parse             # re-parse prd.md into state
anvil prd review --approve  # transition PRD draft → reviewed → approved
anvil plan                  # generate features + tasks from parsed requirements
anvil score [TASK_ID]       # populate six-dim scores; --use-llm to augment
anvil expand TASK_ID        # break into subtasks
anvil review tasks          # promote drafted → reviewed → ready
anvil list [--status X]
anvil show TASK_ID
anvil next                  # pick highest-priority claimable task
anvil claim TASK_ID [--worktree]
anvil release TASK_ID|--force
anvil renew TASK_ID
anvil packet TASK_ID [--format md|json]
anvil submit TASK_ID --commands ... --files-changed ...
anvil apply TASK_ID         # human review → accepted → done
anvil status                # active claims, blockers, sync state
anvil conflicts             # show conflict groups + overlapping claims
anvil sync [github] [--watch] [--fix]
anvil replay --from-events events.jsonl

start-prd, full review, verify, compact from the brief move into skills; the CLI keeps only the underlying state ops.

Distribution: contribute via PR to the fakoli-plugins repo; users install via /plugin install anvil from the fakoli marketplace. Python source ships in bin/src/; uv resolves deps on first invocation. Wrapper scripts shell out to uv run.

Data Model

Pydantic v2 models in bin/src/anvil/state/models.py are the single source of truth. SQLite DDL is generated from them at startup (or via anvil migrate).

ID formats: T001, F001, R001, T001.1 (subtask), C001, D001, E000001, V001, EV001.

Entities (each = Pydantic model + SQLite table): Project, PRD, Requirement, Feature, Task, Score (embedded on Task), Verification (embedded on Task), Claim, Evidence, Decision, Review, Event, SyncMapping, ConflictGroup.

Task lifecycle:

proposed → drafted → reviewed → ready → claimed → in_progress
                                                   ├─→ blocked → in_progress
                                                   └─→ needs_review → accepted → done
                                  reject path:    needs_review → rejected → drafted
                                  stale claim:    claim.stale event returns task to ready
                                                  (claim goes stale; task status does NOT)

Scoring scale (1-5 per dimension): - complexity, parallelizability, context_load, blast_radius, review_risk, agent_suitability. - complexity ≥ 4 triggers expand recommendation. - agent_suitability drives orchestration routing.

Work packets are derived views, regenerated from canonical state. Two forms: markdown (in packets/T001.md) and JSON (from MCP generate_work_packet).

Data Flows (summary)

  1. PRD authoring/anvil:start-prd skill drives dialogue (can bridge to fakoli-flow:brainstorm), writes prd.mdanvil prd parse/anvil:prd review gates draft → reviewed → approved.
  2. Planning/anvil:plan skill: optionally dispatches planner agent (or fakoli-crew:guido); anvil plan commits skeleton; score [--use-llm] populates dimensions; expand for complexity ≥ 4; review tasks promotes drafted → reviewed → ready.
  3. Claim and execute/anvil:execute (or fakoli-flow:execute): nextclaim T012 (gate: PRD reviewed) → auto-create branch/worktree → packet T012 → agent works → heartbeat every 5 min via renew T012submit T012 (auto-releases claim) → /anvil:finish drives apply + ship decision.
  4. Conflict detection — pre-claim warns (not blocks) on expected_files overlap with active claims; --force to override; logged. check-claim.sh hook ALSO warns on Edit/Write outside claimed scope.
  5. Stale claim recovery — on every CLI/MCP op, scan claims with expired leases → mark stale, return tasks to pool. release --force for manual override.
  6. GitHub sync (bidirectional)sync github: create issues for new tasks; reconcile changes; conflict resolution per configured strategy. Polling only.
  7. Reconciliation (sync without target) — cross-check SQLite with file system + git; report orphans; --fix with prompt.

Hooks (the enforcement layer)

hooks/hooks.json wires four hooks:

Event Script What it enforces
SessionStart detect-state.sh Prints one-line summary: language, fakoli-crew/fakoli-flow availability, active claims, ready tasks, blockers
PreToolUse (Edit, Write, NotebookEdit) check-claim.sh Warns if file modified is outside expected_files of any active claim; non-blocking
PostToolUse (Edit, Write, NotebookEdit) record-file-change.sh Appends file_changed event to events.jsonl
PostToolUse (Bash) capture-evidence.sh Captures stdout/stderr/exit code of registered verification commands into the claim's pending evidence buffer

All hooks shell out to ${CLAUDE_PLUGIN_ROOT}/bin/anvil. None block; they warn, log, capture. Follow fakoli-flow/hooks/ patterns (no piped grep, no set -e, proper ${CLAUDE_PLUGIN_ROOT} usage).

MCP Server

.mcp.json wires bin/anvil-mcp as a stdio MCP server. Thirteen agent-facing tools:

get_project_summary           list_tasks                  get_task
get_next_task                 claim_task                  release_task
renew_claim                   generate_work_packet        submit_progress
submit_completion_evidence    check_conflicts             get_dependency_graph
update_task_status

Errors return structured {code, message, target_id, payload}.

Error Handling

Hard rules: - No silent fallback on parse errors. Surface; leave last-good state intact. - No automatic destructive recovery. --fix, --force, force-release require explicit flags. - Events log before mutation. Aborted mutations become error.transaction_aborted; replay ignores aborted events.

Categories: transition errors (Review engine), concurrency (SQLite BEGIN IMMEDIATE + WAL), schema validation (Pydantic), git failures, GitHub sync, LLM provider failures, recovery via sync --fix, hook failures (logged, non-blocking).

--dry-run and --verbose global flags on every mutating CLI command. All errors logged to events.jsonl as error.* actions.

Testing

Layers: unit (<100ms total), component (per-engine with real temp SQLite, <2s/test), CLI integration (Typer CliRunner, <5s/test), MCP integration (FastMCP test client, <5s/test), end-to-end (multi-command scenarios, <15s/scenario), hook smoke (bats-style real shell). Full suite under 90s locally.

Hard rules: - Real SQLite in every test that touches state. - No time.sleep for lease/heartbeat tests. Clock protocol with FrozenClock. - LLM is mocked. LLMProvider protocol with RecordedLLMProvider. - GitHub sync via responses HTTP mocks. Nightly @pytest.mark.live_github against a real test repo. - Git ops use a real local git repo (tmp git init per test). - Hooks tested as real shell scripts.

Coverage targets: 85% overall; 95% on state/, 95% on claims/, 90% on review/, 80% on CLI.

CI matches fakoli-plugins conventions. Steps for anvil: uv sync → ruff → mypy → pytest with coverage gate → hook smoke → scripts/generate-index.sh --check → marketplace.json regen check. Nightly cron for live_github.

Integration with fakoli-flow and fakoli-crew

fakoli-flow: - flow:execute detects anvil; when both installed, dispatches by reading anvil next and calling anvil claim before each wave. Status files replaced by anvil submit. - flow:verify calls anvil status and dispatches sentinel only on tasks with submitted evidence. - flow:finish calls anvil apply per accepted task before merge/PR.

fakoli-crew: - All crew agents gain access to anvil-mcp MCP tools when anvil is installed. - Plugin-owned agents/critic.md and agents/sentinel.md defer to fakoli-crew when its agents are detected.

When anvil is absent, fakoli-flow + fakoli-crew continue to work via existing markdown-status conventions. Integration is opt-in.

Critical Files

  • .claude-plugin/plugin.json — plugin manifest; must validate against marketplace schema. Build first (smith).
  • bin/src/anvil/state/models.py — Pydantic models; all other modules import from here. Second.
  • bin/src/anvil/state/sqlite.py — Backend impl. Must be correct before any engine work.
  • bin/src/anvil/state/transitions.py — Pure transition table. Drives Review engine.
  • bin/src/anvil/claims/manager.py — Concurrency-critical; test extensively with real SQLite.
  • bin/src/anvil/planning/template.py — Deterministic PRD parser; defines user-facing template contract.
  • bin/anvil and bin/anvil-mcp — bash wrappers that uv run Python modules.
  • skills/state-ops/SKILL.md — first skill; validates the skill structure.
  • hooks/detect-state.sh — SessionStart hook; validates hook plumbing.
  • docs/prd-template.md — user-facing contract for what the template parser accepts.

External utilities to reuse: - uv for env + tool install + dependency management. - Typer for CLI. - Pydantic v2 for models + validation. - FastMCP for the MCP server. - responses library for HTTP-mocked GitHub tests. - gh CLI for GitHub sync auth. - fakoli-plugins infrastructure: scripts/generate-index.sh, update-index.yml GitHub Action, marketplace.json conventions.

Verification

End-to-end smoke (first public demo per primer):

/plugin install anvil
anvil init --name "Test Project"
$EDITOR .anvil/prd.md
anvil prd parse && anvil prd review --approve
anvil plan && anvil score && anvil expand T001 && anvil review tasks
anvil next
anvil claim T001                  # auto-creates branch agent/t001-<slug>
anvil packet T001
anvil renew T001
anvil submit T001 --commands "pytest" --output-file out.log --files-changed src/foo.py
anvil apply T001

# Integration
/flow:execute "docs/plans/test-plan.md"

# GitHub sync
gh auth status && anvil sync github

# Reconciliation
anvil sync --fix --yes

Test suite + plugin validation:

uv run --project bin ruff check bin/src
uv run --project bin pytest tests/test_marketplace.py tests/test_install_manifests.py -q

Historical note: the original validation plan also called for full-suite coverage and full-tree strict mypy. Those unbounded baselines are not currently advertised as passing commands; strict mypy remains owned by its remediation milestone.

Historical replay acceptance target: rebuilding an empty projection from the event log had to reproduce canonical state. The original destructive in-place example has been removed because current state may use the shared HOME layout and replay requires a separate --into destination. Follow the current, scratch-only migration replay audit instead.

Phasing (8 phases, each its own PR into fakoli-plugins)

  1. Plugin skeleton: .claude-plugin/plugin.json + README + LICENSE + CHANGELOG + initial CI wiring + bin/ wrappers + pyproject.toml + uv.lock + minimal cli.py (--version only).
  2. State engine: models + SQLite backend + JSONL event log + init/status CLI + state-ops skill + detect-state.sh hook + tests.
  3. Planning engine (template path): prd parse/prd review/plan/score/expand/review tasks/list/show CLI + prd/plan skills + planner agent + tests.
  4. Claims manager: claim/release/renew/next CLI + git_ops + claim skill + check-claim.sh + record-file-change.sh hooks + tests.
  5. Context engine: packet/submit/apply CLI + Review engine apply gate + execute/finish skills + capture-evidence.sh hook + critic + sentinel agents + tests.
  6. MCP server (13 tools) + .mcp.json + bin/anvil-mcp wrapper + tests + docs/mcp.md.
  7. LLM augmentation: Anthropic provider + --use-llm flags + RecordedLLMProvider tests + start-prd skill bridges to fakoli-flow:brainstorm.
  8. GitHub sync (bidirectional) + sync CLI + sync engine + state-keeper agent + tests + docs/github-sync.md + reconciliation + release prep + marketplace.json regen + CHANGELOG for 1.0.0.