anvil roadmap¶
Last updated: 2026-08-24 (v0.6.5 closeout; restructured around Shipped /
Now / Next / Later — the retired v1.11/v2.0/v2.1 version-target buckets are
gone; see How this is organized)
Source of truth: this file. Archived phase backlogs at phase-9-backlog.md and phase-11-backlog.md are kept for historical audit only — do not add new items there.
Companion: tech-debt-backlog.md for non-roadmap debt (12 OPEN CL/TQ/PS items from PR #41 critics; tracked by origin PR, closed across phases). Items there are not duplicated here unless a roadmap item naturally touches the same file.
How this is organized¶
- Priority bucket = when the item actually gets worked, not which numbered
release it ships in. anvil is on the 0.x line now and no longer plans by
v1.11/v2.0/v2.1milestone labels — those names are gone from the structure below (historical "shipped in vX.Y.Z" citations on individual items are untouched; they're audit trail, not planning taxonomy). - Shipped = already landed. Kept here, not deleted, so this file stays the append-only record of what was promised and delivered.
- Now = the committed direction for the current stretch — the integrity-first priority track. What actually gets built next, ahead of everything in Next/Later.
- Next = wanted and scoped, picked up once Now clears: the Phase 10 audit's mechanical carry-forward batch, plus the bigger capability expansion (multi-provider sync scale-out, push-based sync infra, per-provider config schemas).
- Later = follow-on capability and opportunistic hygiene —
additional sync providers, the local SQLite backup snapshot subcommand,
MCP sync tools,
doc/composition cleanups, and items wanted but without a forcing function
yet (formerly the separate
unscheduledbucket; folded in here). - Theme = capability group (sync providers, conflict resolution, snapshot/replay, MCP surface, doc agents, hooks, etc.). Themes are durable across priority buckets; an item may move bucket, its theme rarely does.
- Item IDs preserved verbatim from origin (
P9B-Nfrom phase-9-backlog,P11-XX-XNfrom phase-11-backlog,SL-N/WF-Nfrom the integrity-first priority track) so commit messages, audit cross-references, and the Phase 10 audit stay stable. Every ID in the archived backlogs appears here exactly once (except P11-SK-S5, see Closed / shipped).
Status legend (carried over from origin files, plus SHIPPED for items
that landed): OPEN = wanted, not actively scheduled; TARGETED = scheduled
within its bucket; SPEC-FIRST = needs a design doc before implementation;
SHIPPED = landed (kept inline alongside open siblings for narrative
continuity, e.g. in the Wave lists below); PARTIALLY SHIPPED = part of the
acceptance criteria landed, part is still open.
Shipped¶
Capability that has already landed. Kept here — not deleted — so this file
stays the append-only record of what was promised and delivered; full
item-level detail for the integrity-first track still lives inline in
Now (shipped items stay listed there too, marked SHIPPED, next to
their still-open siblings). This section is the scannable summary the
docs assessment asked for — e.g. sync
github, replay, run-workflow, multi-PRD, and migrate-workspace are all
shipped.
Integrity-first track — Wave 1 & Wave 2¶
- [SL-0] Evidence gate unified with the
applypreview. Shipped in 1.17.1 (PR #66) —transitions._evidence_completedelegates toreview.gates.evidence_complete, locked together by a parametrized agreement test. - [SL-1] Replay proven in CI. Shipped in 1.19.0 —
anvil replay(cli/replay.py) rebuilds state fromevents.jsonl, andtests/test_replay_equivalence.pyasserts replayed state matches original state on every PR. - [SL-3] Typed
ProofArtifactevidence. Shipped in 0.1.0 (B48, part 1 of 2) — a typedProofArtifactunion (CommandProof/DiffProof/LinkProof/AssertionProof) is carried onEvidence.proofs(state/models.py), and tasks can declare typedVerification.required_proofs; acommandrequirement is satisfiable only by aCommandProofwhose realexit_codeis in the passing set. The shell-free capture-evidence dispatcher records each command's real exit code and anoutput_sha256;anvil submit(CLI and MCP) reconciles the per-claim buffer intoEvidence.proofs. Additive and non-breaking — the legacy free-textrequired_evidencepath stayed enforced alongside it, so old event logs replay unchanged. Schema v5 → v6. The portable signed ProofArtifact + strict-by-default variant (part 2 of 2) shipped alongside it. - [SL-6] Spec-assumption scoring. Shipped as
anvil assumptions(cli/plan.py,planning/scoring.py) — ranks PRD requirements byblast_radius * uncertainty(both 1-5, product range 1-25) before planning, purely advisory (never blocks claims or mutates state). - [SL-2] Critic false-pass measurement is PARTIALLY SHIPPED: the
fault-injection corpus and harness are committed
(
benchmarks/critic_corpus/,docs/critic-false-pass-baseline.md) with a mock-backend baseline recorded (false_pass_rate = 1/4 = 0.25); the real-critic baseline run is still open — tracked in Now.
Workflow substrate¶
- [WF-1]
anvil next -q/--quietexit-code loop seam (cli/claim.py) — exit 0 if a task is ready, exit 3 if the queue is empty, sowhile anvil next -q; do …; doneworks without parsing JSON. - [WF-2] Committed, copy-ready loop adapters + how-to:
packaging/loops/ci-drain.sh,packaging/loops/claude-loop.md,packaging/loops/codex-automation.md, documented inhow-to/drive-the-anvil-loop.md. - [WF-3]
anvil run-workflow+ declarative.anvil/workflows/*.yamlrunner (cli/run_workflow.py,workflows/runner.py) — drives each step of a declarative workflow (trigger,steps[], per-steprun/proof/needs) through anvil's governed transitions (create → claim → run → submit evidence → apply) to completion, then exits — no background process. Scoped to ad-hoc loops not derived from a PRD. The broaderanvil workflow-stepposture-2/3 wrapper this theme was named for is a distinct, still-open item — see SL-7 in Now.
Multi-PRD (release-scoped plans)¶
Shipped in 0.3.0 — a project can hold several release-scoped PRDs in one
state.db / events.jsonl. Full theme writeup, the three load-bearing
properties, and the one item this theme deferred (MPRD-RG1, release-group
sync) are under Next →
Theme: Multi-PRD.
Sync & recovery¶
github_issuessync provider (sync/providers/github_issues.py) — the only shippedSyncProvider; the registry-driven Protocol is ready for more (see Next → Theme: Sync providers).anvil replay,anvil backup/anvil restore.anvil migrate-workspace(B44) — one-time, safe-first migration of legacy in-repo<repo>/.anvil/(or<repo>/bin/.anvil/) into the HOME workspace layout: dry-run by default, never clobbers an existing home workspace, copies (never moves).
Closed / shipped (cross-reference)¶
Items that originated in the archived backlogs but shipped before this restructure, kept here for cross-reference traceability.
| ID | Title | Closed in |
|---|---|---|
| P11-SK-S5 | skills/finish/SKILL.md:247-252 — fuzzy detection for fakoli-crew:sentinel; no shell check |
Phase 10 Fix #6 — welder closed this as a bonus while fixing the dangling /anvil:sentinel slash-command reference at the same lines. Removed the broken snippet AND added the claude plugin list 2>/dev/null \| grep -q "fakoli-crew" shell gate (mirroring start-prd/SKILL.md:48), with explicit branches for exit-0 (dispatch fakoli-crew:sentinel) vs non-zero (fall through to plugin-local sentinel agent). The PR-B fix-cycle subsequently dropped the ^ anchor from these patterns once it was discovered that claude plugin list indents each row (so ^fakoli-... never matched). See docs/plans/agent-welder-t11-status.md § "Fix 6 approach" for the welder's full decision rationale. |
| P9-1 | Audit-event honesty — sync.pull.completed emitted on deferred branches |
Phase 9 T5 |
| P9-2 | local_moved-only path set sync_state="in_sync" instead of local_ahead |
Phase 9 T5 |
| P9-3 | SyncAuditPayload single all-optional model accepted nonsense |
Phase 9 T3 |
| P9-4 | RecordedLLMProvider.record_key ignored max_tokens / temperature |
Phase 9 T6 |
| P9-5 | Brainstorm-flow bridge used fuzzy detection | Phase 9 T6 |
| P9-6 | expand --use-llm had no --format prd UX |
Phase 9 T6 |
| P9-7 | Multi-provider config — no way to opt out of every sync provider | Phase 9 T5 |
| P9-8 | Two new plugin-owned doc agents — marketplace-scribe, docs-scribe |
Phase 9 T4 |
See tech-debt-backlog.md § "Phase 8 / Phase 9 closures (sync + LLM cleanups)" for the full implementation detail and test counts on P9-1..P9-8.
Now¶
Priority track: integrity-first (90-day plan). This track sits above the Next/Later buckets below. It is the committed direction for the current stretch and it is sequenced by credibility risk, not by how demonstrable each item is. The Next/Later buckets remain the backlog; this track is what actually gets built first. Status as of 2026-07-07: Wave 1 and Wave 2 are done except SL-2's real-critic baseline run (SL-0, SL-1, SL-3, SL-6 shipped — see Shipped); Wave 3 has not started (SL-4, SL-5, SL-7 all open).
Operating-model principle: sequencing this track by credibility risk embodies fakoli-style P5 (sequence by credibility risk, not demonstrability). See
plugins/fakoli-style/docs/fakoli-style.md.
The reframe this track serves¶
The strategic position is that anvil is the durable, governed state and audit layer that sits underneath an in-session dynamic-workflow runtime (for example, Claude Code's Dynamic Workflows). That runtime is single-driver and in-session: it keeps intermediate results in script variables and discards them when the session ends. anvil is what remembers, provably, what every agent actually did.
One honesty constraint shapes the whole track. There is no state interface to slide "underneath" a session-only runtime today. "Underneath" is earned at the granularity of the step, through three integration postures:
- Beside (ships today). A workflow script voluntarily shells out to the
anvilCLI or MCP tools (next,claim,submit,apply). No enforcement. - Governed step (the realistic "underneath"). A thin wrapper a workflow step calls instead of raw tool calls: claim, run, capture typed proof, submit, apply (gate enforced here). The runtime still drives; every step that matters passes through a recorded, gated transition.
- Projection (the inversion of their context-economy primitive). The
runtime keeps intermediate results out of context in script variables.
anvil persists those variables as
Evidence/Decisionrows, so the audit trail is the durable tail of state the runtime throws away.
Two new types make the postures real and back the items below:
ProofArtifactreplaces free-textrequired_evidencewith typed, verifiable proofs (CommandProof{command, exit_code, output_sha256},DiffProof,LinkProof,AssertionProof). The gate stops asking "does this word appear" and starts asking "does a passing CommandProof exist." Shipped as SL-3 — see Shipped.OutputContractreplaces file-level conflict detection with interface-level declarations (symbols, modules, endpoints, tables), plus an after-the-fact reconciliation that compares the declared contract to the actualDiffProof. Still open — see SL-5 below.
Why this ordering (the argument against doing it differently)¶
The reframe rests entirely on "durable governed state" being trustworthy.
The replay guarantee was, until 1.19.0, unproven in CI (see SL-1) and the
evidence gate was, until 1.17.1, gameable and self-inconsistent. You cannot position as the trust layer
with an untrusted trust layer. So Wave 1 makes the existing claims true, Wave 2
makes governance non-gameable, and Wave 3 builds the integration story on top of
a substrate that has earned it. The temptation to ship the positioning-friendly
items (SL-4, SL-5) first, or to clear the long tidy P11-* audit backlog first,
is the temptation to widen the product instead of making its central claim true.
Resist both.
Wave 1 (Days 1-30): make the claims true¶
Theme: integrity. At the end of this wave every sentence in the positioning is backed by a passing CI job.
- [SL-0] Unify the evidence gate with the
applypreview. SHIPPED in 1.17.1 (PR #66).transitions._evidence_completedelegates toreview.gates.evidence_complete; a parametrized agreement test locks the enforcing gate to the preview gate. Prerequisite for SL-3. - [SL-1] Prove replay in CI. SHIPPED in 1.19.0. The
anvil replayCLI (cli/replay.py) rebuilds state fromevents.jsonlinto a scratch database (the long-planned replay item, pulled forward because the audit positioning depends on it; the siblinganvil snapshotcommand, P9B-7, remains open), andtests/test_replay_equivalence.pyasserts the replayed canonical state is equivalent to the original on every PR — satisfied inside the main pytesttestCI job rather than a separately-namedreplay-equivalencestatus check. This converts the most-repeated and least-proven claim into a verified invariant. - [SL-2] Measure the critic false-pass rate. PARTIALLY SHIPPED. Build
a fault-injection harness: a corpus of known-bad diffs (off-by-one, dropped
null check, assertion-free test, deleted assertion) fed to the critic
agent; measure how many it waves through. Acceptance: a reproducible script
plus a committed baseline false-pass number in
docs/. The harness, corpus, and a mock-backend baseline are committed (docs/critic-false-pass-baseline.md); the real-critic baseline run (needs API access) is still open. You cannot improve the critic until you can score it.
Wave 2 (Days 31-60): make governance non-gameable¶
Theme: typed proof. The substrate stops trusting strings.
- [SL-3] Ship
ProofArtifact(typed evidence). SHIPPED (0.1.0, B48 part 1 of 2). Implemented the typed artifact model; migratedVerification.required_evidence(state/models.py:233); the unified gate (review/gates.py) evaluates typed predicates; shell-freehook dispatch capture-evidencepath emitsCommandProofwith real exit codes and output hashes. The substring path stayed enforced alongside the typed path rather than being deleted (additive, not breaking — old event logs replay unchanged). Depended on SL-0. - [SL-6] Score spec assumptions, not just tasks. SHIPPED. Extended the
six-dimension
Score(state/models.py,Scorevalue object) idea to PRD requirements and surfaces the highest-blast-radius, lowest-confidence assumptions before planning.anvil assumptions(cli/plan.py) reports the top assumptions ranked byblast_radius * uncertainty; purely advisory today (does not yet block claimable tasks on unaddressed assumptions). This is where the human-in-the-loop-at-spec thesis becomes a feature.
Wave 3 (Days 61-90): earn the reframe¶
Theme: "underneath," for real. Only now, on a proven substrate.
- [SL-4] Promote status-file coordination to canonical state. TARGETED.
Today fakoli-flow / fakoli-crew coordinate by writing and grep-parsing markdown
at
docs/plans/agent-<name>-status.md(seefakoli-flow/references/status-protocol.md). Replace that with stateEvents; the wave engine readsanvilinstead of parsing prose. Acceptance: the wave engine has zero markdown-parsing code paths for status. This is the concrete delivery of "fakoli-flow sits on top of anvil." - [SL-5] Contract-level conflict with after-the-fact reconciliation.
SPEC-FIRST. Add
OutputContracttoTask; keyConflictGroup(state/models.py:539) on contract overlap rather thanexpected_filesoverlap; add a post-applydrift check comparing declared contract to actualDiffProof. The reconciliation step is what lifts conflict detection out of the advisory-only class (the same gameability class as the old substring gate: both depend on an honest up-front declaration). Acceptance: a test where two tasks touch the same file but declare non-overlapping contracts and run in parallel, plus a test where the declared contract and the actual diff diverge and a driftEventfires. Depends on SL-3 (DiffProof) — SL-3 has shipped, so SL-5 is unblocked. - [SL-7] Workflow adapter spike (postures 2 and 3). SPEC-FIRST, spike not
product. Build
anvil workflow-step(the governed-step wrapper) and one worked example wiring a dynamic-workflow script to persist its script-variable intermediate results asEvidence/Decisionrows. Acceptance: a recorded run where a workflow script's discarded intermediate state is queryable inevents.jsonlafter the session ends. Distinct from WF-3 (anvil run-workflow, shipped — see Shipped), which drives a declarative file-based workflow rather than wrapping an in-session dynamic-workflow script's individual steps.
What this track explicitly defers¶
The multi-provider sync expansion (P9B-1 Linear, P9B-2 Monday, the follow-on
Jira / GitHub Projects providers) and the 56-item P11-* audit batch stay in
Next and Later below. Adding a third sync provider makes
the product wider; it does not make the central claim more true. None of it
belongs in these 90 days.
Semantic indexing (sqlite-vec) and a knowledge-graph view are likewise deferred
to after Wave 1. They are useful eventually — semantic dedup of requirements
(SL-6), retrieval of prior decisions, and contract-level conflict modelling
(SL-5) — but they widen the surface before the integrity claims are proven,
which is exactly what this track resists. They must also stay outside the
replay boundary: an embedding is model-derived and non-deterministic, so it is
a rebuildable derived index, never canonical state in events.jsonl. Captured as
fakoli-style principle P11 (derived indexes live outside the replay boundary;
distinct from the P11-* audit batch below).
Theme: Workflow substrate (runtime-neutral workflow)¶
This theme grows SL-7 (workflow-step) from a Wave 3 spike into a product axis:
"runtime-neutral workflow," the next axis after runtime-neutral state. It
sits on SL-3 (typed ProofArtifact, shipped) for the per-step gate and is the
forcing function for SL-4 (status-file coordination → events). Full narrative in
docs/specs/2026-06-19-anvil-workflow-substrate.md.
The framing: today anvil's only front door is the PRD (PRD → parse → review →
plan/score → tasks → claim → packet → submit evidence → apply). The second
front door is the workflow/loop itself. Harness-native orchestration primitives
(Claude Code dynamic workflows = JS orchestrating subagents; Codex automations =
scheduled prompts; the OpenAI Agents SDK = code) are ephemeral and
harness-specific; anvil is the durable, governed state + audit layer underneath
them. The key refinement: the PRD is the spec — for the common case you do
not hand-author a workflow file, because anvil already turns the PRD into a ready
queue. The job is to transfer/drive that ready queue into whatever loop or
automation a runtime offers, so each step runs anvil's governed transitions.
The seam is anvil next (cli/claim.py:500),
which already returns the next ready task or, with --json, {data: {task: null}}
on an empty queue (exit 0). The loop body already exists —
claim → packet (the contract that teaches the steps) → do the work →
submit --evidence → apply (gate) — and the execute skill wraps it. Both
invocation modes are the same primitive ("one governed task per invocation"):
run the body once for anvil next's task (a Codex automation fire / CI / cron), or
drain until empty (while anvil next -q; do <body>; done, e.g. Claude's self-paced
/loop or any shell). Durable state makes both resumable and safe under
concurrency via single-winner leases.
Why it strengthens anvil: it exercises the wedge (single-winner leases, file-conflict detection, evidence gating) under real parallel load; adds a second entry point covering the ad-hoc / brownfield ~75% the PRD front door misses; collapses the fakoli-flow / fakoli-crew trinity (coordination becomes anvil events — SL-4); and keeps loops correct-not-just-fast (leased + evidence-gated steps cannot double-claim or fake "done").
- [WF-1]
anvil next -qexit-code seam. SHIPPED. — see Shipped. Adds a-q/--quietflag toanvil next(cli/claim.py:500) that gives jq-less shells and automations a branchable exit code: exit 0 if a task is ready, exit 3 if the queue is empty. This is the single missing bit that turns the existinganvil nextinto a loop seam —while anvil next -q; do …; doneworks without parsing JSON. - [WF-2] Committed loop adapters + how-to. SHIPPED. — see
Shipped. Worked,
committed adapters that drive the WF-1 seam from each runtime — a Claude
/loopdrain, a Codex automation single-fire, a CI/cron drain — plus a how-to that documents the "one governed task per invocation" vs "drain until empty" modes over the same primitive. - [WF-3]
anvil run-workflow+.anvil/workflows/*.yamldeclarative path. SHIPPED. — see Shipped. A committed, harness-neutral declarative workflow format (trigger,steps[], per-steprun/fan_out/claim/proof/needs/on_fail) plus a governed runner that drives each step through anvil's transitions. Scoped only to ad-hoc loops not derived from a PRD — the common case is already covered by WF-1/WF-2 driving the PRD's ready queue. Design lives indocs/specs/2026-06-19-anvil-workflow-substrate.md; it extends the SL-7 spike but does not close it — the generalanvil workflow-stepposture-2/3 wrapper (SL-7 above) is a separate, still-open item.
Next¶
Wanted and scoped; picked up once Now clears — see What this track explicitly defers for why these wait.
These are the Phase 10 plugin-audit deferrals. Items already satisfied by the
current implementation are marked SHIPPED inline; the remaining findings are
SHOULD FIX, CONSIDER, or NIT severity, not release blockers. The bulk close as
mechanical batches; see Cross-cutting themes
for the recommended welder fan-out.
Theme: Audit honesty (mutating-tool input validation)¶
- [P11-MC-S1] SHIPPED in v0.6.5. The canonical
_require_actorvalidator now rejects empty actor identity before mutating MCP operations and preserves normalized actor continuity across lifecycle surfaces. - [P11-MC-S2]
list_tasks.status: str | Nonenot constrained — typo like"in-progress"or"DONE"returns silently empty list. Replace withLiteral[...]matchingTaskCountsByStatusfields verbatim. - [P11-MC-S4] SHIPPED in v0.6.5.
get_next_task.actoris retained and now selects the actor-specific accept-rate history used by the task-offer governor; CLI and MCP expose the same calculation and recovery fields.
Theme: MCP schema fidelity¶
- [P11-MC-S3] Return type
list[dict[str, Any]]/dict[str, Any]strips field-level schema from Claude's view acrosslist_tasks,get_task,get_next_task. DefineTaskSummaryor reuseTaskPydantic model fromstate.models; dropjson.loads(model_dump_json())shim. Closes P11-MC-N1 simultaneously. - [P11-MC-C1] Every tool re-resolves
Path.cwd()per call; futureos.chdir()would silently address different project. Capture_STATE_DIRat module import. - [P11-MC-C2]
_reap_staleswallows all exceptions silently; no surfacing inclaude --debugtraces. Addlogger.warning("stale-claim reaping failed: %s", exc)inside except. Adjacent to CL-3 in tech-debt-backlog (_reap_stale_claimsbare except) — close both in the same patch. - [P11-MC-C3]
WorkPacketResponse.content: Anyallowed but narrower union possible. SwitchAny→str | dict[str, Any]. - [P11-MC-N1]
json.loads(t.model_dump_json())triple-roundtrips data through JSON. Replace witht.model_dump(mode="json"). Closed automatically by P11-MC-S3. - [P11-MC-N2]
DependencyEdgeconstructed with**{"from": dep_id, "to": t.id}splat to dodge keyword. Add comment or switch toDependencyEdge.model_validate(...).
Theme: Skill hygiene (no-fuzzy-detection rule)¶
See Theme 1 for batch-fix leverage notes.
- [P11-SK-S1]
skills/execute/SKILL.md:8,15,256— fuzzy detection forfakoli-flow:execute. Add Step 0claude plugin list 2>/dev/null | grep -q "fakoli-flow"; branch on exit code. Mirrorstart-prd/SKILL.md:48. Note: the grep pattern must NOT use^—claude plugin listindents each row with❯so a leading anchor never matches. - [P11-SK-S2]
skills/finish/SKILL.md:8,245-246— fuzzy detection forfakoli-flow:finish. Add explicitclaude plugin list 2>/dev/null | grep -q "fakoli-flow"check at top of Step 1. - [P11-SK-S3]
skills/claim/SKILL.md:15,250— fuzzy detection forfakoli-flowandfakoli-crew:welder/scout. Wrap each "when X is installed" section inclaude plugin list 2>/dev/null | grep -q "fakoli-..."shell check (no^anchor) or move prose toreferences/composition.md. - [P11-SK-S4]
skills/finish/SKILL.md:177-212— fuzzy detection for sync provider availability. Replace prose withtest -n "$GITHUB_REPOSITORY",gh auth status >/dev/null 2>&1,anvil sync github --health. - [P11-SK-S6]
skills/start-prd/SKILL.md:194-197— fuzzy detection for LLM availability. Add explicittest -n "$ANTHROPIC_API_KEY"check; document branches; or move toreferences/llm-augmentation.md.
Theme: Skill hygiene (phase-status drift)¶
See Theme 5.
- [P11-SK-S7]
skills/state-ops/SKILL.md:119-132— phase-availability tables contradictexecute/SKILL.md(anvil conflicts"pending" vs "available"). Reconcile via singlereferences/phase-status.md. - [P11-SK-S8]
skills/state-ops/SKILL.md:67-96— Steps 2 and 3 labeled "Phase 3 — pending" but every other skill useslist/showas available. Update to "available" matching rest of plugin. - [P11-SK-S9]
skills/state-ops/SKILL.md:1-4— description is longest in plugin (60+ words), weak trigger phrase. Add concrete trigger phrases in quotes; trim capability list.
Theme: Skill hygiene (workflow discipline)¶
- [P11-SK-C2]
skills/start-prd/SKILL.md:70-110— six-question discipline explicit but stopping rule "material" is interpretive. Add concrete stopping rule — max 1 follow-up if under 5 words, never chain more than 8 total. - [P11-SK-C3]
skills/plan/SKILL.md:107-137— Step 3 documents Phase 7 limitation as 4-step workflow buried in paragraph. Promote to### Step 3a — Author subtasks manuallyblock or extract. - [P11-SK-C4]
skills/prd/SKILL.md:76-84— Step 1 lacks explicit one-question-per-message discipline (weaker than start-prd). Mirror start-prd. - [P11-SK-C5]
skills/execute/SKILL.md:70-84— Step 2 abort flow happens after packet fetch; dishonest agent skips it. Move Step 2 ahead of packet fetch. - [P11-SK-C6]
skills/finish/SKILL.md:109-116—--reasonrequirement forapply --rejectburied in prose. Promote to callout at top of section.
Theme: Skill hygiene (drive-by NITs)¶
- [P11-SK-N1]
skills/start-prd/SKILL.md:228— Phase 7 Notes table cell has\|escape that may render literally. Use HTML entity|. - [P11-SK-N2]
skills/claim/SKILL.md:138-143— example ISO timestamp drifts vsexecute/SKILL.md:121. Pick one wall-clock date or use placeholder. - [P11-SK-N3]
skills/state-ops/SKILL.md:22— "State-ops is NOT for" sentence repeats 4x in one paragraph. Format as bulleted list. - [P11-SK-N4]
skills/prd/SKILL.md:200-215— Phase 3 Limitations section duplicates content at lines 39-46. Delete one table or merge columns.
Theme: Hooks (hot-path perf)¶
See Theme 3.
Superseded for the active manifest. hooks/hooks.json now invokes the
shell-free Python dispatcher; the entries below describe cleanup of retained,
unwired legacy scripts rather than current hook latency.
- [P11-HK-S1]
hooks/check-claim.sh:36-59— hot-path perf budget violation; spawnspython3twice (100-300ms) on every Edit/Write/NotebookEdit; exceeds declared 200ms. Consolidate into singlepython3 -cprinting both fields; mirrorrecord-file-change.sh:35-58pattern. - [P11-HK-S2]
hooks/record-file-change.sh:95-106— hot-path perf budget violation;_escape_json()spawns 4python3instances on fallback path; 5-6 total spawns. Move JSON escaping into original extractionpython3block; emit pre-escaped values. - [P11-HK-N1]
hooks/record-file-change.sh:55-57— threeprintf … | sed -n 'Np'invocations; eachsedis a fork. Replace with singleread/mapfile. Drive-by during P11-HK-S2. - [P11-HK-N2]
hooks/check-claim.sh:95—>/dev/null || truediscards CLI stdout; future structured JSON warning silently dropped. Add inline comment cross-referencing CLI subcommand contract docs. Drive-by during P11-HK-S1.
Theme: Hooks (contract documentation)¶
See Theme 4.
- [P11-HK-S3]
README.md/ newhooks/README.md— non-blocking contract undocumented at plugin/doc level; future maintainer will reintroduceset -e. Add hook-contract section. Single-paragraph fix; high-leverage.
Theme: Hooks (robustness)¶
Superseded for the active manifest. The shell-free Python dispatcher owns active error isolation and state resolution. Legacy-script findings remain as optional cleanup unless those scripts are wired again.
- [P11-HK-C2] All four
.shfiles — no diagnostic fallback when hook silently fails. SupportANVIL_HOOK_DEBUG=1env var redirecting stderr to.anvil/.hook-debug.log. - [P11-HK-C3]
hooks/detect-state.sh:29—$("$CLI" status --hook-format 2>&1)merges stderr into status line shown to Claude. Drop2>&1; capture separately for diagnostic-fallback branch. - [P11-HK-C4] SHIPPED. The active hook manifest no longer invokes the
legacy shell scripts. Its shell-free
anvil hook dispatchpath resolves the same HOME/local/ANVIL_ROOTstate layout as the CLI and MCP server. - [P11-HK-C5]
hooks/detect-state.sh:14-20— language detection uses sequential overwrites; polyglot projects mislabeled. Either emit comma-joined list or guard each line. Cross-plugin coordination opportunity withfakoli-flow/hooks/detect-context.sh.
Theme: Agents (description completeness)¶
- [P11-AG-S1]
agents/critic.md:12-22— description has only 1<example>block (rubric floor 2; convention 3). Add 2 more with<commentary>: one for fakoli-crew fallback path, one for SHOULD-FIX-only verdict. - [P11-AG-S2]
agents/planner.md:12-40— description has only 2<example>blocks; below 3-example convention. Add a third covering re-planning after PRD rejection / incremental conflict. - [P11-AG-S3]
agents/sentinel.md:12-19— description has only 1<example>block AND example lacks<commentary>. Add 2 more examples +<commentary>to every example. - [P11-AG-S4]
agents/sentinel.md:23-28—allowed-tools:used instead oftools:. Rename key. Reviewer may upgrade to MUST FIX for systemic consistency with the 5 Phase 10 MUST FIX agents — costs nothing if bundled with S3/S5. - [P11-AG-S5]
agents/sentinel.md:1-103— file is 103 lines, at proportionality floor; missing Composition, Inputs, "NOT" boundary, Status File Output sections. Expand to ~140-180 lines mirroringcritic.mdstructure. - [P11-AG-C4]
agents/planner.md:76-80— composition mentions onlyfakoli-crew:guidoas defer-to; missing scout/critic acknowledgment. Add one-line note. - [P11-AG-N1]
agents/sentinel.md:103— missing trailing newline. Drive-by during P11-AG-S3/S4/S5.
Theme: Documentation (install messaging, surface counts)¶
See Theme 7.
- [P11-ST-S1] SHIPPED. README uses the public
/plugin marketplace add fakoli/anviland/plugin install anvil@anvilflow, with source installation kept as an explicit alternative. - [P11-ST-S2] SHIPPED.
[Unreleased]is empty; dated release entries own past-tense changes. - [P11-ST-S3] SHIPPED. Root
.pytest_cache/is ignored. - [P11-ST-S4] SHIPPED. README presents one published-package install story and labels alternate paths consistently.
- [P11-ST-C1] CLOSED as superseded. A hand-maintained README count
table would immediately drift.
anvil describe --jsonis the authoritative live CLI/MCP inventory; architecture documents the current surface split. - [P11-ST-C2] SHIPPED.
[Unreleased]no longer carries unlinked forward-looking provider claims; roadmap items own that planning detail. - [P11-ST-C3]
README.md:5-7— minimal badge set; no CI / test-count badges. Add CI status badge (once live-GitHub nightly workflow public) and a test-count badge. - [P11-ST-N1] SHIPPED. The stale "this release" parenthetical is gone.
Theme: Sync providers (multi-provider expansion)¶
The SyncProvider Protocol shipped in v1.8.0 was deliberately registry-driven so contributors can add providers without engine changes. v1.8.0 / v1.9.0 ship github_issues only; it remains the only shipped provider today (see Shipped → Sync & recovery).
- [P9B-1]
LinearIssuesProvider(linear_issues). OPEN. GraphQL-only API; httpx client with respx mocking. Status mapping needs a per-team workflow inspection step. Step-by-step contributor guide already indocs/sync-providers.md§ "Step-by-step: add Linear support". Acceptance: provider module + GraphQL transport + full-lifecycle respx tests +.github/workflows/anvil-live-linear.ymlgated onLINEAR_API_KEYsecret +anvil sync linear_issues --healthworks. - [P9B-2]
MondayBoardsProvider(monday_boards). OPEN. Monday has people-columns and per-board custom columns;provider_metadatadict carries the bulk of the shape. Auth via Monday API key. REST+JSON (Monday's GraphQL is opt-in per workspace). Same acceptance shape as P9B-1.
Theme: Multi-PRD (release-scoped plans)¶
The v0.3 reframe: a single project holds several release-scoped PRDs in one
state.db / events.jsonl instead of exactly one. Each PRD is a
release/milestone-scoped, separately-gated, revisable plan carrying a target
version/tag; its requirements, features, and tasks are partitioned by an owning
prd_id. Shipped in 0.3.0 — full design in
docs/specs/2026-06-22-multi-prd-revisable.md;
task-by-task backlog in
docs/backlog/multi-prd-revisable.prd.md.
The three load-bearing properties this theme holds:
- The v6→v7 migration is zero-data-loss. The in-place v6→v7 migration (the
v0.3 multi-PRD persistence foundation) rebuilds the partitioned
prds/ requirements / features / tasks layout so that a pre-multi-PRD database becomes a project whose lonedefaultPRD owns every existing row. Nothing is dropped and nothing has to be re-authored; the single-PRD project is just the one-PRD degenerate case after the migration. (The follow-on v7→v8 step is a purely additive per-PRDrevisioncounter — seestate/sqlite.py_m_to_v7/_m_to_v8.) - Gating is per-PRD; conflict detection is cross-PRD. The
prd_status_gatekeys on the task's owning PRD (task.prd_id): a task is claimable once its PRD is approved for its exact current material, even while a sibling PRD is stilldraft. Conflict groups andanvil nextexclusion sets, by contrast, are computed over all PRDs, so two tasks in different PRDs that touch the same file are still single-winner-coordinated — the moat holds across the whole project, not per-PRD. - Replay stays equivalent. Every multi-PRD mutation carries
prd_idthrough the event payloads, so replayingevents.jsonlfrom empty reconstructs the partitioned canonical state exactly. Replay-equivalence is checked as logical equivalence (canonical row-ordered dump / per-table content hash), never byte-identical SQLite, and the migration backfill is written to match what replay would produce.
Release/milestone sync wiring (PRD→GitHub-milestone) is intentionally not
in this theme — only the SyncMapping.prd_id + prd-kind data plumbing shipped;
the network-touching milestone client is deferred to [MPRD-RG1] under
Theme: Sync infrastructure.
Theme: Sync infrastructure (push-based + conflict completion)¶
- [P9B-5] Webhook-based sync (vs polling). SPEC-FIRST.
--watchpolls every N seconds; for providers that publish webhooks (GitHub, Linear, Monday, Jira), accept push-based sync via a long-running listener. Webhook secret in.anvil/config.yaml; HMAC verification on every payload. Needs design doc first: engine's current "one fetch round-trip per task per pass" assumption does not hold under webhooks (out-of-order events, duplicates, races). Spec scope:anvil webhook-listen --provider X --port 8080subcommand, event de-duplication via(provider_id, external_id, last_modified)tuple, out-of-order queueing with configurable max-delay, per-provider HMAC verification, polling fallback when listener crashes. - [P9B-6] Immediate-apply
*_appliedresolution variants. TARGETED. Phase 9 T5 deferred wiringremote_wins_applied/local_wins_appliedper TODOs atcli/sync.py:1054and:1068. Conflict-safety design (re-fetch on moving target, retry/back-off contract) needs specifying first. Acceptance:remote_wins_appliedcalls_apply_remote_to_localinline inside the pull loop;local_wins_appliedcallsprovider.push_task(...)inline with a defined retry/back-off contract for the race where a parallel remote edit lands between decision and push;*_appliedtokens join the controlled vocabulary indocs/github-sync.md; 4+ new tests intest_cli_sync.py. - [MPRD-RG1] PRD→release-group sync (
ensure_release_groupProtocol + GitHub milestone client). OPEN. Deferred out of the multi-PRD release (Phase 7 ofdocs/specs/2026-06-22-multi-prd-revisable.md; tracked as T029 indocs/backlog/multi-prd-revisable.prd.md). The multi-PRD work shipped the release/sync data plumbing only —SyncMapping.prd_id+entity_kind: Literal['task','prd'], per-PRD--prdpush scoping, andprd_idon reconciliation discrepancies. The network-touching milestone wiring was explicitly not built so no provider had to change. Scope when picked up: - A provider-neutral
ensure_release_group(release_tag, target_version, prd_summary, mapping) -> ExternalRefProtocol method (covers GitHub Milestone / Linear Cycle / Jira FixVersion), optional and capability-gated via asupports_milestones(a.k.a.supports_release_groups) flag so existing providers stay unchanged. - GitHub client
create_milestone/list_milestonescalls plus issue→milestone assignment for the issues a PRD owns. - A
sync.milestone.ensured(release-group) audit event and prd-kindSyncMappingrow persistence (entity_kind='prd', carryingprd_id, nulltask_id) so the 1:1 PRD↔release/milestone mapping is recorded. - A
missing_milestone_mappingreconciliation discrepancy kind for a PRD that has atarget_tagbut no persisted milestone mapping (sibling tomissing_sync_mapping;drift_sync_statealready special-cases prd-kind rows so a milestone produces no task-shaped drift). - Behind the capability flag throughout;
anvil sync … --prd <id> --pushgains the milestone-ensure step only for providers that advertise the capability.
Theme: Configuration (provider config schemas)¶
- [P9B-9] Provider config schemas in
config.yaml. SPEC-FIRST (co-required with P9B-1 Linear). Currentsync.providersconfig key is a flat list; as soon as providers need per-provider config (Linear team ID, Monday board ID, Jira project key + workflow map), the flat list becomes a nested map. Design doc decides: does the new map shape coexist with the flat list, or replace it? Migration path: a list of strings is shorthand for "the listed providers with empty config" — keeps v1.9.0 configs valid.
Cross-cutting themes (high-leverage batches)¶
Items spanning multiple critics/areas that benefit from cohesive treatment. These come from the Phase 10 audit and supersede the "items by critic" view when planning Phase 11 welder fan-out. Each theme is welder-sized and self-contained.
Theme 1 — No-fuzzy-detection rule across skills¶
Closes: P11-SK-S1, P11-SK-S2, P11-SK-S3, P11-SK-S4, ~~P11-SK-S5~~, P11-SK-S6 (originally 6 SHOULD FIX items; 5 live — P11-SK-S5 closed in Phase 10 Fix #6, see Closed / shipped).
Pattern: every skill that conditionally bridges to fakoli-flow, fakoli-crew, a sync provider, or LLM augmentation uses prose-only "when X is installed" framing without a claude plugin list 2>/dev/null | grep -q "X" shell check (no ^ anchor — claude plugin list indents each row, so the anchored form never matches). start-prd/SKILL.md:48 and finish/SKILL.md:249-254 are the reference implementations every other skill should mirror.
Welder effort: ~3 lines per site, 5 sites — single welder pass, ~50 minutes.
Theme 2 — Non-empty actor validation across MCP mutating tools¶
Closed in v0.6.5: P11-MC-S1 (1 SHOULD FIX, originally 6 sites).
The shared _require_actor validator now protects mutating MCP entry points;
this batch remains here as the audit cross-reference.
Theme 3 — Hot-path perf budget on hook scripts¶
Superseded for the active manifest: P11-HK-S1, P11-HK-S2, and P11-HK-N1 now describe only retained, unwired legacy wrappers. Active hooks use the shell-free Python dispatcher. Revisit this batch only if the wrappers are wired again or retained compatibility itself gains a measured performance requirement.
Theme 4 — Hook contract undocumented at plugin level¶
Closed: P11-HK-S3. Architecture and design now document the shell-free
dispatcher, the five active hooks, their non-blocking exit 0 contract, and
the separately opt-in blocking stop gate.
Theme 5 — Phase-status table drift across skills¶
Closes: P11-SK-S7, P11-SK-S8 (2 SHOULD FIX); enabled by P11-SK-C1 (extract to references/).
Pattern: anvil conflicts is "pending" in state-ops, "available" in execute. list/show are "pending" in state-ops Step 2/3 but available in every other skill. State-ops is the laggard.
Fix shape: single source of truth at references/phase-status.md (or docs/phase-status.md); skills link to it instead of inlining tables.
Welder effort: create reference doc + update 7 SKILL.md references — ~2 hours.
Theme 6 — Composition duplication across three doc/state agents¶
Closes: P11-AG-C1, P11-AG-C2, P11-AG-C3 (3 CONSIDER).
Pattern: docs-scribe, marketplace-scribe, and state-keeper each carry near-identical "three doc/state specialists inside anvil" composition tables. If the split ever changes, three files need to update in lockstep.
Fix shape: extract to docs/specs/internal-agents.md; agents link to it.
Welder effort: ~1 hour.
Theme 7 — Install messaging drift in README + CHANGELOG¶
Closed: P11-ST-S1, P11-ST-S2, P11-ST-S4, and P11-ST-N1. README now has
one published-package install story, [Unreleased] is empty, and release-bound
phrasing has been removed. The release helper and its tests keep current-version
examples synchronized.
Later¶
Follow-on capability and opportunistic hygiene — wanted, but not next in line. Pick up when an adjacent welder pass touches the file, or when a forcing function lands.
Theme: Sync providers (workflow-aware integrations)¶
- [P9B-3]
JiraIssuesProvider(jira_issues). OPEN. Jira's workflow/status taxonomy is per-project; provider needs a one-time discovery call to map anvil's 11TaskStatusvalues to the project's actual statuses. Auth via PAT + email pair. Acceptance: same shape as P9B-1 plus--discover-statusesflag that writes the discovered mapping into.anvil/config.yamlundersync.providers.jira_issues.status_map. - [P9B-4]
GitHubProjectsProvider(github_projects). OPEN. Sibling togithub_issuesbut for Projects v2 (the newer board surface). Shares the gh-CLI / httpx transport fromgithub_issuesbut addresses a different remote object kind. Probably co-locates insync/providers/github_projects.py.
Theme: Snapshot / replay¶
- [P9B-7]
anvil snapshotsubcommand. OPEN. This is a local SQLite.backupand retention workflow, distinct from the shipped read-onlyanvil project snapshot --jsonprovider operation. Phase 5 (v1.4.0) removed the pre-createdsnapshots/directory because nothing wrote to it. Acceptance:anvil snapshot [--retention 30d|count:N]writes timestamped databases under the resolved state directory;--listshows size + age;--restore <name>restores atomically (temp file, swap via rename).
Theme: MCP surface (sync tools)¶
- [P9B-8] MCP sync tools surface. OPEN. MCP server (Phase 6) exposes 24 read/mutate tools but does NOT expose
sync_*tools. Agents that want sync today must shell out via Bash. Acceptance: 4 new MCP tools —sync_run(provider, *, direction='both', task_id=None),sync_health(provider),sync_status(),sync_reconcile(*, fix=False). Tool errors map cleanly toToolError(message)with the same exception classes the CLI handles. Documented indocs/mcp.md§ Sync tools; tests intests/test_mcp.py.
Theme: Agents (composition deduplication)¶
See Theme 6.
- [P11-AG-C1]
agents/docs-scribe.md:1-366— 366 lines (near 400 ceiling); ~60 lines duplicatemarketplace-scribe.mdandstate-keeper.mdcomposition prose. Extract shared "three doc/state specialists" composition intodocs/specs/internal-agents.md; link from all three agents. - [P11-AG-C2]
agents/marketplace-scribe.md:1-308— same composition duplication (lines 144-161, 292-308). Same fix as C1. - [P11-AG-C3]
agents/state-keeper.md:1-293— same duplication pattern (lines 94-107). Same fix as C1.
Theme: Skills (subdirectory extraction)¶
- [P11-SK-C1] All 7
SKILL.mdfiles — noreferences/,examples/, orscripts/subdirectories; bodies bundle phase-status tables and composition prose. Extract toreferences/phase-status.md,references/composition.md, etc. Closes ~20-30% of SKILL.md body weight. High leverage — enables Theme 5 (phase-status drift) and Theme 1 (no-fuzzy-detection) batches.
Theme: Hooks (concurrency hardening)¶
- [P11-HK-C1]
hooks/capture-evidence.sh:232+record-file-change.sh:113— race-prone append on shared files (events.jsonl,orphan.json); JSON records can exceedPIPE_BUFwhenSTDOUT_EXCERPTis nearMAX_EXCERPT=4000. Addflockguard OR document at-most-rare interleave and have replay tolerate truncation. May defer further pending a sync-hardening pass.
Theme: Hooks (config-driven matchers)¶
Wanted but no compelling forcing function yet; revisit when an adjacent item forces a touch on the same file or when a config-driven matcher framework lands.
- [P11-HK-N3]
hooks/capture-evidence.sh:119-128— hardcoded verification-command pattern list; Phase 6+ TODO already flagged. Track as deferred config-driven matcher. Aligned withtech-debt-backlog.mdCL-10 (capture-evidence.sh+gates.pypattern sets not aligned).
Companion: tech-debt-backlog.md (not duplicated here)¶
These items remain owned by tech-debt-backlog.md and are not duplicated into roadmap scope unless a roadmap item naturally touches the same file. Listed here for cross-reference only.
| ID | Source | Status |
|---|---|---|
| CL-1, CL-2, CL-3, CL-4, CL-5, CL-8, CL-10, CL-11, CL-12, CL-13 | PR #41 critics | OPEN |
| TQ-1, TQ-2, TQ-3, TQ-4, TQ-6, TQ-7, TQ-8 | PR #41 Critic-4 | OPEN |
| PS-1 | PR #41 Critic-2 | OPEN |
Adjacency hint: Phase 10 finding P11-MC-C2 (silent _reap_stale exception swallow) is adjacent to CL-3 (_reap_stale_claims bare except). The welder closing P11-MC-C2 should consider closing CL-3 in the same patch. Phase 10 finding P11-HK-N3 (capture-evidence.sh hardcoded matcher list) is aligned with CL-10 (capture-evidence.sh + gates.py pattern sets not aligned).