Skip to content

Latest commit

 

History

History
691 lines (482 loc) · 146 KB

File metadata and controls

691 lines (482 loc) · 146 KB

Changelog

All notable changes to superpowers-v (Compound V) are documented here.

The format is based on Keep a Changelog, and this project uses semantic versioning.

[2.17.0] - 2026-07-26

Added — Co-change advisory (ordered, git-derived) + failure-prioritized evidence packing

Two approaches internalized from a critical read of the repowise project (AGPL-3.0 — ideas only, NO code copied), then built from scratch against this repo's own history. Six further candidates from the same review were evaluated and rejected on our own data.

Feature A — co-change advisory: the inverse of the scope gate. The scope gate answers "did a worker write OUTSIDE its lane?" — a containment question. It cannot answer the opposite failure: "does this partition own file A but forget partner file B, which this repo's own history says almost always moves with A?" New scripts/compound-v-cochange.py (rules / check) answers that from git log alone — zero model involvement.

  • ORDERED rules, never symmetric pairs. It emits A -> B with its own direction: marketplace.json -> plugin.json and plugin.json -> marketplace.json are two distinct rules with different support and different confidence, because "is B missing when A moves?" is a directional question.
  • Four conjunctive bars before a rule fires — support ≥ 8, P(B|A) ≥ 0.70, a 95% Wilson lower bound ≥ 0.50 (guards small-sample luck: 8/11 reads as 0.73 but its lower bound is 0.43), and narrow support ≥ 3 (co-changes in non-release, non-format commits touching ≤ 10 files — what separates a real coupling from a wide doc sweep). Release and bulk commit counts are reported beside every rule so a headline support can't be read in isolation. Rename unification (-M) is applied, so a rename cannot manufacture a phantom rule. --explain-rejections shows what was rejected and on which bar.
  • ADVISORY — it adds NO NEW hard gate. compound-v:partition-reviewer now writes its PASS/FAIL verdict FIRST (new Step 6.5) and only then runs co-change (Step 7), which may only append to an unconditional WARNINGS section rendered for BOTH PASS and FAIL. There is no FAIL: COCHANGE_* code and the agent is instructed not to invent one. The guarantee is ordering-bound, not exit-code-bound, because an exit code cannot bind an LLM reviewer — and check exits 0 whether or not it finds anything (non-zero is reserved for operational errors), which is what structurally stops a caller from promoting a correlation into a gate.
  • It does NOT replace either existing CI lockstep guard, and neither guard changed. CI enforces the plugin.json / marketplace.json / CHANGELOG versions exactly, at push time; co-change advises statistically, at partition time, about a file a plan may have forgotten. Both stay.
  • "Could not tell" is a distinct answer from "nothing found." A byte-capped git read or a history too short to clear the support bar returns complete: false with a reason and emits no rules at all; the reviewer must report that as NOTE: COCHANGE_INCOMPLETE ("could not determine"), never as a clean bill of health. A non-zero git exit is surfaced as an operational error, never flattened into "no rules".
  • Anti-ruflo: every warning carries support, rate, Wilson lower bound, narrow support and the sample window verbatim — no risk score, no confidence %, no "likely". Inventing a summary metric on top of the counts is precisely the fabricated-evidence failure this project exists to prevent.

Feature B — failure-prioritized, explicitly lossy evidence packing. Every truncator feeding an external judge was a tail-drop, so it amputated exactly the traceback at the END of a log. pack_evidence() in scripts/compound-v-collect-results.py keeps the failure content and drops the filler instead, via a TOTAL 8-rung loss hierarchy (byte-identical passthrough → drop non-failure spans → zero the context radius → priority-allocate and truncate an oversized span → shrink the header → drop the header and all markers → a fixed placeholder → omit the block).

  • The claim is exactly "failure-prioritized, explicitly lossy, and always within budget" — NOT "never drops a failure line". Those two are mutually impossible: failure lines alone can exceed any budget, and a log where every line is an ERROR has no filler left to drop. Rungs 5-7 are unmarked by construction — there is no room left for a marker, so the rung reached IS the signal (the caller logs it).
  • Packing runs AFTER redaction, and that ordering is the security property. redact_uncapped() is extracted from compound-v-epic-arbiter.py with both fail-closed rules intact (unclosed PEM/PGP block, unclosed quoted labelled secret), and the evidence path is redact → fail-closed → pack, on already-sanitized text. Packing only deletes WHOLE lines, so it can never un-redact. Packing first would be a real egress hole, not a style preference: dropping a key's BEGIN/END or a password= label line destroys the multi-line structure redaction matches on, and a short secret would then also evade the opaque-token regex. Omission markers are path-free by construction and section_label is a closed enum.
  • An over-budget prompt SKIPS the poll with a bounded diagnostic rather than silently truncating it. A missing ballot is honest; a quietly-shortened prompt changes what a judge votes on.

ADR 0002 — any published number ships with its limits in the same document (docs/superpowers/adr/0002-limits-ship-with-the-claim.md). The anti-ruflo CI gate catches fabricated numbers; it cannot catch a number that is entirely real and still misleads because the reader can't see what it was measured on. Every published figure now carries a "What this does not show" note next to the claim. Five alternatives declined, including CONVENTIONS.md (generated — /v:onboard --refresh would silently erase the rule) and a CI grep (a regex cannot separate a claim from a version string, and widening the anti-ruflo gate would false-positive itself into being disabled — the v2.14.1 lesson). The ADR applies the rule to itself and states plainly that it creates no hard gate.

Verification

Selftests under LANG=C on the Python 3.9 floor: compound-v-cochange.py 69 cases; compound-v-collect-results.py 94 checks; compound-v-epic-arbiter.py 237 checks (was 196 — the original 196 are untouched); compound-v-scope-check.py passing; frontmatter lint clean. Run against this repo's own history, the engine emits six firing ordered rules and nothing sub-threshold.

What this does not show

Those six rules were measured on one repository — this one — over the 381 eligible commits in its history at the time of measurement, with a ≤ 10-file narrow-support bar calibrated to this repo's commit width. A young repo, a squash-merge-only history, or a wide monorepo will legitimately produce no rules at all; that is a correct result, not a failure. A rule is a correlation in past commits — not a causal claim, and not a contract that two files must move together. The historical single-file touches behind these rules are unpaired historical touches: an unadjudicated signal. None was adjudicated as a violation and this release does not claim any was one. Nothing here measures whether the advisory improves review outcomes, catches real omissions in practice, or saves any time or tokens — no such measurement was taken.

[2.16.0] - 2026-07-15

Added — Decision memory + challenge (recall your own past reasoning, always challenged)

During the brainstorm/elicitation phase Compound V already intercepts, it now remembers your own dated past decisions and surfaces them as falsifiable historyalways paired with a divergent counter-move, so a recall triggers re-examination, not autopilot. New scripts/compound-v-preferences.py (recall/capture/distill/stats/purge) + /v:preferences + a brainstorm.preferences config key. Grounded by three pre-flights whose domain audit reframed the feature: the original "let the brainstorm reason as the creator" clone was rated high-hazard (choice-blindness confabulation, default-nudge dark patterns, echo chamber, opposing this project's own anti-anchoring moat), so v1 ships the safe memory + challenge framing instead.

  • Three modes off | on-demand (default) | marked. marked puts a soft, falsifiable dated badge (↩ your past pick: N/M · date) beside the matching option — a label, never a pre-selected default (a mark is information; a pre-tick is an answer you must override — the audit's red line). Every surfacing is challenge-paired or suppressed (no-challenge).
  • The "why" is captured UNPROMPTED (free-text first); a tapped candidate is a weaker borrowed class, excluded from the distilled "your reasoning" — never an inferred rationale.
  • Anti-anchoring: suppressed on recon-touched / high-novelty forks (never fires where Trigger-0 widens). Drift honesty: recency-weighted last-K disagreement demotes + banners a shifting pattern; a holdout probe records un-nudged choices; patterns auto-expire.
  • Split storage: the raw decisions.jsonl stays LOCAL (~/.claude/compound-v/preferences/, private, purge-able); the distilled preferences.md is written in-repo (docs/superpowers/preferences/, git-tracked → V-memory, /v:remember-able) and is secret+PII-scrubbed before write.
  • Anti-ruflo: counts only (4/5 similar forks), never a fabricated confidence %; recall is evidence, never an authority — the brainstorm human-gate is untouched. Pure Python 3.9 stdlib (reuses V-memory's fts5_escape + redact and append_line by import); --selftest auto-run by the CI all-selftest gate.

[2.15.0] - 2026-07-14

Added — Local observability dashboard (present-only, read-only)

Closes the plugin's biggest competitive gap (no observability UI) — while keeping the no-daemon / git-derived-control philosophy. New scripts/compound-v-dashboard.py renders docs/superpowers/execution/** (runs, epics, per-job status, scope-gate verdicts, usage, blocker ledger) as a browser view; wired through /v:status --html|--serve and the new /v:dashboard command.

  • emit — a self-contained static HTML snapshot (data inlined, offline, theme-aware — for sharing / audit), written to a git-ignored docs/superpowers/execution/dashboard.html.
  • serve — an ephemeral, read-only, 127.0.0.1-only live viewer that auto-refreshes as a run/epic progresses (the local equivalent of a competitor's live agent UI). It is a foreground process you Ctrl-C; it never backgrounds, never auto-launches, binds loopback only, serves GET/HEAD only (any other method → 405), is realpath-contained to the execution root (traversal / symlink-escape → 403, non-.json/.html/.yaml → 404, no directory-listing leak), and writes nothing to any run dir.
  • Read-only by design — observe in the browser, control via the CLI. No merge/kill/retry buttons; the guarantees stay git-derived and human-gated (the moat, not a gap).
  • Anti-ruflo — a dashboard that does not lie: renders only what is in the state files — real counts (never a fabricated %-progress), measured-only usage ( when a backend reports none, never a fabricated 0), and only real timestamps sourced from the state files. Degrade-safe: a run with only manifest.yaml shows "no state yet", malformed JSON shows "unparseable", an empty root shows "no runs yet" — never a crash.
  • Pure Python 3.9-safe stdlib (http.server, no Flask/CDN/npm); --selftest (auto-run in CI by the v2.14.1 all-selftest gate); security posture verified live (loopback bind, 405/403/404 on the attack cases).

[2.14.1] - 2026-07-14

Fixed — CI safety net & housekeeping (from a plugin health audit)

A 5-dimension health audit (dead-code · CI/test-coverage · doc/skill-drift · contract-consistency · safety) found the plugin CODE clean (all safety invariants hold, contracts tight) but two real holes in the CI safety net that let regressions ship green.

  • CI ran only 4 of 29 script --selftests. validate.yml now runs every scripts/*.py --selftest (dynamic discovery) under the Python 3.9 floor — previously only the marathon quartet (epic-state/arbiter/watch/headless-shim) was defended, leaving the scope gate (compound-v-scope-check.py), model resolver, pre-eval, usage, memory, and the collector uncovered. It also validates every tracked run-manifest (not just the example) and hard-fails if the validator script is missing.
  • The intra-plugin dead-link guard was a silent no-op. Its fail=1 was set inside a piped while subshell and never propagated, so the guard printed dead links but never failed the build. It now accumulates hits in a temp file, covers .py/.sh/.json/.yml link targets (not just .md), and strips :line suffixes. Fixed the 10 dead cross-refs it now catches.
  • Test coverage: added --selftest to compound-v-collect-results.py (33 checks over the real job_result conformance logic CI previously only checked via a drift-prone reimplementation) and compound-v-update-memory.py (15 checks).
  • Cleanup: removed two dead helpers (_split_lines, _repo_root_default) and a stray models.err (now gitignored).
  • Docs: corrected the stale "devin/opencode worker not yet built" claim (both scripts are built; auth-pending/unverified), added /v:adr to the AGENTS.md command table, and documented the v2.14 headless --allow-build opt-in.

[2.14.0] - 2026-07-14

Added — Confirmed blockers (2nd external family) + headless resurrection shim

Built as one dogfooded epic (docs/superpowers/execution/2026-07-14-v2.14-blockers-and-headless/), grounded by three LIVE pre-flights (archaeology · domain · library) that reshaped the design before a line was written, plus three user policy decisions.

Confirmed blockers — done_with_blockers now reachable via a genuine 2nd external family.

  • The marathon arbiter panel (compound-v-epic-arbiter.py) now polls a second, distinct external model family — Gemini via agy — read-only, alongside Codex (GPT). The advisory poll passes an explicit resolved Gemini --model (family derived from that string, fail-closedagy 1.1.1's catalog is no longer Gemini-only), reads stdout, reuses the Codex redaction/parse/security-boundary path, and passes no --dangerously-skip-permissions (verified live: agy --print answers read-only without it).
  • A blocker is CONFIRMED only when ≥2 distinct external families agree on the SAME blocker_category (closed enum: credential | external-account | infra | third-party-data | legal-approval | human-decision) — not merely the blocked_external label. This defends the correlated-oracle false-confirm (two LLMs hallucinating different missing facts under the same label).
  • compound-v-epic-state.py derives confirmed from the arbiter's frozen audit (bound via a new --audit-file, realpath-contained + validated: matching epic_id/feature/blocked_external disposition, audit["confirmed"] is True) — never from a caller-supplied --families-agreeing CSV (which stays as recorded metadata), and raw --confirmed/--blocker-confirmed booleans stay hard-rejected. It adds the done_with_blockers terminal (a successful, auto-merging terminal) + an awaiting-final-review pre-terminal + the mandatory is_terminal prefix; records the agreed --blocker-category on the ledger; auto-sets a durable blocker_audit_due obligation on a confirmed blocker (gates record_final_review(passed) + the terminal until an approved re-review clears it, with an atomic --record-blocker-audit-failed revert on ISSUES); and relaxes record_final_review(passed) to accept an epic whose only non-done features are confirmed-blocked. An abandoned/halt_feature feature or a SUSPECTED (unconfirmed) blocker still halts to blocked_needing_human. The checkpoint (non-marathon) path is byte-identical.
  • /v:epic auto-merges done_with_blockers via the final integration review → finishing-a-development-branch (the chosen policy); a confirmed blocker is always over-sampled by a durable-obligation PASS-integrity re-review (verifying the frozen audit's confirmed, ≥2 distinct external families on the same category, and no retry dissent); and the blocked remainder (feature · category · families · evidence) is surfaced to the human, never silently dropped. Framed honestly: ≥2 distinct families is the minimum defensible bar — distinct-family LLM votes are correlated (shared pretraining/RLHF), not fully independent — paired with same-category agreement + audit over-sampling, not treated as strong independent corroboration.

Headless resurrection shim — opt-in, present-only.

  • New compound-v-headless-shim.py emit --os macos|linux prints a macOS launchd plist / Linux cron entry + runbook so a user can opt into resurrecting a marathon epic while the desktop app is closed. It is present-only — the plugin never launchctl/crontab-installs it (AST-asserted) and never runs the agent.
  • The emitted command uses --permission-mode dontAsk + a curated --allowedTools allowlist (runs read-only + allowlist, refuses everything else) — never a bypass flag. The runbook carries a prominent DO-NOT block referencing the repo-deletion incident. It bakes an absolute claude path (fails the emit if unresolved), /dev/null stdin, and prints launchctl bootstrap gui/$UID (modern) as the user's install step. Honest boundary: launchd fires on wake with one coalesced catch-up; it does not run while powered off/asleep, and a gui/$UID LaunchAgent needs a GUI login.

Changed

  • .github/workflows/validate.yml runs the new compound-v-headless-shim.py --selftest under the Python 3.9 floor alongside the existing epic-state/arbiter/watch selftests.

[2.12.0] - 2026-07-13

Added — Per-ticket usage capture + on-demand cross-brand advisor

Two features, built as one dogfooded epic (docs/superpowers/execution/2026-07-13-usage-and-advisor/), grounded by three LIVE pre-flights that changed the design before a line was written.

  • Feature A — measured usage on job_result. A new optional usage object ({input_tokens, output_tokens, advisor_calls, backend, measured}) is threaded worker → collector → aggregator → /v:status, recording ONLY real measured backend output (anti-ruflo: never an estimate).
    • scripts/compound-v-usage-extract.py (new) normalizes per-backend event streams (verified live, not from training data): codex turn.completed.usage summed across turns, opencode step_finish.part.tokens, cursor result.usage. Backends with no machine-readable usage (antigravity agy, claude-via-Task subagent, devin) emit measured:false + null tokens — fail-open, never a fabricated number.
    • scripts/compound-v-collect-results.py build_result() now passes usage through (a pre-flight-caught blocking gap: the collector re-synthesizes every result and previously dropped it, so every measured value was silently discarded).
    • scripts/compound-v-usage-aggregate.py (new) rolls usage up per ticket/feature/epic, counting measured:false jobs as "unmeasured" rather than zero. /v:status gains a degrade-safe usage column; the old blanket "no token metrics" line is reworded to permit MEASURED usage while still banning estimates.
  • Feature B — on-demand cross-brand advisor (opt-in, subagent pattern). A cheap Sonnet executor consults a stronger advisor of a preferably DIFFERENT brand (Codex if available, else Opus) only on a hard sub-decision.
    • Live pre-flight REFUTED the assumed claude -p --advisor flag (it does not exist) and rejected the real advisor_20260301 API tool (requires an API key + anthropic SDK, breaking the plugin's pure-stdlib/no-service/subscription ethos). Advisor is therefore a harness subagent pattern.
    • scripts/compound-v-resolve-model.py exposes advisor_eligible (a standard/core-slice implementer OR a fast-path Claude worker) and a cross-brand advisor selector (codex > other non-claude > Opus fallback; never Haiku). scripts/compound-v-validate-manifest.py validates an optional per-job advisor: block and rejects it on ineligible job types; manifests without it stay valid.
    • scripts/compound-v-advisor-consult.sh (new) runs ONE READ-ONLY advisory turn — codex exec --sandbox read-only or claude -p --model opus --permission-mode plan, and NEVER --dangerously-skip-permissions. A read-only advisor that cannot write files structurally forecloses the 2026-07-13 nested-bypass-agent incident. Proven by a fake-backend stub test with no live run.
    • scripts/compound-v-preeval.py gains an advisor_calls → escalate sensor (a fail-open, escalation-only clone of the churn_hot triad): repeated advisor consults are a post-run signal that a job was harder than its tier.

[2.11.0] - 2026-07-13

Added — Auto-resurrection watch (opt-in, marathon-only)

v2.10 shipped the Marathon Loop but deliberately deferred auto-resurrection: a hard death still needed a human to re-run /v:epic <epic-id>. v2.11 closes that gap with an ADDITIVE opt-in watch surface on top of marathon (--watch at --init, rejected without --stance marathon; no in-place upgrade of an existing epic, same rule as marathon itself). A watch-off marathon epic stays byte-identical to v2.10 — none of the fields below are ever written for it.

  • V1 — atomic resume authority + liveness heartbeat (scripts/compound-v-epic-state.py): --claim-resume is the crux — ONE fcntl.flock-guarded atomic transaction that decides whether a scheduler-fired session may resume a dead epic, returning {"claimed","reason":"claimed|live|terminal|resume-cap","resume_count"}. There is no pid or lease object involved — the Claude Code harness has no stable driver pid across shell calls, so a FRESH last_progress_at heartbeat alone defers the claim (live) and the --claim-resume flock is the sole ownership/serialization authority, closing the duplicate-resurrection gap an earlier pid-lease design would have had. --liveness is a read-only watcher poll ({"incomplete","stale","epic_status","terminal","resume_count"}); stale requires incomplete, non-terminal, and past a heartbeat threshold (default 45 min) — heartbeat age is the whole staleness signal. --renew-lease is the live driver's own heartbeat call (kept under its original flag name for driver-side stability): it simply bumps last_progress_at to now, no pid, no TTL, nothing to create-or-renew. A new resume_count global breaker axis (max_resume_count, default 20) permits N resumes and blocks the (N+1)th, tripping the same blocked_needing_human latch as every other breaker; --clear-breaker --reset-resume-count re-arms it. Built directly on v2.10's crash-safe resume — nothing about the existing single-process marathon path changed.
  • V2 — two-tier watcher (scripts/compound-v-epic-watch.py, new): never talks to a scheduler directly and never re-implements any state-spine logic. emit-prompt prints a SELF-CONTAINED resume prompt for a scheduler to hand to a fresh, memoryless session — that session calls --claim-resume, branches on the result, and performs the full disarm inline on a terminal/resume-cap verdict (a cold-prompt design: no conversation history is assumed). plan reads --liveness and advises the two tiers' cadence (off-minute :17/:47, ~30 min apart) and whether to disarm. The driver (/v:epic, not this script) owns the real scheduler wiring — session CronCreate/CronDelete for Tier-1, mcp__scheduled-tasks__create_scheduled_task/delete_scheduled_task for Tier-2.
  • V3 — idempotent watcher registry + driver arm/disarm + capability detection: --record-watcher-armed/--record-watcher-disarmed/--list-watchers track scheduler tasks idempotently by (provider, task-id), so a crash-and-replay during arming or disarming is a harmless no-op, never a duplicate or a leak. /v:epic's marathon loop (commands/v-epic.md §0c "Watch-on marathon start" and "Watch disarm") bumps the heartbeat and arms both tiers once at invocation start (recording an intent record before each real scheduler create call, so a crash mid-arm never double-arms on re-entry), re-arms a Tier-1 task past its ~7-day expiry, and disarms both tiers (plus a deterministic-id fallback, attempted even when the registry is empty) at every terminal exit. /v:init gained a capability-detection step for scheduler availability on this machine, feeding the epic.autonomy.watch config key (consulted only once, at a NEW epic's --init — the persisted epic-state.json is the sole authority afterward).
  • CI: .github/workflows/validate.yml now also runs python3 scripts/compound-v-epic-watch.py --selftest in the same Python 3.9 step as the existing compound-v-epic-state.py/compound-v-epic-arbiter.py selftests.

The corrected honest boundary (v2.11) — still not "survives while you sleep"

Auto-resurrection is bounded and partial, not magic:

  • Tier-1 (session CronCreate) pauses while the session is unavailable or busy, MISSES any fire that elapses while paused (no catch-up), may restore on the next conversation turn while still unexpired, and expires after 7 days even inside a continuously open session.
  • Tier-2 (scheduled-tasks, on-disk) runs only while the desktop app is open and the machine is awake; it performs exactly ONE catch-up for the most recent missed run on app start/wake, within 7 days. It is not an always-on server.
  • "Survives quota exhaustion" holds only if the quota has since reset AND the session is still authenticated — an expired OAuth token still needs a human.
  • A machine that is truly off (laptop closed, asleep) is not covered by either tier. Genuine machine-off execution needs remote infrastructure, never claimed built-in here.
  • Resurrection is bounded by max_resume_count (default 20) — a persistently-dying run halts at blocked_needing_human for a human, same as any other tripped breaker.

Opt-in (epic.autonomy.watch, default off); the default epic and a watch-off marathon are unchanged. No fabricated cost/token metrics anywhere in this surface.

Provenance

Built on v2.10's crash-safe marathon resume. Cross-model reviewed by Codex gpt-5.6-sol.

[2.10.0] — 2026-07-13

Added — Marathon Loop (opt-in autonomous /v:epic, PHASED scope)

An opt-in marathon stance for /v:epic: instead of stopping at every feature checkpoint, the epic can chew through the whole runnable feature DAG in one invocation. The default checkpoint epic is behaviorally unchanged — marathon is chosen only at --init time and cannot be flipped onto an existing checkpoint epic. Scope was deliberately PHASED after three Codex Sol xhigh review rounds converged that every critical concurrency finding traced to auto-resurrection (a two-tier watcher reviving the epic while you're away); removing that from v2.10 makes the marathon single-process and the whole class of concurrency criticals disappears. See docs/superpowers/specs/2026-07-12-epic-autonomous-mode-design.md for the full scope decision and the deferred v2.11 sketch.

  • Marathon Loop + DAG-autonomous routing (scripts/compound-v-epic-state.py): a marathon-only autonomy state block, --next --autonomous (a separate, read-only routing function from the default --next — byte-identical default behavior preserved) that routes on deterministic DAG reachability, so an abandoned or blocked feature removes only its transitive dependents, never its independents. attempts tracking, --can-retry, --record-disposition, --record-final-review. Terminal states: done (all features done and a persisted final_review.status=="passed" — never on feature-completion alone), blocked_needing_human (a tripped breaker, a halt_epic verdict, or exhausted reachable work), running_with_failures (non-terminal). done_with_blockers is defined but structurally unreachable in v2.10 (needs a 2nd confirming external model family — deferred to v2.11).
  • Cross-model Arbiter Panel (scripts/compound-v-epic-arbiter.py, new): classifies a feature FAILURE via a two-phase, challenge-bound API — --prepare issues a bounded Claude ballot-task prompt tied to {epic_id,feature,attempt,challenge_id} (an HMAC-keyed, per-epic challenge secret; a mismatched/replayed/stale challenge is dropped before any model call), then --classify polls Codex (real sandbox, read-only, through the timeout supervisor, evidence size-capped and secret-redacted before egress) and validates a driver-supplied Claude ballot, aggregating both with a complete, deterministic truth table. Family-diverse aggregation: ballots collapse one-per-family (gpt/gemini/claude/grok/unknown); a parse-failed or errored ballot is dropped and logged, never fabricated as a vote; empty or tied → conservative halt_feature; retry_fix past the per-feature retry cap is masked to halt_feature. Antigravity/Cursor are excluded from arbitration (no kernel write-confinement) — implementation workers only, never advisors. Fail-closed secret redaction before any external-model egress (labelled tokens, auth headers, private keys, URL credentials, multiline/unclosed-quote secrets — omits the suspect evidence rather than risk a half-redacted leak). O_NOFOLLOW evidence containment: every untrusted path under the arbiter's audit directory is opened via dir-fd + O_NOFOLLOW (TOCTOU-safe — never validate-a-name-then-reopen-it), atomic tmp+rename writes, capped/rotated audit JSONs so an all-night run can't fill the disk. Every ballot + resolved family + aggregation reason is frozen to docs/superpowers/execution/epics/<epic-id>/arbiter/<feature>-<attempt>.json.
  • Blocker Ledger (scripts/compound-v-epic-state.py): "do everything you can" — finish everything reachable, isolate only the genuinely impossible, escalate with proof, never halt the rest. A blocked_external disposition marks a feature blocked (ledger entry) without halting the epic; --next --autonomous skips it and routes around only its transitive dependents. v2.10 blockers are always SUSPECTED--blocker-confirmed true is hard-rejected everywhere it could be set; CONFIRMED (≥2 distinct known external model families agreeing) is structurally unreachable on a Codex+Claude-only panel and is deferred to v2.11 alongside a second safe external family and the done_with_blockers terminal.
  • Global circuit breakers + human resume (scripts/compound-v-epic-state.py): total_attempts, no_progress_cycles (a full autonomous pass that advances done by zero), and wall-clock hours since autonomy.started_at — counts and hours only, never a fabricated cost. --breaker-check is read-only; --trip-breaker atomically parks the epic at blocked_needing_human. Re-checked before every feature and before every model call (arbiter, sample-audit, final review) — an honest, not a hard real-time, guarantee. Human recovery, never automatic: --clear-breaker (--reset-wall-clock, --set-max-total-attempts N) re-arms a tripped breaker; --clear-disposition clears a sticky halt_epic verdict — both followed by the human re-running /v:epic <epic-id>, which is re-entrant and resumes the marathon from epic-state.json.
  • PASS integrity — anti-reward-hack gate (agents/spec-reviewer.md §2.5, commands/v-epic.md): a marathon SUCCESS is not blindly trusted. The reviewer contract gained a deterministic "did this diff weaken its own tests/scorers to pass?" check; the marathon driver sample-audits a deterministic fraction of PASSes (every 3rd done this invocation, plus always the first) with a fresh adversarial re-review, and gates terminal done on a final cross-feature re-verification (--record-final-review) over the whole accumulated diff since autonomy.start_sha.
  • CI: .github/workflows/validate.yml now sets up Python 3.9 (the documented marathon-scripts floor) and runs both new --selftest suites (compound-v-epic-state.py, compound-v-epic-arbiter.py) as a required job — a red selftest now fails CI.

The honest v2.10 boundary — no auto-resurrection

Marathon is opt-in; the default epic still checkpoints. "Survives a fall" means two things, both true today and neither overclaimed: in-session, the loop continues past a soft per-feature error to the next runnable feature automatically, within the one live /v:epic invocation. After a hard death (quota, closed terminal, crashed machine), a human re-invokes /v:epic <epic-id>, which resumes from the committed epic-state.json. There is no automatic resurrection while you're away in v2.10 — nothing wakes the epic back up on its own. That is the deferred v2.11 auto-watcher (Execution Lease + Two-Tier Watcher + generation-fenced execution across the dispatcher/worker/merge-back/commit layer) — its own spec, its own review pass, because it needs correct distributed concurrency that the v2.10 single-process design deliberately avoids. No fabricated cost/token metrics anywhere in either stance.

Provenance

Converged from four independent pre-implementation reviews plus three Codex Sol xhigh adversarial rounds on 2026-07-12 that drove the phased-scope decision. Built across four disjoint units (state spine → arbiter panel → driver/reviewer wiring → this docs/CI/release unit) and cross-model reviewed by Codex gpt-5.6-sol.

[2.9.0] — 2026-07-12

Added — Pre-Evaluation stage + proportionate fast-path

A fast, cheap Pre-Evaluation stage now runs before Trigger 0, scores each change request on two separate axes, and — only when a change is provably trivial and low-impact — OFFERS a proportionate fast-path. Everything else routes to the full pipeline. The request-level score never auto-routes; it only ever offers (Iron-Invariant #4). Fail-closed is the law everywhere: any ambiguity, missing data, tier disagreement, unknown axis, budget overrun, or parse failure → FULL_PIPELINE (or escalate, post-diff). Never fail open.

  • Two-axis truth-table scoring, no raw LLM magnitude (scripts/compound-v-preeval.py, skills/compound-v/phase-preeval.md). Bands (difficulty ⊥ impact) are assembled by deterministic logic from tiered evidence — path patterns (T1), a calibrated fast-path history (T2), and a single light-tier classify (T3) invoked by the parent harness as a Task, never from Python. The derived 1-10 is a post-decision band-midpoint DISPLAY label, never the gate. Six hard Layer-A overrides (localization-failed, sensitive-path, shared-token/a11y/generated, semantic-vs-path disagreement, churn-hot, unknown-axis) each short-circuit to FULL with zero further cost; a fired override needs zero model calls.
  • Bounded localization (scripts/compound-v-localize.py): a low verdict is impossible until a bounded, read-only localize() (rg → git grep → grep degrade, hard file-cap + timeout, every external CLI routed through the timeout supervisor with stdin </dev/null) has resolved real paths / tokens / fan-out. Writes a committed localization artifact the fast-path manifest binds against.
  • Content-pattern taxonomy (.claude/compound-v-impact-taxonomy.example.yaml, scripts/compound-v-taxonomy.py): impact is decided on what a change semantically is, not only where its file lives (AC-8). Kinds include shared_token and a11y — a "cosmetic" color that is really a brand/contrast-compliance surface, or an aria-label that silently breaks WCAG, both escalate. Regex patterns are a documented safe subset (no nested quantifiers), deterministically validated and matched inside a killable subprocess (AC-16).
  • Cross-artifact-bound fast-path manifest, materialized by a dedicated owner (scripts/compound-v-fastpath-materialize.py, AC-14): an accepted FASTPATH_ELIGIBLE record is materialized into a run whose single-implementer manifest (review modeled as a dispatcher phase outside jobs, not a job) passes compound-v-validate-manifest.py --mode pre-dispatch — the sole write_allowed literal equals localization.resolved_paths[0], and pre_eval_id / decision / taxonomy_digest / localization content-digest are all validator-enforced to be equal across manifest + record + artifact (AC-13). A tampered or ineligible record is rejected fail-closed before any write or commit.
  • Normalized escalation-only churn (scripts/compound-v-churn.py): generated/vendor paths and pure-format commits are excluded (single-sourced in the taxonomy churn block). A churn-hot path escalates; absence or an insufficient sample never lowers.
  • Sibling post-diff re-classifier (scripts/compound-v-postdiff-reclassify.py, AC-5): a separate analyzer (never an extension of the hardened name-only scope gate) runs pre-merge against the pinned baseline and the same authoritative changed-path set. It answers one question — "does the materialized diff still deserve the fast-path, or must it ESCALATE?" — via sensitive-path touch, size accounting (tracked numstat unioned with separately-measured untracked bytes), a shared taxonomy content re-check over changed hunks, and a typed structural pass (a real stdlib-ast analyzer for Python; JS/TS/Go/Ruby fail closed unless provably trivial). Any uncertainty escalates.
  • Three new state-machine states, idempotent + crash-consistent escalation (skills/compound-v/state-machine.md, AC-15): PRE_EVAL_DONE is a record-status field (no state.json exists at prediction time), while FASTPATH_DISPATCHED / ESCALATION_REQUIRED are real phases. Escalation mints a new run-id and never mutates the frozen manifest (AC-4); a two-phase protocol (commit patch+baseline evidence → deterministic child run-id → create+commit child → commit parent escalated_to) reconciles partial states on resume, discovering an existing child before minting one.
  • Three-event triage-outcomes + git-derived precision in /v:status (scripts/compound-v-triage-outcomes.py, AC-3/AC-12): telemetry is strictly append-only — predictedbindactual, joined on the write-once pre_eval_id, no back-fill. Precision is computed from the fast-path parent outcome only, git-derived, and reports insufficient (never a fabricated number) on an empty or below-floor stream (AC-10). The escalation child contributes escalation evidence, never a healthy signal (cohort separation).
  • /v:init + /v:onboard wiring: /v:init gains pre_eval.* config (fail-closed defaults, malformed → warn → default) and revocable remember-my-choice per taxonomy-category (AC-11 — a remembered choice skips the OFFER for that category only; it can never bypass the fail-closed overrides). /v:onboard drafts a first-cut taxonomy + churn-exclusion block from the repo's structure, kept/edited by a human at the gate (never auto-applied). Thin ADR capture is exposed via /v:adr.

Tests

  • tests/v2.9-e2e/test_fastpath_and_escalation.py — a runnable stdlib unittest e2e suite (12 cases, green under LANG=C) driving the REAL merged scripts end-to-end: AC-1 (shared-token "make button red" → FULL via override #3), AC-11 (a css-only-remembered request still escalates on a shared-token/a11y surface; the engine has no remember parameter), AC-3/7 (accepted fast-path → materialized manifest passes --mode pre-dispatch; clean diff does not escalate; a sensitive-path or shared-token diff does), and AC-10/12 (precision reports insufficient, never a number, on an empty/below-floor stream).

Provenance

Built by Compound V dogfooding itself — the feature shipped as a 16-job manifest dispatched through the very orchestrator it extends. The plan was hardened to convergence across 5 Codex plan-review rounds (each reject → accept-all, closing 3–4 crit + high findings per round, folded into a single Lifecycle & commit-ordering protocol as the release's one authority).

[2.8.1] — 2026-07-11

Added — session-aware codex workers

  • Structured session-id capture. The headless codex worker now runs codex exec with --json and parses the first {"type":"thread.started","thread_id":"<uuid>"} event, carrying the UUID-validated thread_id inside the canonical job_result.session_id (empty when the event is absent) — replacing the brittle stderr banner scrape; the dispatcher persists session_id + failure_class into state.json jobs[<id>]. (scripts/compound-v-run-codex-worker.sh, skills/backend-launcher/adapter-codex.md)
  • logs/<job-id>.jsonl run-dir convention. A new --events-log <path> worker arg tees the --json event stream to docs/superpowers/execution/<run-id>/logs/<job-id>.jsonl; the dispatcher records that same path in state.json jobs[<id>].log. Standalone worker use keeps an $ART default, so the arg is optional and degrade-safe. (agents/parallel-dispatcher.md, skills/compound-v/state-machine.md)
  • Liveness JSONL signal. classify_job() now reads the events-log's newest line when present: an event newer than the staleness threshold is a WORKING signal, an older newest-event reinforces STALE. Malformed/partial JSONL never raises — it falls through to the prior git+FS+pid behavior. No log field ⇒ identical prior behavior. (scripts/compound-v-liveness.py)
  • --ephemeral discovery review. compound-v-codex-review.sh adds --ephemeral to its single codex exec invocation — discovery rounds must not persist or resume (statelessness is the anti-anchoring point). Never added to the worker. (scripts/compound-v-codex-review.sh)

Fixed

  • Resume/parallel-dispatcher contradiction reconciled. v-resume.md and parallel-dispatcher.md now state a byte-identical resume-eligibility rule: a codex job may be resumed via codex exec resume <captured-uuid> IFF its failure_class is environmental (timeout | network) AND its worktree still exists; every other case recreates the worktree fresh at HEAD. Kills the archaeology-flagged contradiction (v-resume.md:29 vs parallel-dispatcher.md:183). (commands/v-resume.md, agents/parallel-dispatcher.md)
  • Dead job["log"] now populated. The state-machine's log field, previously documented but never written, is now recorded at dispatch for codex jobs and consumed by liveness.
  • Stderr UUID-scrape replaced. The fragile stderr session-id extraction is deleted in favor of the structured --json thread.started capture above.

Probed

  • Thread-naming unsupported in codex exec (live-probed 2026-07-11): codex exec exposes no flag to name or pin a thread id, so the worker captures the auto-generated UUID from the thread.started event rather than assigning one. --json and --output-last-message verified to coexist (result path unchanged); --ephemeral verified accepted by codex exec. All codex capability facts here are live-probed, per the library audit — not re-invented.

[2.8.0] — 2026-07-11

Security — two scope-gate exploits, both reproduced before fixing

  • Rename bypass (HIGH). The gate's diff ran with git's default rename detection ON, so git mv docs/important.md src/renamed.md under write_allowed: [src/**] collapsed to a single record whose --name-only output was just the destination — the out-of-scope deletion of docs/important.md was invisible and the verdict was pass (reproduced). The diff argv now carries --no-renames: both sides of a rename surface as a delete + an add, and the out-of-scope source path BLOCKS. (scripts/compound-v-scope-check.py)
  • Symlink escape (MEDIUM). The gate string-matched changed paths and never lstat-ed anything — a symlink inside the allowed area pointing outside the worktree glob-matched cleanly, and a write through it landed OUTSIDE the repo with verdict pass (reproduced). The verdict path now scans the WHOLE gate root (os.walk with followlinks=False, symlinks only — cheap) and reports every symlink whose realpath escapes the root as a violation "<path> (symlink escapes the worktree)" — unconditionally: even inside the allowed area, and even for a pre-existing link committed before the baseline with no new changes at all, because a write through either lands where git sees nothing and the link itself is the only reliable gate-time signal. Degrade-safe on unreadable entries. Honesty note (in the module docstring too): the gate DETECTS the channel; it cannot observe writes already made through it — kernel-level confinement (the codex backend's sandbox) remains the preventive layer.
  • Three new selftest cases — rename-out-of-scope, job-created escaping symlink, pre-existing (committed-before-baseline) escaping symlink — each verified to FAIL against the unfixed logic via a temporary revert and PASS after the fix; the suite is green.

Added

  • Trigger-0 hook backstop (hooks/brainstorm-trigger0-nudge.sh, registered in hooks/hooks.json): when the Skill tool invokes superpowers:brainstorming, a one-line idempotent reminder to run the Trigger 0 gates is injected. A reminder, not enforcement — Trigger 0 stays description-driven; the hook closes the "agent simply forgets" gap documented in v2.7.0.
  • xhigh effort — codex-only. codex-cli live-accepts model_reasoning_effort=xhigh (probed 2026-07-11 on 0.144.1); the effort vocabulary gains xhigh valid iff backend: codex — every other backend rejects with a clear error naming the rule. Enforced in lockstep at compound-v-resolve-model.py, compound-v-validate-manifest.py, both codex shell workers, and stated identically on every active effort-vocabulary surface.
  • Directions-late protocol (anti-anchoring, made explicit): the brainstorm forms its own first-principles proposals BEFORE reading the recon doc's ## SUGGESTED DIRECTIONS; consumption is observable via the recon-outcomes stream.
  • recon-outcomes stream (docs/superpowers/memory/recon-outcomes.jsonl): an append-only event machine — a gate-stopped Trigger-0 evaluation emits exactly one terminal event (plumbing_skip|kb_skip|off|declined|no_engine); an engine run emits firedsaved (with path) → consumed as three separate appended events, never a mutated line. Never read by routing.
  • VERIFIED / UNVERIFIED split in recon docs: the output contract is now genuinely five verbatim sections (## QUESTIONS TO ASK, ## VERIFIED FACTS / CONSTRAINTS, ## UNVERIFIED LEADS, ## SUGGESTED DIRECTIONS, ## SOURCES). VERIFIED = checked against a cited primary source (provisionally binding; 1B/1C revalidate); everything else is an UNVERIFIED LEAD that must become a question until validated.
  • Gate-2 freshness rule: a strong KB hit now requires scope AND freshness — volatile material (libraries, APIs, regulations, availability, best practices) older than ~30 days degrades to partial: still evidence, no longer skip-authority.

Fixed

  • Recon wiring finally reaches the executing 1B/1C: the recon-read step existed only in the phase docs — agents/domain-expert.md, agents/doc-validator.md, and both prompt templates never mentioned it, so dispatched pre-flights never learned a recon doc existed. All four now carry the read step plus the exact-path handoff contract.
  • Epistemic contradiction in the gate-3 offer: the "verbatim" copy promised deep-research even on machines without it, conflicting with the honesty rule one section down — the offer is now engine-aware and honest, and decline paths are reachable.
  • Fail-closed config, verbatim everywhere it's consumed: missing file or key → documented defaults (deep_research: "ask", batch_elicitation: true); malformed JSON, wrong type, or unknown value → warn once, then deep_research=ask and batch_elicitation=false for the session — an invalid value is never treated as auto.
  • Staleness sweep: GEMINI.md was entirely pre-v2.7 ("three transitions", Gemini 2.5, missing command rows) — refreshed to the four-transition reality; surviving codex-cli 0.130 pins → 0.144.1 and cursor worker provenance comments 2025.09.12 → 2026.06.26.

Audit credit

Five audit lines drove this release: F1 (live dogfood of Trigger 0/elicitation — procedures actually executed), F2 (cross-repo consistency/staleness sweep), F3 (scripts robustness — both scope-gate exploits reproduced on scratch fixtures before any fix), from three parallel Fable agents; plus C1/C2 — two independent max-effort Codex gpt-5.6-sol passes at xhigh (the v2.7.0 guidance red-teamed as executable instructions, 28 findings; design red-team, 9 findings + 5 proposals). Cross-model by construction, convergent findings independently confirmed across lines. The pre-dispatch Codex plan review (verdict reject, 7 findings, all accepted) reshaped the plan itself — including the whole-root pre-existing-symlink scan shipped above.

Post-build cross-model review (Codex gpt-5.6-sol @ xhigh, 5 rounds)

The build was reviewed to convergence. Round 1 (9 findings, all accepted): a .git-named escaping symlink bypassed the scan; the outcomes event machine had no legal failure transition; the exact-path handoff had no literal storage carrier; five active surfaces still described batching as companion-only; the dedicated "max-effort" review command still capped at high. Rounds 2–5 hardened the symlink scan alone through four more genuine edges — a nested real .git directory hiding a link, a chmod 000 directory, and finally a real false-PASS where os.path.islink silently swallows EACCES on a 0400 (readable-but-not-searchable) directory (fixed by switching to os.lstat, which raises). Each fix carries a selftest; the gate self-test suite is green.

[2.7.0] — 2026-07-10

Added

  • Trigger 0 — pre-brainstorm recon (skills/compound-v/phase-0-recon.md): when a brainstorm is about to begin on an unfamiliar topic, a gated, bounded research pass (bundled deep-research if present, ≤6 parallel WebSearch otherwise, skip-with-notice if neither) writes an anti-anchoring recon doc to docs/superpowers/recon/ that the brainstorm — and later pre-flights 1B/1C — read first. Gate order: plumbing-skip → V-memory KB hit → brainstorm.deep_research config (ask default / auto / off hard kill-switch). Recon is evidence, never a routing input. Description-driven with zero hook backstop — weaker than Triggers 1–3, documented as such.
  • Batched elicitation (skills/compound-v/brainstorm-elicitation.md): ≥3 independent questions (≤5 groups/screen, never a grid) may batch into ONE Visual Companion form screen — reusing upstream's companion server as-is, only if the user already accepted it this session. Independence is judged on answer interaction; when unsure → sequential. Deliberately overrides upstream's "text questions → terminal" rule for this narrow case, and says so.
  • /v:init: brainstorm.deep_research + brainstorm.batch_elicitation policy keys (committed config) and a deep_research presence probe (machine-local capabilities cache, advisory only — fire-time listing check is the contract).
  • CI guard: CHANGELOG top version must equal plugin.json version — closes the bug class where v2.6.4 shipped with both manifests still at 2.6.3 (the bump was written but never committed, and manifest-vs-manifest lockstep can't see it).

Fixed

  • Pre-flight phase docs 1B/1C now read docs/superpowers/recon/ before opening new searches (deepen, don't repeat).
  • skills/compound-v/skill-escalation.md reconciled with Trigger 0's earlier deep-research use (previously claimed deep-research fires only past 1B/1C).

Cross-model review (Codex gpt-5.6-sol, 6 rounds, 10 accepted findings)

  • /v:init stated ask/auto unconditionally — now explicitly gate 3 of 3 (plumbing-skip and KB-hit gates named, authority linked).
  • Epic mode silently bypassed Trigger 0 — per-feature brainstorms now run the recon gate sequence up front; later features converge via the KB-hit gate by design; the autonomous loop is described as the post-spec execution tail.
  • Stale three-phase enumerations (SKILL.md quick-reference heading, plugin/marketplace descriptions) updated to the four-transition reality.
  • The CHANGELOG guard was hardened round-by-round to CommonMark-correct fence handling: opener char+length tracked, closer requires same char + run ≥ opener + only trailing whitespace, a backtick opener with a backtick in its info string is not a fence, headings indented ≤3 spaces are matched with indent-independent version extraction. A 15-fixture adversarial suite was exercised locally; unbalanced fences still fail conservatively (loud, never a false pass).

[2.6.4] — 2026-07-10

Fixed — Compound V's own audit trail could be silently deleted, and /v:status could mislead

Two real incidents noticed by Oscar Salcedo, which a requested Codex cross-model hunt for "similar/adjacent bugs" grew into a full sweep of the same bug class across the orchestrator:

  • Data loss: an uncommitted run directory vanishes on worktree cleanup. docs/superpowers/execution/<run-id>/** is documented as "the committed run substrate" (execution-manifest.md) — but nothing in the pipeline actually committed it. superpowers:finishing-a-development-branch's cleanup step runs git worktree remove on both its Merge and Discard paths, which silently deletes any uncommitted files in that worktree — taking Compound V's own audit trail with it. After a restart, /v:status would then honestly (but confusingly) report "no orchestrator runs" for a repo that demonstrably had one.
  • Misleading status message for non-Compound-V work. When a repo had real prior work done via plain Superpowers subagent-driven-development (evidenced by .superpowers/sdd/ task-brief/report/review artifacts) rather than Compound V's own manifest-driven dispatch, /v:status's "no orchestrator runs" message read as "nothing happened here" — it had no visibility into that different, upstream-owned execution path. Fixed with a cheap presence-check (not a parse — that directory's format belongs to the base Superpowers plugin, not Compound V) that disambiguates the message without trying to understand or summarize its contents.

The commit-discipline fix, after four rounds of Codex review, landed nine explicit commit points across the pipeline (each closing a path where state could be written but never survive a worktree cleanup):

  1. /v:orchestrate — commits manifest.yaml + the initial state.json right after materializing them.
  2. parallel-dispatcher Step 7 — commits the run directory + memory/scorecard files in one shot before handing off to finishing-a-development-branch (the one point that can trigger the destructive cleanup). Round 1 of review caught a bug in this very fix: state.json's phase was flipped to MERGED after the commit, so the committed record permanently lagged one phase behind reality — fixed by writing MERGED first, then committing everything together. 3–7. commands/v-epic.md — a separate, epic-level epic-state.json (the epic's only resume mechanism, one level up from any single feature's run directory) was never committed anywhere. Five commit points added: after init, at every checkpoint (the default MAX_FEATURES=1 stopping point after every feature), at epic-complete, at epic-blocked, and — caught in round 3 — after crash-reconcile (the --status failed "abandon and stop" path is terminal and doesn't otherwise pass through the checkpoint's commit).
  3. commands/v-resume.md — its own completion path didn't reference committing the recovered run substrate; a resume completing this way could re-lose the very state it just recovered.
  4. commands/v-collect.md — standalone use (re-checking an already-dispatched run without re-dispatching) rewrote results/*.json + state.json with no commit step at all.

state-machine.md documents the general "written to disk ≠ durable" principle tying it all together. Docs-only; no code changed. Codex cross-model verification, four rounds: round 1 found the MERGED-ordering bug plus the v-epic/v-resume/v-collect gaps; round 2 (broad hunt) confirmed the fix and found nothing new to add; round 3 caught the crash-reconcile gap; round 4 (narrow re-check) confirmed all nine commit points present, correctly scoped, and non-contradictory.

[2.6.3] — 2026-07-10

Changed — Codex defaults bumped to the GPT-5.6 family (Sol/Terra/Luna)

  • deepgpt-5.6-sol, standardgpt-5.6-terra, lightgpt-5.6-luna (was gpt-5.5/gpt-5.5/gpt-5.3-codex-spark) — a real per-tier differentiation where deep/standard previously shared the same model. Live-verified all three on codex-cli 0.144.1 (PROBE_OK). gpt-5.6-sol requires codex-cli >= 0.143.0 — confirmed broken with a clear 400 "requires a newer version of Codex" on 0.142.5, working on 0.144.1; an under-floor client fails loud (not silently — the failure-policy retries once then halts cleanly). gpt-5.6-terra/gpt-5.6-luna work on older clients too (verified back to 0.142.5). compound-v-codex-review.sh's cross-model-review default follows the deep tier (gpt-5.6-sol, "Codex on their max").
  • Two independently-stale adapter pins refreshed during the audit: adapter-codex.md's verified-against pin (0.130.00.144.1); adapter-cursor.md's verified-against pin (2025.09.122026.06.26) and a now-false claim — "cursor-agent has no models list command" — corrected: it does now (cursor-agent models, a live 187-entry catalog verified). Grok is not present in that live catalog for this account (press coverage says available, likely region/plan-gated — not documented since unconfirmed hands-on). No auto-discovery was added for Cursor's catalog (would be over-engineering — it spans unrelated vendor families with no shared naming convention, unlike Antigravity's single-family Gemini catalog /v:models already ranks); curated + user-overridable stays the flow, now pointing at the real command for manual discovery.
  • Every doc stating the codex model map as current fact updated for consistency (v-init.md seed, v-models.md roster/table/example, routing-policy.md map/resolve-example, execution-manifest.md tier table/config example). Illustrative "(e.g. gpt-5.5)" mentions explaining the resolution mechanism (never hardcode a model — the resolver handles it) and the dated routing-lessons.md historical entry were deliberately left untouched. Codex cross-model verification caught one real misscompound-v-resolve-model.py's own source comment still said "cursor-agent has no models list command" (I'd audited the .md docs for this false claim but missed the .py comment) — fixed; a second pass confirmed every codex tier mapping, the review-script default, and every version pin consistent, with no remaining stale gpt-5.5/gpt-5.3-codex-spark current-default claims.

[2.6.2] — 2026-07-06

Fixed — .claude/compound-v.json no longer commits machine-local capability

  • Closed a real downstream-repo review comment: a teammate flagged the committed .claude/compound-v.json as looking like it should be gitignored. The diagnosis: the file mixed genuine team policy (stance, models, memory, epic, review, workflows_accelerator — correct to commit) with a machine-local capability snapshot (backends, checked_at — "which CLI/MCP tools were detected on the machine that last ran /v:init") — a fact about one developer's machine, wrong the moment a teammate with a different local setup opens the file.
  • The fix removes backends/checked_at from the committed file — no new file needed. A correct, already-uncommitted home for exactly this data already existed: ~/.claude/compound-v-capabilities.json (/v:init Step 4b, user-home-scoped, already documented as "reused across repos"). backends was pure redundancy with it.
  • Audited before touching anything: compound-v-resolve-model.py's load_config_models() reads only the models key; a full-repo grep found zero programmatic readers of backends/checked_at — actual backend availability is already re-probed live at dispatch time (the env-aware codex→claude fallback). So this is a hygiene/trust fix, not a routing-behavior change — nothing about dispatch logic changed. Backward-compatible: an existing committed file with the old fields is simply ignored, no migration needed.
  • commands/v-init.md Step 4a and commands/v-models.md Step 3 updated (write path + example JSON + an explicit "why" note at the canonical source). Codex cross-model verification: ACCURATE — independently confirmed load_config_models() reads only models, zero remaining backends references anywhere in the repo, the sole remaining checked_at is correctly inside the Step 4b capability-cache shape, and the Step 4b cache fully covers the old capability role.

[2.6.1] — 2026-07-06

Fixed — worktree git-base fixes are the caller's job, never the worker's

  • Closed a real incident from a downstream repo: a parallel-dispatch batch assigned a job to Codex, but the job's worktree needed its git base fixed — Codex's sandbox is confined to $WT, while the worktree's actual git metadata lives outside it, in <repo>/.git/worktrees/<job-id>/, and approval_policy: never means it can't ask to escalate. A sandbox limitation, not a code one. The orchestrator worked around it by dropping worktree isolation for Codex — which is not a fix: it removes the only file-scope enforcement Codex has (codex ⇒ worktree is a hard invariant in compound-v-validate-manifest.py precisely because Codex can only be confined to a directory, never a file allow-list), and risks interleaved writes if other jobs are running concurrently in the same tree.
  • The correct fix, now explicit: every dispatch or retry of an external worker (Codex/Antigravity/Cursor) goes through the full worker-script lifecycle, which already recreates the worktree fresh at current HEAD every time — never patch an existing worktree's git state, and never delegate that patch to the worker itself. A job that needs another job's already-landed output must model that as depends_on in the manifest, not discover it mid-run.
  • New SKILL.md §Worktree git-base fixes (the shared, mechanism-level explanation), a cross-reference in adapter-codex.md, and explicit language in parallel-dispatcher.md's isolation step and its retry line (which previously just said "re-dispatch the same backend" without specifying the worktree is recreated fresh — the exact ambiguity that let the workaround slip through). Docs-only; no code changed.
  • Codex cross-model verification, two rounds, caught real gaps in the fix itself. Round 1 confirmed the core sandbox mechanism but found the depends_on guidance overclaimed: merge-back only stages a job's changes (git apply --index) — it never commits, so HEAD doesn't move, and a dependent job's "fresh worktree at HEAD" would not contain a prerequisite's merged-but-uncommitted work. Fixed: parallel-dispatcher.md Step 1 now requires the caller to verify Task 0's result is actually committed (for both direct and worktree isolation) before Step 2 begins — the missing link between depends_on and a correct fresh-worktree baseline. Round 1 also flagged an overclaim that Codex "cannot touch outside metadata even with --dangerously-style flags" — narrowed to the documented pinned invocation only. Round 2 confirmed the round-1 fixes, then caught one more: the wording assumed a direct-isolation implementer always commits its own work — adapter-claude.md establishes only that it writes against the main tree, not that it commits — fixed to an explicit caller-side verify-and-commit step for both isolation modes. Two full review rounds, three real corrections, all fixed.

[2.6.0] — 2026-07-06

Added — pr-review skill + /v:pr-review command

  • pr-review skill — a two-axis, stack-agnostic deep code-review skill for a pull/merge request or a local diff. It first builds shared understanding of the change's intent, then hunts bugs and edge cases along two deliberately separate axes run as context-isolated sub-agents so neither pollutes the other: Standards (does the code follow this repo's documented conventions, discovered in a Phase-0 sweep?) ⊥ Spec (does it faithfully implement the originating spec/issue/PRD?). Findings are reported side by side, never merged across axes; genuine author-intent unknowns are promoted to Open Questions; every finding carries a verdict + confidence. Review-only — it never edits, commits, pushes, or merges code. Ships SKILL.md + four references/ (exploration checklist, review domains, findings format, comment-posting).
  • /v:pr-review command — a thin entry point in the /v:* family that runs the skill. Argument = PR/MR URL or number; empty = current branch vs. its base. Auto-detects the host: GitHub (gh), GitLab (glab), or a hostless local diff.
  • Self-contained — no new runtime deps, hooks, or scripts; frontmatter within the linter's limits and all intra-plugin .md cross-refs resolve.

[2.5.5] — 2026-07-05

Performance

  • Dense search: repeated queries skip the model load. Every dense search paid one isolated-venv subprocess = one ONNX model load per query (seconds). A new query_cache SQLite table (sha256(query) + model → vector, IF NOT EXISTS so no migration, bounded to the 500 most-recent rows) lets a repeated query — the common case for /v:remember and the recall→action bridge's templated queries — return in milliseconds. A model change misses by key; identity drift (embedder revision change) clears the cache alongside the corpus re-embed, so a stale-revision vector is never served; any cache error falls back to embedding (the cache is an optimization, never a failure mode). Selftest proves hit / miss / model-miss / failed-embed-not-cached with a counting fake embedder. Profiled first: the FTS5 lane (rebuild 0.7 s, search 0.28 s, hooks ≤0.25 s) was left untouched — already fast. Codex cross-model verification caught the stale-vector hazard — the (query, model) key alone can't see an embedder revision change (the same drift the corpus re-embed handles), independently confirming the author's own finding — fixed via _invalidate_query_cache on the drift branch, plus the extra coverage Codex asked for (different-query miss, cache bound, drift invalidation): 7 cache checks total, all green.

[2.5.4] — 2026-07-05

Performance

  • V-memory DENSE refresh now loads the embedding model once, not per file. The refresh embedded per file — reindex_file invoked the isolated-venv embedder subprocess once per file, and each subprocess rebuilt the ONNX InferenceSession, so N files meant N model loads (the reason the first full pass over docs/superpowers/** was slow). cmd_refresh now uses a new reindex_batch that chunks all to-index files, flattens their chunks into one embedder call, and slices the vectors back per file — one model load per refresh. The FTS5-only (embeddings-off) path is unchanged and it stays degrade-safe (a failed batch persists NULL embeddings → FTS5-only; the CORE lexical lane is never affected). Selftest injects a call-counting fake embedder proving the single call + correct per-file vector slicing + degrade — no network/model needed. Codex cross-model verification: ACCURATE on all five claims with file:line evidence (single call, offset slicing with no off-by-one, empty-corpus skips the model load, degrade-safe NULL fallback, atomic persistence preserved).

[2.5.3] — 2026-07-05

Added — npx autoskills recommender for /v:onboard

  • Third-party skill discovery. /v:onboard now recommends npx autoskills when a project manifest is detected — a new recommend-autoskills subcommand in scripts/compound-v-onboard.py flags applicability (package.json, pyproject.toml, requirements.txt, Gemfile, go.mod, Cargo.toml, composer.json, pom.xml, build.gradle, or a top-level *.tf), with the marker file as evidence; an unknown repo yields applicable: false (no false recommendation).
  • Present-only, gated --dry-run, never auto-installs. In DIAGNOSE, onboarding surfaces the recommendation and — behind a human confirm — runs the preview npx autoskills --dry-run through the process-group timeout supervisor with stdin </dev/null (the v2.5.0 external-launch invariant), to show which skills it would install. The real install stays the user's own action (autoskills has its own confirm + SHA-256 verification).
  • Auto-trigger-degradation caution. Because mass-installing overlapping skills degrades auto-triggering across the whole skill set (the onboarding Skills stance), the recommendation always carries a loud caution to review the dry-run and prefer a focused subset.
  • Built with TDD, dogfooded, cross-model Codex-verified. 5 selftest checks (manifest → applicable + evidence + --dry-run command; empty → not applicable; pyproject.toml → applicable; a top-level main.tf → applicable with the filename as evidence; a directory named *.tf → not applicable). Dogfood on superpowers-v itself (no standard manifest) → applicable: false — the negative path. Codex cross-model verification (the model that writes ≠ the model that checks) caught two real bugs in the Terraform branch — the evidence was the literal "*.tf" instead of the actual filename, and a directory named foo.tf was a false positive — both accepted and fixed, each with added selftest coverage.

[2.5.2] — 2026-07-03

Added

  • Compound V Academy — a gamified 3-episode tutorial (Developer · Product Owner · Universal Creator) is now linked prominently from the README: https://amiainative.dev/compound-v. The fastest way to learn the whole pipeline (onboarding → the three scouts → dispatch → the review gates), with the squad as guides.

Fixed

  • Scope gate: bracketed path segments are literal. [locale] / [uid] / [slug] in a write_allowed glob were parsed as fnmatch character classes ([locale] = "one of l,o,c,a,e"), which falsely BLOCKED any Next.js App Router write scope (e.g. app/[locale]/…/[uid]/page.tsx) and raised a regex FutureWarning. Bracketed dynamic segments — the dominant real-world case — now match literally; the selftest covers the App Router case positive + negative. (scripts/compound-v-scope-check.py)
  • /v:review-plan schema resolves from the plugin, not the reviewed repo. The cross-model review script defaulted its JSON-schema path to $REPO/schemas/… (the reviewed repo), so /v:review-plan died with "schema not found" in every project except this one. It now resolves the default schema next to the script (its install dir); the --schema override is unchanged. (scripts/compound-v-codex-review.sh + new regression test)

[2.5.1] — 2026-07-01

Added — MCP / external-tool recommender for /v:onboard

  • /v:onboard now recommends the right external tools for your stack — a new recommend-mcp subcommand in scripts/compound-v-onboard.py maps repo signals → tools from a curated, currency-verified table, with a deliberate CLI-over-MCP bias: a github.com remote yields the gh CLI, never a GitHub MCP server (avoids the broad-PAT toxic flow). Rows: Supabase MCP (--read-only --project-ref), Postgres MCP (--access-mode=restricted), Playwright MCP (pinned >=0.0.40, CVE-2025-9611), Context7, Sentry — every MCP row ships least-privilege flags pre-filled.
  • .mcp.json via diff + confirmation, never auto-apply. mcp_json_config() builds the config from the confirmed MCP recommendations, merged additively — it never clobbers an existing same-named server, and CLI recommendations (gh) are surfaced as setup instructions, not .mcp.json entries. The write is a gated WRITE-step artifact behind the human approval gate.
  • Lethal-trifecta warn-only. Any private-data + untrusted-content + external-write server (Supabase / Postgres) emits a named warning with a specific remedy (read-only + dev/branch-scoped + single-repo session). Read-only defaults defuse most at the source; no hard refusal — the user decides.
  • Deterministic + evidence-cited + honest. The table is a static curated map (no model guesswork on tool names/flags); each recommendation cites its triggering signal; an unknown stack yields an empty set (no invented tools). Currency (packages / flags / CVE pin) was WebSearch-verified 2026-07-01.
  • Built with TDD, dogfooded, cross-model Codex-verified. 21 selftest checks (github→gh CLI, Supabase read-only, Postgres restricted, fast-moving→Context7, Playwright, citation-grade evidence, trifecta warning, additive-merge, no-clobber, empty-on-unknown, Postgres DSN, existing-server warning). Dogfood on superpowers-v itself: exactly one recommendation (github → gh CLI), no false MCPs, empty mcpServers (the negative path). Codex cross-model verification (the model that writes ≠ the model that checks) caught three real spec/impl gaps the Opus author missed — a Postgres DSN (no pg dep) went undetected, evidence wasn't file:line citation-grade, and trifecta warnings skipped existing .mcp.json servers — all three accepted and fixed, each with added selftest coverage.
  • Onboarding scope: .mcp.json / MCP recommender moved from fast-follow to in-scope; .claude/rules/*.md (→ future) and bulk skill generation (deliberately avoided) stay out.

[2.5.0] — 2026-07-01

Added — hang detector (liveness probe + dispatcher sweep + enforced external launch)

  • Liveness probe — scripts/compound-v-liveness.py. Classifies each running job in a run's state.json from git + filesystem only (never model-self-report — same ethos as the scope gate): LIKELY-DONE (the worktree has a commit past its recorded baseline — the work landed and only the completion notification is stuck), STALE (no working-tree progress past the threshold — a suspected hang), WORKING, DEAD (a recorded pid died with no progress), and UNKNOWN (degrade-safe — a missing/unreadable signal never crashes the probe). .git is excluded from the mtime walk so a commit doesn't mask staleness. Stdlib-only; --selftest (12 checks) covers every class with real git/fs/pid fixtures; exit 3 when any job is STALE/DEAD.
  • /v:status gains a Liveness column — every running job shows its class + a hint (LIKELY-DONE → /v:resume / auto-collected, STALE → suspected hang). Degrade-safe: a probe error shows and never breaks the table.
  • Dispatcher liveness sweep (parallel-dispatcher Step 2d). Between batches — and while awaiting a background job whose completion notification never arrived — the dispatcher runs the probe and acts: LIKELY-DONE → collect now (scope-gate + merge + done), ending the "nudge the dispatcher by hand" failure mode a parked subagent caused; a STALE/DEAD external worker → the existing timeout failure-policy (retry cap, then halt — no new mechanism); a STALE Claude subagent → surfaced (the harness owns the kill), reclassifying LIKELY-DONE once its commit is observed. No new phase, no daemon; documented in state-machine.md + failure-policy.md.
  • Fixed — the one uncapped external-launch path. scripts/compound-v-codex-review.sh (the cross-model plan review) capped its codex exec via a timeout/gtimeout binary only when one was installed (no binary ⇒ no cap) and signalled only the direct child. It now runs under the shared process-group supervisor compound-v-run-with-timeout.py (guaranteed hard cap + whole-group kill), matching the three worker scripts. This closes the gap behind a real 44-minute hang this cycle (an ad-hoc codex review that had no cap and blocked on stdin).
  • Enforced-launch invariant (backend-launcher/SKILL.md). Every external-CLI invocation — dispatched worker OR orchestrator-level (cross-model review, ad-hoc verification) — MUST run through compound-v-run-with-timeout.py with stdin </dev/null; a bare codex/cursor/agy call is a bug. The probe detects a hang after the fact; this rule prevents it.
  • Anti-over-engineering. Archaeology confirmed the three worker scripts already enforce supervisor + </dev/null and run synchronously under the hard cap, so the probe deliberately does not police external workers or add pid bookkeeping — its unique, non-redundant value is the Claude-subagent LIKELY-DONE/STALE case that nothing caught before. ~200-line stdlib probe, one purpose; no daemon, no new deps.
  • Built directly with TDD, dogfooded live. The probe was proven end-to-end on a fabricated run with a real git worktree: a parked job (worktree committed past baseline) classified LIKELY-DONE, a 40-minute-idle worktree classified STALE, a fresh one WORKING, a done job skipped — exit 3 as designed. Full regression (6 script selftests + banner + frontmatter lint + CI version-lockstep) green.
  • Cross-model Codex verification earned its keep. A GPT reviewer (the model that writes ≠ the model that checks) adversarially reviewed the probe and caught four real issues the Opus author missed: LIKELY-DONE using HEAD != baseline instead of git ancestry (a reset/checkout would read as done), _pid_alive misreading EPERM (an alive-but-unsignalable process) as dead, _newest_mtime following symlinks (os.statos.lstat), and a stale bare-timeout … codex exec example in SKILL.md contradicting the new launch invariant. All four accepted and fixed, each with added selftest coverage (15 checks, green).

[2.4.0] — 2026-07-01

Added — stance-aware models map (cost-aware routes Claude standard → Sonnet 5)

  • Tier→model resolution is now stance-aware. The cost-aware stance routes Claude standard-tier implementers (core_slice, tests_new) to Sonnet 5 (via the native sonnet alias — no concrete ID pinned); balanced (the default) is unchanged (standard → opus). Exactly one built-in cell changed: cost-aware.claude.standard opus → sonnet. cost-aware.claude.deep stays opus; the codex/antigravity/cursor maps are identical across stances.
  • Resolver (scripts/compound-v-resolve-model.py). DEFAULT_MODELSDEFAULT_MODELS_BY_STANCE keyed by stance (with a derived DEFAULT_MODELS = DEFAULT_MODELS_BY_STANCE["balanced"] alias so existing references are untouched). New --stance flag (default balanced); stance is a trailing kwarg on resolve() so every existing caller is unbroken. VALID_STANCES is re-declared locally (mirrors compound-v-validate-manifest.py, no shared import).
  • Config backward-compat. .claude/compound-v.json models accepts BOTH the legacy flat shape {backend:{tier:model}} (applied to every stance) and a new per-stance shape {stance:{backend:{tier:model}}}, discriminated by whether every top-level key is a stance name. Existing seeded configs keep working unchanged.
  • Every Claude-model-resolving call site threads --stance <routing_stance>parallel-dispatcher (the batch resolve and Task 0), phase-3-parallel-opus-dispatch, adapter-claude, /v:status (its per-job model column — without the flag it would display opus for a job that actually dispatches as sonnet under cost-aware), and the /v:models verification loop. No flag ⇒ balanced (current behavior).
  • partition-reviewer stance-gate. Under cost-aware, a standard-tier Claude Sonnet implementer is the routing-policy default and is exempt from the 8-box SONNET_UNJUSTIFIED junior-task check; balanced/conservative/claude-only apply the check as before. Invariants hold in every stance: reviewers ⇒ deep ⇒ opus, sensitive (auth/payments/PII/a11y) ⇒ deep ⇒ opus, the light-tier Sonnet check, and never Haiku. The deterministic validator is unchanged — it never adjudicated implementer Sonnet eligibility.
  • Fixed — version lockstep (marketplace.json). .claude-plugin/marketplace.json had lagged at 2.1.1 while plugin.json advanced to 2.3.1 (the 2.3.0 and 2.3.1 releases bumped only plugin.json), which the CI lockstep check in .github/workflows/validate.yml flags as a mismatch. Both are now bumped in lockstep to 2.4.0, greening CI.
  • Built by Compound V, dogfooded, cross-model verified. Implemented through the plugin's own /v:dispatch pipeline (5 jobs — resolver serial spine + 3 parallel worktrees + integration review; git-derived scope-gate PASS on every job; 3-pass Review Gate APPROVED, 5/5 acceptance criteria). The new behavior was dogfooded live: a cost-aware manifest with a standard-tier Claude job resolved to Sonnet and passed partition-review with no SONNET_UNJUSTIFIED flag, while the deep reviewer stayed Opus. Codex cross-model verification (the model that writes ≠ the model that checks) returned ACCURATE on all seven claims with file:line evidence (incl. cost-aware.claude.deep stays opus, the config-shape discrimination, and fail-closed resolution).

[2.3.1] — 2026-06-30

Added — model visibility in the dispatch tree

  • The dispatch tree and /v:status now show the resolved model per job. parallel-dispatcher announces each batch as a tree annotated with backend · model (tier/effort) (resolved via scripts/compound-v-resolve-model.py before dispatch), and /v:status gains a Backend · Model column — so it is always visible which model each job runs on, both live during dispatch and after the fact.

Note — Claude Sonnet 5

  • Claude Sonnet 5 (claude-sonnet-5, released 2026-06-30) is picked up automatically wherever Compound V routes to the sonnet tier alias (the light tier on the Claude backend) — the resolver intentionally emits native tier aliases (opus/sonnet), so the new model flows in with no code change. Routing more work to Sonnet 5 (it benchmarks close to Opus 4.8 at lower cost) is a deliberate routing-policy change tracked for a future minor (a cost-aware-stance standard → sonnet route), not a silent default shift — the default stays Opus by default, reviewers always Opus, never Haiku.

[2.3.0] — 2026-06-30

Added — /v:onboard (project onboarding → trusted, citation-verified knowledge base)

  • New /v:onboard command — studies an existing repo and builds a trusted knowledge base (docs/superpowers/architecture/{architecture,business-logic,tech-context}.md) plus cross-tool agent instructions (root CONVENTIONS.md, AGENTS.md as the portable source of truth + a thin @AGENTS.md CLAUDE.md bridge, conditional DESIGN.md for UI repos), all behind a human approval gate, then feeds them into V-memory. Authority doc: skills/compound-v/onboarding.md; thin command: commands/v-onboard.md. /v:onboard --refresh re-checks cited-evidence staleness.
  • Deterministic toolkit scripts/compound-v-onboard.py (stdlib-only): pack (repo pack-manifest + advisory secret scan), verify-citations (the two-tier gate), staleness (cited-evidence drift + uncited-new-file heuristic), design-lint (wraps npx @google/design.md), detect-ui, scan-output.
  • Two-tier citation gate (anti-hallucination). Tier-1 (cited path resolves + 1 ≤ start ≤ end ≤ lineCount) is mechanical and blocks 100% of claims; Tier-2 (do the cited lines actually support the claim?) runs on 100% of load-bearing claims (security / fail-closed / concurrency), where an unsupported load-bearing claim is BLOCKING. Generation defaults to read-then-cite. (Live feasibility probe on this repo: read-then-cite scored 23/23 path/range/support under an adversarial verifier; naive free-write failed to even produce valid structured output.)
  • Untrusted-input rule. Any existing instruction file (AGENTS.md / CLAUDE.md / GEMINI.md / cursor / windsurf / copilot rules) is treated as evidence to quote and summarize, never a directive to execute during onboarding; the managed-policy layer is informational-only.
  • Secret-scan granularity (input advisory, output blocking). The pack input scan is advisory — it surfaces secret-shaped strings anywhere in the repo (test fixtures, security docs) at the human gate but does NOT halt the run. The blocking refusal is scan-output, run on the GENERATED docs only, enforcing the invariant "no credential reaches a generated, committed file." (Caught while dogfooding: the input scan reports ~40 benign false positives on this very repo — the plugin's own selftest fixtures and secret-scanning scripts — which a repo-wide hard block would have wrongly halted on.)
  • V-memory engine extension (scripts/compound-v-memory.py). tracked_files() now also indexes root AGENTS.md / CLAUDE.md / CONVENTIONS.md / DESIGN.md via a scoped second git ls-files union (DOCS_REL not widened, fail-closed [] on git error preserved); doc_type_for() gains clean labels for them. (Cosmetic: until the first refresh after upgrade, search may report "N new behind".)
  • /v:init + SessionStart banner. /v:init's closing report now suggests running /v:onboard; the banner gains a read-only, fail-silent staleness line ("N architecture docs stale vs HEAD → run /v:onboard --refresh") guarded so it can never abort the banner under set -euo pipefail.
  • Built by Compound V, dogfooded on itself. Implemented through the plugin's own /v:dispatch pipeline (5 jobs, all Opus, scope-gate PASS on every job, one transient Overloaded auto-retried, 3-pass Review Gate APPROVED 6/6), then /v:onboard was run on superpowers-v itself (51 claims, all 11 load-bearing passing Tier-2 ok:true, output secret gate clean, DESIGN.md correctly skipped on the no-UI repo). This release ships alongside the repo's own generated knowledge base and the CLAUDE.md bridge it previously lacked.
  • Dependencies verified current (2026-06-30): @google/design.md v0.3.0 (lint real, JSON findings + WCAG), repomix v1.16.0 (Secretlint secret-scan built-in). Deliberately fast-follow / out of v1: the MCP recommender (and per the maintainer, GitHub is used via the gh CLI, not a GitHub MCP server), path-scoped .claude/rules writing, and bulk skill generation.

[2.1.1] — 2026-06-27

Fixed — Cursor worker hardening (all caught by live verification, not self-tests)

  • Process-tree timeout supervisor (scripts/compound-v-run-with-timeout.py) — adopted by ALL three external workers (cursor, codex, antigravity). These backends previously capped via an external timeout/gtimeout (or a bash watchdog), which signals only the direct child — a tool/shell child the agent spawned could outlive the cap and write after the scope gate (the exact leak the gate exists to stop). The new supervisor starts the command in a new session (setsid) and on expiry killpgs the whole process group (SIGTERM → grace → always SIGKILL — a descendant that ignores SIGTERM is still reaped) → status: timeout (124). It holds no copy of the command's output fds, so a hung child can't hang the dispatcher's $(…) capture. Proven by --selftest (a descendant — incl. one that traps SIGTERM — that tries to write after the cap is reaped first; the write never lands) and live success + --timeout-sec 1 ⇒ status:timeout through all three workers. --timeout-sec must be > 0; --grace >= 0. (Limitation: a descendant that itself setsids into a new session escapes — true containment needs cgroups/job-objects; backend tool children don't daemonize.)
  • Fixed a dispatcher-hang in the watchdog. The watchdog subshell inherited the worker's stdout, so its sleep held the dispatcher's $(...) capture pipe open — every Cursor dispatch hung for the full timeout after the job finished. The watchdog's fds are now redirected to /dev/null and its sleep child is reaped. Verified: worker E2E back to ~29 s (was hanging ~600 s).
  • Cursor model default is now auto. A Cursor Free plan can only use Auto — passing a named model (sonnet-4 / gpt-5 / …) errors with "Named models unavailable." resolve-model now maps every Cursor tier to auto (works free and paid); named per-tier ids are a paid-plan opt-in via /v:models / config. /v:init Step 1e detects timeout/gtimeout and warns when the Codex worker would have no hard cap.
  • New regression coverage: a full-pipeline seam test (validate-manifest → cursor worker → merge-back git-apply) — 8/8 live, verifying the merge-back path the isolated worker test never exercised.

[2.1.0] — 2026-06-27

Added — Cursor CLI backend (4th dispatch backend)

  • cursor-agent as a headless dispatch backendscripts/compound-v-run-cursor-worker.sh, a Bash-spawned worker in its own git worktree that mirrors the Antigravity adapter (worktree isolation + git-derived scope gate → canonical job_result). Verified live (cursor-agent 2025.09.12): the success path (write within write_allowed) and the BLOCKED path (write outside scope → violations) both pass.
  • Invocation (verified): cd "$WT" && cursor-agent -p -f --output-format json [--model M] "<prompt>" </dev/null. -f is required — a headless run refuses an untrusted worktree without it. Output is one JSON object: .resultsummary, .session_id (a real UUID) → resumable via cursor-agent --resume. Token .usage is ignored (anti-ruflo).
  • Lower-trust / opt-in — same tier as Antigravity. No kernel write-confinement (-f grants arbitrary write+shell); the git-diff gate is detection, not prevention. Prefer Codex (kernel-sandboxed) for untrusted / high-stakes work; backend: cursorisolation: worktree.
  • Plumbing: classify-failure.py --backend cursor (OpenAI/Anthropic-style needles + provisional cursor-auth); resolve-model.py cursor map (sonnet-4-thinking / sonnet-4 / gpt-5, user-overridable via /v:models); adapter-cursor.md runbook; /v:init detects cursor-agent + auth and adds it to backends. Available only when installed AND authenticated (env-aware routing).

[2.0.0] — 2026-06-27

Added — V-memory (local-first recall over docs/superpowers prose)

  • V-memory — a local-first RECALL layer over the docs/superpowers/** prose (a new subsystem, hence the major bump). It extends the existing two-half memory (machine-generated task-outcomes.jsonl/scorecard + human-curated routing-lessons.md) and never rewrites them; recall is EVIDENCE for planning + review, NOT a routing input — routing stays the deterministic v1.1 order (routing-lessons.md → stance table → conservative scorecard → fallback → invariants). Engine: scripts/compound-v-memory.py. Authority doc: skills/compound-v/memory.md.
  • Two lanes — CORE always on, DENSE opt-in. CORE is SQLite FTS5 BM25 over the git-tracked prose (pure stdlib, the default, always on). DENSE is opt-in embeddings (multilingual-e5-small) used in a rank-union with FTS5, scale-gated, and degrade-safe — when the embeddings are absent or broken the engine silently falls back to FTS5-only. The DENSE venv lives OUTSIDE the repo (~/.cache/compound-v/memory/<repo-id>/) and is bootstrapped only by an explicit command — never on its own.
  • Embeddings are PURE PYTHON. fastembed (onnxruntime + tokenizers) — NO Node, no daemon, no external vector-DB service, no fabricated metrics.
  • One deterministic, conservative-only recall→action bridge — recall-check --files <glob>. It counts prior job_result records (status in {blocked, error, timeout} / scope violation) on the same file pattern; N ≥ k (default 2) yields the verdict tighten (force worktree / add a review pass / fold into Task 0). It never reroutes to lower trust and never loosens — the prose analogue of the scorecard's unhealthy → escalate.
  • Two new commands/v:remember (recall search) and /v:memory-refresh (index / bootstrap).
  • /v:init now configures recall + autonomy (structured questions → .claude/compound-v.json, honored by the engine/skills): the recall lane (memory.embeddings, FTS5 vs opt-in embeddings — the engine adds vectors automatically when on and bootstrapped), the memory autonomy level (memory.auto_recall / memory.auto_tighten), the epic-autonomy cadence (epic.max_features), and an automatic cross-model review default (review.cross_model).
  • New hook — hooks/memory-refresh.sh. Silent, self-backgrounds an FTS5-only refresh, never installs/bootstraps; appended to SessionStart + PostToolUse:Write.
  • Key invariants (all enforced): the cache lives outside the repo; only git-tracked prose is indexed; the FTS5 lane is crash-safe; writes use flock + a transaction; hooks never bootstrap the DENSE lane.
  • New surfaces: engine scripts/compound-v-memory.py; authority doc skills/compound-v/memory.md; commands commands/v-remember.md + commands/v-memory-refresh.md; hook hooks/memory-refresh.sh.

[1.2.0] — 2026-06-27

Changed — Epic mode hardening (closes the gaps a re-review of v1.1 surfaced)

  • Specs are batched UP FRONT — the autonomy-vs-quality tension resolved. The epic now brainstorms a real spec file per feature before the autonomous loop (the one human-interactive phase, approved once), carried as a spec_path on every feature in features.json/epic-state.json. The loop runs each feature from its pre-approved spec and never pauses to brainstorm. compound-v-epic-state.py --init --require-specs refuses to start unless every feature has an existing spec_path — deterministic enforcement, not just prose.
  • Decomposition review gate (one level up from partition-review). compound-v-epic-state.py --lint --features F.json flags structural smells in the feature DAG — an ISLAND feature (no depends_on and no dependents → a likely missed dependency) and an over-coupled feature (depends on most others → a layer, not a vertical slice) — plus hard validation, before any build. A weak decomposition is the #1 way an epic fails downstream.
  • Autonomy budget / checkpoint. An epic is N full v1.0 runs, so it runs under a MAX_FEATURES budget per /v:epic invocation (default 1): after the budget is spent it STOPS and reports --stats (done/remaining) for the human to review and re-run — a real cost ceiling + human-in-the-loop point, not an unbounded autonomous burn.
  • Reconcile-by-resume — no discarded work. A feature stuck running (crashed mid-pipeline) is reconciled by running its own /v:resume <run-id> first (re-dispatch only that run's incomplete jobs), falling back to full restart (pending) or failed only if it can't recover — composing with the per-feature crash-resume instead of throwing away half-built work.
  • compound-v-epic-state.py gains --lint, --stats, --require-specs, and a spec_path field (21-case self-test, up from 12). Docs: commands/v-epic.md + skills/compound-v/epic-mode.md rewritten to the batched-spec, budgeted, decomposition-gated, resume-reconciling workflow.
  • Validated end-to-end: a real 2-feature epic (corecli, dependency-ordered) driven through the full loop with live Codex workers — batched specs → --lint--init --require-specs → topological build accumulating on one branch → the integrated app runs (python cli.py → 5, cli importing core's code) → fail-fast halt on a scope-blocked feature → reconcile drill — all behaved correctly.

[1.1.0] — 2026-06-27

Added — Epic mode (multi-feature autonomous build)

  • Epic mode — chain multiple plan-runs into one autonomous, resumable, dependency-ordered multi-feature build (PRD §8). A v1.0 run executes ONE plan (one feature); an epic chains several — an ordered set of features, each run through the FULL v1.0 pipeline (spec → 3 pre-flights → writing-plans + partition → manifest → dispatch → 3-pass review) in dependency order, accumulating onto one branch ("build a whole app"). It is the same discipline one level up — resumable, topological, no daemon. scripts/compound-v-epic-state.py is the deterministic state spine over epic-state.json (one level up from state.json): --init validates feature ids/refs/cycles and writes every feature pending; --next returns the next runnable feature (pending with all depends_on done, in topological order) or a stop reason (runnable|epic complete|epic blocked|epic needs reconcile) — the loop is fail-fast (any failed feature halts the whole epic, even independent pending ones, until reconciled) and reconcile-strict (a running feature seen between features means a prior run crashed → reconcile via --update --status pending|failed before continuing, never an infinite wait); --update sets a feature's status/run-id and rolls up the epic status; --summary renders the feature table. The new /v:epic command (commands/v-epic.md) is the driver: it resolves the epic brief into a feature list ({id, title, depends_on}), inits or resumes from docs/superpowers/execution/epics/<epic-id>/epic-state.json, loops --next → run that one feature through the full v1.0 pipeline → --update --status done --run-id <run-id>, then on epic complete runs a final cross-feature integration review (the whole accumulated diff against the epic's acceptance criteria) and hands to superpowers:finishing-a-development-branch; on epic blocked it stops, surfaces the failed feature, and stays resumable (re-run /v:epic after a fix). Every per-feature concern is reused unchanged (scope gate, model-broker, failure-handling, scorecards). Honesty boundary, stated loudly: epic mode is autonomous chaining, not "guess a product from one sentence" — each feature still needs a real spec; large epics run sequentially feature-by-feature (parallelism is within a feature, no cross-feature parallel dispatch in v1.1); quality is bounded by per-feature spec + partition quality. Docs: skills/compound-v/epic-mode.md (the model, the resumable run-dir layout, the integration review, the honesty boundary); skills/compound-v/SKILL.md lists epic mode as a capability.

Added — Antigravity backend adapter (promoted from 1.0 stub)

  • Antigravity (agy) is now a real backend, not a stub. A Bash-spawned agy --print worker (scripts/compound-v-run-antigravity-worker.sh) that mirrors the Codex worker: runs one file-scoped job inside a dedicated $TMPDIR git worktree at HEAD, then emits the canonical job_result. Same CLI shape as the codex worker (--run-id/--job-id/--repo/--prompt-file/--model/--write-allowed/--timeout-sec/[--read-only]/[--network]/[--output-schema]), same id-safety + timeout-int guards, same delegation to the deterministic scope gate scripts/compound-v-scope-check.py for git-derived enforcement (baseline SHA captured before worktree add so an in-worktree commit can't hide changes), and the same fail-closed status + failure_class/retry_after_seconds emit. Verified live against agy 1.0.13: cd "$WT" && agy --dangerously-skip-permissions --add-dir "$WT" --print-timeout "<sec>s" [--model …] --print "<prompt>"flag order is load-bearing (--print MUST be last; its value is the prompt). Summary comes from agy's printed stdout; session_id is "" (agy exposes no resumable session UUID). --model is optional (omitted when empty); --read-only/--network/--output-schema are accepted for CLI parity but advisory/ignored (agy has no kernel sandbox toggle or output-schema flag).
  • ⚠️ Lower-trust, opt-in backend (documented loudly). Unlike Codex's --sandbox workspace-write (a kernel-level write-confinement root), agy has NO kernel write-confinement, and headless writes require --dangerously-skip-permissions — which lets the agent run arbitrary shell and write outside the worktree. The worktree + post-hoc git diff gate enforces file-scope inside the worktree (detection) but cannot prevent an out-of-worktree write/shell side-effect. So Antigravity is opt-in / lower-trust — prefer Codex (kernel-sandboxed) for untrusted / high-stakes work.
  • antigravity ⇒ worktree invariant added to scripts/compound-v-validate-manifest.py (mirrors codex ⇒ worktree): an external worker with no kernel sandbox must be worktree-isolated. New self-test: antigravity + isolation: direct → INVALID.
  • Failure classifier (scripts/compound-v-classify-failure.py) gains an antigravity backend with Gemini/agy error rules. Gemini reuses RESOURCE_EXHAUSTED for both quota exhaustion and per-minute throttling, so the out_of_credits needles are deliberately quota/billing/credit-specific (billing, exceeded your current quota, insufficient credit, …) — bare quota / exceeded your / usage limit are excluded so throttle text like "Quota exceeded for quota metric … per minute" or "exceeded your rate limit" classifies as rate_limited (transient retry), not out_of_credits (which would force a needless backend reroute); ambiguous exhaustion falls through to the safer rate_limited. Also auth (permission_denied/401/403), context_length, overloaded (503/500/unavailable), network. Self-tests cover the quota-vs-throttle split (per-minute quota → rate_limited; hard billing → out_of_credits; permission_denied → auth).
  • Model resolver (scripts/compound-v-resolve-model.py) carries a fallback antigravity map (deep → Gemini 3.1 Pro (High), standard → Gemini 3.1 Pro (Low), light → Gemini 3.5 Flash (Low)) used when no discovered map is present; the worker omits --model if the resolved value is empty. New self-test for antigravity/deep.
  • Docs: skills/backend-launcher/adapter-antigravity.md replaced the stub with the real adapter runbook (6 load-bearing steps, verified agy invocation + flag order, worktree + git-diff scope gate, no resume, and a prominent Safety section); skills/backend-launcher/SKILL.md updated (real adapter, lower-trust caveat); skills/compound-v/routing-policy.md lists antigravity as a selectable alternative for large_isolated (env-aware: only when agy is installed) with the antigravity ⇒ worktree invariant and the prefer-Codex safety note; commands/v-init.md detects agy and records it as a lower-trust backend.

Added — Antigravity model auto-discovery

  • Antigravity model auto-discovery. agy models </dev/null returns the live catalog headlessly (it just waits on stdin — the same </dev/null fix already used for agy --print; no TTY needed, ~2s), and scripts/compound-v-discover-models.py (pure parse + rank — the caller fetches the catalog and pipes it in; the script never calls a backend) ranks it into a deep/standard/light proposal written to .claude/compound-v.json (--write-config merges into the models.antigravity block, preserving the other backends). /v:models and /v:init use it — agy models </dev/null | python3 scripts/compound-v-discover-models.py --backend antigravity --write-config .claude/compound-v.json — so the tier map tracks the live catalog instead of a hand-curated list. Against agy 1.0.13 the proposal is deep: Gemini 3.1 Pro (High), standard: Gemini 3.1 Pro (Low), light: Gemini 3.5 Flash (Low). Corrected the earlier "agy models hangs / needs a TTY" claim — it does not; it is auto-discoverable headlessly.

Added — adaptive routing (worker scorecards)

  • Worker scorecards — a data-driven routing signal from measured outcomes (PRD §8). Routing was a static guess (a task-type → a fixed backend/tier, applied the same in every repo); scorecards make it adaptive. scripts/compound-v-scorecard.py deterministically aggregates docs/superpowers/memory/task-outcomes.jsonl into docs/superpowers/memory/worker-performance.jsonl — one row per (backend, type) with {total, success, blocked, error, timeout, avg_rework, block_rate, error_rate, success_rate, health}, where health ∈ {insufficient_data, healthy, watch, unhealthy} (a cell needs ≥5 samples to be judged; below that it stays insufficient_data). CLI: --update [--outcomes P] [--out P] regenerates the file; --query --backend B --type T prints one cell's stats + health. Before assigning a task-type's static-default backend, the router queries the measured health of that (backend × task-type) in this repo and acts on it: unhealthyescalate UP a fixed trust ordering (claudecodexantigravity) to an equal-or-higher-trust seat (Opus is the safe escalation) with a one-line justification — it never auto-routes to a lower-trust backend (a Codex-unhealthy cell escalates to Opus, never silently to Antigravity, which is explicit opt-in only); watch → keep the default but note it; healthy/insufficient_data → static default unchanged. Scorecards are a hint layered on the static policy, not a replacement, and only ever make routing more conservative (escalate up), never weaker — the HARD invariants (reviewers⇒opus, Codex⇒worktree, unclear⇒planning, sensitive surfaces⇒deep) are untouched. The scorecard never modifies the human-curated routing-lessons.md and emits no cost/token metrics (anti-ruflo). worker-performance.jsonl is machine-generated, regenerated each run by compound-v-scorecard.py --update after the dispatcher appends fresh outcomes — never hand-edited. Wired into agents/parallel-dispatcher.md (post-run memory step + per-job routing query), skills/compound-v/routing-policy.md (§Scorecard-aware routing), and skills/compound-v/SKILL.md (memory layout).

Hardened — cross-model review + worker robustness

  • Cross-model (Codex) adversarial review of the v1.1 diff, fixed to convergence. A read-only Codex gpt-5.5/high pass reviewed the new code over two rounds; every real finding was fixed: epic-state fail-fast + crash-reconcile semantics, scorecard trust-ordering (escalate up, never auto-downgrade to a lower-trust backend), and the classifier's quota-vs-throttle needle narrowing (all reflected in the entries above). Two findings were follow-up-tracked, then completed below.
  • Newline-safe path transport in both backend workers. compound-v-run-codex-worker.sh and compound-v-run-antigravity-worker.sh now pass the scope gate's .changed/.violations JSON arrays straight through (jq --argjson) instead of a newline-joined round-trip, so a filename containing a literal newline stays one element in files_changed/violations; the blocked decision keys off a gate-derived viol_count (a JSON [] is non-empty). The gate itself (compound-v-scope-check.py) was already NUL-correct, so the BLOCK decision was always right — this fixes the reported arrays. New scripts/test-worker-path-transport.sh self-test; fixed byte-identically in both workers.
  • TMPDIR / worktree-root canonicalization (both workers). Require an absolute $TMPDIR, canonicalize the tmp root up front and build the worktree parent from the real path, reject a symlinked parent, and assert the worktree lives outside the repo — defense-in-depth on the existing id-character + symlink-safe containment guards. The deterministic $RUN_ID/$JOB_ID worktree path is kept on purpose (resume/cleanup locate the worktree by it, so no random mktemp -d).

[1.0.0] — 2026-06-26

Compound V graduates from a description-driven skill-pack into a lightweight execution orchestrator. The three pre-flights and /v:archaeology are behaviourally unchanged; the orchestrator extends the tail of the flow (manifest → dispatch → scope-gate → collect → review → memory) with multi-backend execution, per-job isolation, and crash-resume. No daemon, no MCP server, no vector DB, and no fabricated token-cost metrics (the anti-ruflo charter). Built by dogfooding the Compound V pipeline on this repo.

Added — the orchestrator delta

  • Execution manifest (skills/compound-v/execution-manifest.md, examples/manifest.example.yaml). A machine-readable manifest.yaml of file-scoped jobs — backend · optional tier/effort · isolation · write_allowed/read_allowed · per-job and feature-level acceptance criteria — materialized from the verified Partition Map immediately after writing-plans. A job carries an optional tier + effort; model becomes an optional override. A job MUST have model or tier (backward-compatible: existing explicit-model jobs stay valid); reviewer jobs must resolve to tier=deep or model=opus. This is the contract between planner and executors.
  • Backend Launcher sub-skill (skills/backend-launcher/). One job_spec → job_result contract (schemas/job_result.schema.json) that every adapter implements; the orchestrator speaks only this contract and never sees backend-specific flags. Adapters: adapter-claude.md (Task-based, model override, maxTurns: 15), adapter-codex.md (headless codex exec in a git worktree), adapter-antigravity.md (stub — see dispositions below).
  • Headless Codex worker (scripts/compound-v-run-codex-worker.sh). Runs one file-scoped job on codex exec inside a dedicated $TMPDIR git worktree, then emits the canonical job_result. Verified against codex-cli 0.130: the flag set is --cd / --sandbox / --skip-git-repo-check / --model / --output-last-message / -c sandbox_workspace_write.network_access (plus optional --output-schema). --ask-for-approval never is invalid for codex exec and is omittedexec already defaults to approval: never. Resume is codex exec resume <uuid>. The cosmetic [features].codex_hooks is deprecated stderr is suppressed.
  • Scope gate (scripts/compound-v-scope-check.py). The deterministic authority behind the prose SCOPE LOCK. After every job it unions git diff --name-only <baseline> with git ls-files --others --exclude-standard and the gitignored set (git ls-files --others --ignored --exclude-standard -- .) and tests each changed path against write_allowed. A violation is BLOCKED — the job never merges and the run halts. Enforcement fields (files_changed / violations / blocked) are git-derived, never model-self-reported.
  • Manifest validator (scripts/compound-v-validate-manifest.py). A deterministic invariant gate the partition-reviewer runs: disjoint write_allowed, Codex⇒worktree, reviewers⇒Opus/deep, shared resources in the serial Task 0. Extended for the model-broker: tier ∈ {deep,standard,light} and effort ∈ {low,medium,high} when present, and every job must carry model or tier.
  • State machine + crash-resume (skills/compound-v/state-machine.md). A lightweight state.json (not an FSM engine) tracks phase + per-job status under docs/superpowers/execution/<run-id>/. /v:resume reconciles state.json against git reality (git-wins tie-break) and re-dispatches only pending/failed/blocked jobs. Resume lives in Engine A so it survives a hard crash.
  • Result collector + lean memory (scripts/compound-v-collect-results.py, scripts/compound-v-update-memory.py, docs/superpowers/memory/routing-lessons.md). Normalizes heterogeneous worker output into schema-conforming job_results, folds in the scope verdict, and appends one line per job to task-outcomes.jsonl. routing-lessons.md is human-curated. No semantic search, no scorecards in 1.0.
  • Routing policy (skills/compound-v/routing-policy.md). task-type → (tier, effort) + backend/isolation (no concrete model strings in the table). Balanced default; Conservative and Cost-aware stances; env-aware Claude-only fallback when Codex is absent. Documents the config models map, the resolver, and /v:models. Cites routing-lessons.md as a consulted input.
  • /v:init (commands/v-init.md). Detects Codex CLI / Context7 MCP / required skills, walks through any missing installs one at a time, re-probes the Codex flag set against codex exec --help, sets the routing stance, and saves config: project .claude/compound-v.json (stance + a seeded default models map so routing works out of the box — mentions /v:models for refresh/customization) + user ~/.claude/compound-v-capabilities.json (capability cache).
  • New commands /v:orchestrate, /v:collect, /v:status, /v:resume, /v:models (commands/).
  • Skill escalation policy (skills/compound-v/skill-escalation.md). Gated pull-in of deep-research / playground / avoid-ai-writing, plus forced Context7 — only when genuinely needed, each logged in the run's reasoning.
  • Strict job_result schema (schemas/job_result.schema.json) and committed fixtures (examples/) so CI validates real data.
  • New CI gates in validate.yml: schema validity, manifest-invariant check, collector schema-conformance, and a no-fabricated-cost-metric grep.
  • Cross-model plan review (optional, gated). A different model family (Codex/GPT) adversarially reviews a high-stakes plan/manifest before dispatch — the value is error decorrelation (a second Opus shares Opus's blind spots; Codex has different priors). Policy in skills/compound-v/cross-model-review.md; the read-only reviewer is scripts/compound-v-codex-review.sh, emitting findings against schemas/plan-review.schema.json. Advisory only — the orchestrator arbitrates every finding; Codex is never the authority. Gated by stakes (security/auth/payments/migrations/shared data model, large/coupled partition, architectural change, or human request); skipped for small/mechanical plans. Wired in after the partition-reviewer PASS in phase-3 and surfaced by the partition-reviewer agent; manually triggerable via the new /v:review-plan command.
  • Graceful backend-failure handling (classify → retry / reroute / halt). When a dispatched job returns non-success, the dispatcher runs a deterministic two-stage pipeline instead of guessing or blindly retrying. scripts/compound-v-classify-failure.py classifies the failure from exit code + stderr (codex) or the stream-json api_retry.error enum (claude) into one of {out_of_credits, rate_limited, overloaded, auth, context_length, timeout, network, other, none} — by error TYPE, not HTTP status (OpenAI insufficient_quota and a throttle are both 429; the Anthropic credit error is a 400/402, not 429). scripts/compound-v-failure-policy.py is the static decision table: out_of_credits/auth never retry (out_of_credits circuit-breaks the backend for the run and re-routes the remaining jobs via the env-aware codex→claude rewrite — the SAME runtime rewrite, not just /v:init; auth halts for re-auth); transient classes retry the same backend with exponential backoff + jitter (honoring retry-after), capped per-class AND by a run-level max_total_retries (anti retry-storm); context_length re-routes with escalate_tier (bigger tier, or split the job). job_result gains a failure_class field (Codex worker emits it; null on success/blocked). The "circuit breaker" is state.json fields read at batch boundaries (no daemon): attempts / cooldowns / circuit_open / total_retries / max_total_retries; a transient failure only deprioritizes (short cooldown, probed half-open next batch) while a confirmed out_of_credits/auth opens the breaker for the run. A failed job past its retry budget is marked failed and the batch continues (ralph-tui-style — independent jobs don't die because a sibling 429'd); the run halts only when the last viable backend is exhausted (→ /v:resume after top-up). Every re-route/circuit-break is loud — surfaced in /v:status and the run summary with the cost direction; never a silent cheap→expensive swap. Policy in skills/compound-v/failure-policy.md; wired into agents/parallel-dispatcher.md (Step 2c), phase-3, state-machine.md, routing-policy.md, commands/v-status.md, and the backend-launcher contract. claude has no further local fallback in 1.0 (antigravity is 1.1), so an out_of_credits/auth on claude halts rather than re-routes.

Security / Fixed — independent Codex review hardening (round 2)

A second independent Codex review went deeper and surfaced eight more findings — including a critical enforcement bypass and two regressions introduced by round 1; all are fixed:

  • Commit-inside-worktree bypass of the scope gate (CRITICAL). The gate keyed off uncommitted git diff HEAD ∪ untracked, so an executor that COMMITTED its changes inside its worktree left a clean tree and slipped past enforcement. compound-v-run-codex-worker.sh now captures the baseline SHA with git rev-parse HEAD BEFORE git worktree add and passes --baseline <sha> (not HEAD) to compound-v-scope-check.py, so a git diff <baseline-sha> still includes the committed change and BLOCKS it. New scope-gate self-test: a file committed inside a worktree, outside write_allowed, must block.
  • Timeout argv-injection guard. --timeout-sec is interpolated unquoted into the timeout argv in both bash wrappers; a crafted value like 5; touch /tmp/PWNED injected argv. Both compound-v-run-codex-worker.sh and compound-v-codex-review.sh now reject any non-^[0-9]+$ value with die.
  • macOS-symlink-safe containment (REGRESSION fix). Round 1's containment assertion compared a canonical (pwd -P) parent against a raw $WT prefix; on macOS $TMPDIR is /var/folders/... while its canonical form is /private/var/folders/..., so the prefix check falsely rejected every valid run. The worker now canonicalizes BOTH sides before comparing; the id-character regex (no /, no ..) remains the real traversal defense.
  • Direct-mode pre-existing snapshot (REGRESSION fix). Round 1's gitignored/untracked union made direct-mode checks flag PRE-EXISTING untracked/ignored files a job never created. compound-v-scope-check.py gains --preexisting <file> (paths present before the job, one per line) that are excluded from the changed/violation set; parallel-dispatcher.md documents the dispatcher snapshotting pre-existing untracked+ignored for a direct job and passing --baseline <sha> --preexisting <snapshot>. New self-test: a snapshotted pre-existing file is not flagged, while a new out-of-scope file still BLOCKS. (Worktree mode is unaffected — a fresh worktree add HEAD has no pre-existing untracked.)
  • Backend enum aligned to antigravity. compound-v-validate-manifest.py accepted an undocumented none and rejected the documented stub backend antigravity. The job-backend enum is now {claude, codex, antigravity} (none is the routing "return to planning" sentinel, never a dispatched job); execution-manifest.md and routing-policy.md wording matches.
  • Validator requires the remaining top-level fields. compound-v-validate-manifest.py now also requires top-level spec_path, plan_path, and audits (joining the round-1 run_id/feature/acceptance_criteria/routing_stance/max_parallel set); examples/manifest.example.yaml still validates.
  • Collector job-id traversal guard. compound-v-collect-results.py builds <run-dir>/results/<job-id>.json; --job-id is now validated against ^[A-Za-z0-9._-]+$ (rejecting ./..) before any path is built, exiting non-zero on a bad id (same class as the round-1 worker guard, previously missed here).
  • Empty write-scope allowed for review jobs. compound-v-run-codex-worker.sh no longer dies on an empty --write-allowed; an empty allow-list means NO writes are permitted, so the gate treats any changed path as a violation. adapter-codex.md documents empty write-scope = read-only/review job.

Hardened — backend-failure round 2 (fail-closed + health-aware reroute + deepest-tier guard)

A second hardening pass on the graceful backend-failure feature, tightening the executable behavior and the docs that describe it:

  • Fail-closed enforcement faults. A worker error/timeout status can no longer carry failure_class: none — a genuine failure can't masquerade as success and skip the policy loop.
  • Fallback-health-aware reroute. compound-v-failure-policy.py gained --fallback-open: an out_of_credits whose only fallback is itself circuit-open now returns halt (both causes surfaced) instead of a doomed reroute. The dispatcher passes it when circuit_open[<fallback-backend>].open is true.
  • Deepest-tier context guard. The policy gained --current-tier {deep|standard|light}: a context_length failure escalates a tier unless already at the deepest tier (deep), where it halts and the job is split (back to planning) rather than escalating into a model that doesn't exist.
  • Real claude enum parsing. The classifier now parses the claude stream-json api_retry.error enum and maps the exact value (billing_errorout_of_credits, etc.); the claude substring needles are a narrow fallback used only when the output isn't JSON (no bare context/invalid_request, which would mis-escalate). Run the adapter with --output-format stream-json.
  • Retry-After honored. The classifier extracts the provider wait; job_result carries it as retry_after_seconds (int), which the dispatcher passes as --retry-after so a retry sleeps the provider's stated time instead of synthetic backoff.
  • Circuit breaker is a reconciled object. state.json circuit_open is now { "<backend>": { "open", "reason": "out_of_credits|auth", "opened_at", "cleared_by" } } (not a bare bool). /v:resume reconciles it by reasonout_of_credits stays open until a top-up or a liveness probe, auth until re-auth (/v:init) — and never silently re-dispatches to a still-open breaker.
  • Per-(job, class) attempts. state.json attempts is keyed { "<job>": { "<failure-class>": n } }, so a budget consumed by one class doesn't starve another; the counter resets/forks on a backend re-route or class change. The dispatcher passes attempts[job][class] as --attempts.

Docs updated to match the scripts (no behavior is encoded in prose that the scripts don't enforce): skills/compound-v/failure-policy.md, skills/compound-v/state-machine.md, agents/parallel-dispatcher.md, commands/v-resume.md, skills/backend-launcher/adapter-claude.md.

Hardened — backend-failure round 3 (collector parity + breaker wiring)

A third pass closing what a cross-model review of the round-2 code surfaced:

  • Collector parity (critical regression fix). compound-v-collect-results.py now emits the new required failure_class + retry_after_seconds fields, so a normalized claude/direct job_result satisfies job_result.schema.json (its hand-rolled conformance checker now also handles nullable ["string","null"] types).
  • Auth opens the breaker. Opening circuit_open[<backend>] is keyed on the policy's circuit_break: true — true for auth as well as out_of_credits — not only the out_of_credits reroute path.
  • Retries write a cooldown timestamp. The retry action records cooldowns[<backend>] = now + backoff_seconds before sleeping, so the resume/half-open logic has a real timestamp to probe.
  • Mid-batch circuit-break is check-before-launch. Before launching each job the dispatcher checks circuit_open[backend]; in-flight jobs on a newly-broken backend complete and fail-fast (a no-daemon dispatcher can't un-launch them).
  • Codex 5xx → overloaded. server_error / 5xx from codex now classify as overloaded (retryable), not other.

Fixed / Documented — independent Codex review hardening (round 3)

A third independent Codex review pass (0 critical, 3 high, 5 medium) produced quick real fixes plus honest documentation of inherent limits:

  • model: haiku execution-layer override rejected. The never-Haiku policy was only checked in frontmatter (lint-frontmatter.py), but a manifest job could pin model: haiku (or claude-haiku-...) as an execution-layer override and slip through. compound-v-validate-manifest.py now flags ANY job whose explicit model contains "haiku" (case-insensitive) as a violation. New self-test: a job with model: haiku is INVALID.
  • depends_on graph validated (refs + cycles). compound-v-validate-manifest.py now validates each job's depends_on: every referenced id must exist among the manifest job ids (a dangling ref is a violation), and the dependency graph must be acyclic (cycle detection via DFS, naming the jobs on the cycle). New self-tests: dangling ref INVALID, cycle INVALID, valid DAG OK.
  • Manifest structural type-checks. Required fields are now type-checked, not just presence-checked: jobs non-empty list, acceptance_criteria list, audits mapping, max_parallel int, run_id/feature/spec_path/plan_path strings, and per-job write_allowed/read_allowed/acceptance lists. A wrong-typed field is its own specific violation; examples/manifest.example.yaml still validates.
  • NUL-safe scope-gate path handling. compound-v-scope-check.py switched all three git probes to NUL-delimited output (git diff --name-only -z, git ls-files --others --exclude-standard -z, and the -z ignored variant) and splits on \0, so a filename containing a newline cannot smuggle additional paths past the gate. New self-test: an unusual filename (a name with a space, and a name with a literal newline where the FS allows) is attributed as a single path and BLOCKS correctly.
  • Documented inherent limit: read_allowed is advisory. Only write_allowed is git-enforced; git cannot track reads, so read_allowed documents intent and scopes the prompt but is NOT a hard boundary. Stated plainly in execution-manifest.md, backend-launcher/SKILL.md, adapter-codex.md, and adapter-claude.md.
  • Documented inherent limit: direct-mode dirty-tree caveat → prefer worktree. isolation: direct gates against a baseline minus a pre-existing untracked/ignored snapshot, so a job that MODIFIES a pre-existing untracked/ignored file is not flagged. worktree (a fresh checkout with no pre-existing files) is the exact-gate safe default for anything untrusted or on a dirty tree; direct stays serial-only and is for trusted, clean-tree jobs. Documented in execution-manifest.md and routing-policy.md.
  • Stale merge-back instructions corrected. Removed the remaining git diff HEAD | git apply (drops untracked additions) merge-back forms in adapter-claude.md, phase-3-parallel-opus-dispatch.md, compound-v/SKILL.md, and this CHANGELOG's model-broker note, replacing them with the index-based patch (git add -A && git diff --cached --binary HEAD | git apply --index) used everywhere else.
  • Clarified deliberate design: agent-driven flow, deterministic enforcement. Added a note in phase-3-parallel-opus-dispatch.md that the orchestration flow is intentionally agent-driven (Engine A, anti-ruflo: no daemon) while enforcement lives in deterministic scripts (scope-check / validate-manifest) — the safety guarantees are in the scripts, not the flow.

Security / Fixed — independent Codex review hardening

A pass of an independent Codex code review surfaced eight correctness/security findings in the orchestrator scripts and docs; all are fixed:

  • Path-traversal guard on run_id / job_id (CRITICAL). compound-v-run-codex-worker.sh built a worktree path from these ids and ran git worktree remove -f || rm -rf on it — a ../ in an id could escape $TMPDIR and delete arbitrary directories. Ids are now validated against ^[A-Za-z0-9._-]+$ (rejecting ./..) before any path is built, and the worktree path is asserted to live strictly under $TMPDIR/compound-v/ before any removal. compound-v-validate-manifest.py rejects the same unsafe ids (and run_id) so a malicious manifest never reaches dispatch.
  • Worker delegates enforcement to the Python gate. The worker previously derived violations/files_changed/status with a bash case-glob matcher that was weaker than the Python authority (bash * matches /) and diverged from it. The bash matcher is deleted; after the codex run the worker now calls compound-v-scope-check.py (parsed with jq) as the single source of truth, layering timeout/error exit codes on top.
  • Scope gate now sees gitignored writes. compound-v-scope-check.py only probed git ls-files --others --exclude-standard, which excludes ignored files — a worker could write a gitignored path (dist/, .env) undetected. It now also unions git ls-files --others --ignored --exclude-standard -- ., so any ignored write outside write_allowed is reported and BLOCKS (covered by a new self-test).
  • Allowed new files survive merge-back. The documented merge-back git diff HEAD | git apply silently dropped untracked (new) files — an allowed new file passed the gate but was lost. Replaced everywhere with an index-based patch that includes additions (git add -A && git diff --cached --binary HEAD | git apply --index) across backend-launcher/SKILL.md, adapter-codex.md, parallel-dispatcher.md, and the PRD/plan.
  • Direct-mode scope check requires --baseline. A --repo (direct) job's baseline must be the recorded pre-dispatch commit, not a defaulted (possibly-moved) HEAD; the gate now errors if --baseline is omitted in direct mode. Worktree mode keeps the HEAD default (worktrees are fresh from HEAD).
  • Validator enforces all required fields + parallel ⇒ worktree. compound-v-validate-manifest.py now validates every required top-level and per-job field and their enums (backend/isolation/run/routing_stance/tier/effort) before the invariant checks, and rejects any run: parallel + isolation: direct job (per-job scope attribution requires worktree isolation). The example manifest's parallel claude jobs moved to isolation: worktree; execution-manifest.md and routing-policy.md state the rule crisply (parallel ⇒ worktree; direct ⇒ serial).
  • Collector can no longer override the scope verdict. In compound-v-collect-results.py the --files-changed / --violations / --blocked flags are now additive-only when a scope verdict is present: blocked = scope OR flag, violations/files_changed = union(scope, flag). A flag may force a block or add entries but can never clear a scope-gate block or drop a scope violation.

Fixed

  • validate-manifest.py globs_overlap soundness fix. The manifest validator's write-glob overlap test (rule 1, disjoint writes) had a soundness bug — caught on the first real cross-model review run when Codex read the repo and flagged it. Hardened so overlapping write_allowed globs are reliably detected.

Added — the model-broker delta

Stops hardcoding model strings. Jobs route by intent, not by a literal model name, so the plugin survives model churn and gains Codex's reasoning-effort dimension.

  • Tier + effort vocabulary — a stable routing vocabulary that never changes when models churn. tier ∈ {deep, standard, light} (deep = strongest reasoning: architecture, security/auth/payments, designing tests, external APIs, all reviewers, the shared-foundation Task 0; standard = bounded core/feature build incl. large isolated Codex work; light = mechanical single-file / docs / i18n). effort ∈ {low, medium, high} is an orthogonal hint with a sensible default pairing (deep→high, standard→medium, light→low) that stays independently tunable per task-type.
  • Refreshable config model-map.claude/compound-v.json gains a models map (claude / codex / antigravity, each deep/standard/light → a concrete model). The map is not committed in the repo — it is documented and seeded by /v:init, then refreshed via /v:models. Claude uses native tier aliases (opus/sonnet), Codex is a curated+user-overridable list (it has no models list command), and Antigravity values are auto-discovered from agy models (see the 1.1 auto-discovery note). Never haiku, anywhere.
  • Model resolver (scripts/compound-v-resolve-model.py). Generic — no backend-specific Codex/Antigravity logic baked into routing. CLI: --backend {claude|codex|antigravity} --tier {deep|standard|light} [--effort {low|medium|high}] [--config PATH] [--explicit-model M]. Carries a built-in default map so it resolves with no config file; a models.<backend>.<tier> entry in --config overrides the default; --explicit-model (a manifest override) always wins. Emits one JSON object on stdout — { "backend", "tier", "model", "effort" } — and exits non-zero when a tier can't be resolved. Python 3.9-safe, stdlib only.
  • Codex --effortscripts/compound-v-run-codex-worker.sh gains an optional --effort {low|medium|high} arg that appends -c model_reasoning_effort=<effort> to both codex exec invocations (with and without --output-schema). Everything already there is preserved: the </dev/null stdin redirect, stdout capture, scratch-outside-worktree handling, no --ask-for-approval never, bash 3.2 safety, shellcheck-clean.
  • /v:models (commands/v-models.md). Discovers available models per backend — agy models for Antigravity (when present), a curated list for Codex, native tiers for Claude — shows them, lets the user assign tier→model, and writes the models map into .claude/compound-v.json. This is the "skill picks the models and offers you options" surface.

Changed

  • plugin.json + marketplace.json1.0.0 in lockstep; added the orchestrator keyword.
  • SKILL.md evolved to orchestrator-as-default — the description now mentions manifest materialization and the scope-enforced, resumable pipeline, without weakening the auto-fire triggers (every existing evals.json case still passes).
  • /v:dispatch evolved to be manifest-aware backward-compatibly: it accepts a bare plan path (auto-materializing a manifest), a manifest, or a run-id. The 0.1.x plan-path flow — and the plan-saved-nudge hook — keep working.
  • Agents evolved: parallel-dispatcher is manifest-driven and multi-backend — for each job it runs compound-v-resolve-model.py with (backend, tier, effort, config) before dispatch to get the concrete model, passes --model <resolved> (+ --effort for Codex) to the worker, then calls scope-check.py after every job and HALTS on BLOCKED (an explicit manifest model skips resolution); partition-reviewer runs validate-manifest.py as its deterministic backing gate; spec-reviewer runs the three-pass Review Gate (spec acceptance criteria · quality/no-regression/no-fabricated-metrics · final integration). All reviewers remain model: opus. The agent's own model: opus frontmatter is unrelated to execution-layer resolution; resolved manifest models (gpt-5.5, etc.) are execution-layer data and never appear in frontmatter.
  • Phases evolved: phase-2 emits manifest.yaml (not only prose); phase-3 is manifest-driven multi-backend dispatch with per-job isolation and the scope gate.
  • Hooks evolved: session-banner.sh adds a /v:init hint when .claude/compound-v.json is absent; plan-saved-nudge.sh mentions /v:orchestrate alongside the existing dispatch path. Both keep all three platform JSON branches and stay shellcheck-clean.

Explicit dispositions

  • Antigravity adapter = stub, deferred to 1.1. Assessed, not assumed. Google's official agy CLI fits the contract, but two blockers keep it out of 1.0: headless agy --print returns empty stdout when piped/redirected (#408, #318) and there is no non-interactive auth (#223). adapter-antigravity.md ships as a stub returning unsupported; the 1.1 spike targets the Antigravity Python SDK first.
  • Workflows accelerator = kept in 1.0 as opt-in (Engine C). skills/compound-v/workflows-accelerator.md is a capability-probed fast-path for large parallel batches (16-wide) that auto-falls-back to Engine A's batched Task dispatch when Workflows is absent or disabled. The scope gate and state.json resume stay in Engine A even when C runs, so file-scope enforcement and crash-resume never regress. Engine B (claude -p shell-out) was rejected (rate-limit cascades + third-party-orchestrator policy).

Notes

  • All helper scripts — including the new compound-v-resolve-model.py — target stock-macOS bash 3.2 and python 3.9 (stdlib only; pyyaml optional with an embedded-subset fallback) and are shellcheck-clean and executable.
  • The models map is documentation + seeded config, never committed in the repo. compound-v-resolve-model.py ships with a built-in default map so routing works even with no config file present.
  • Worktrees live in $TMPDIR/compound-v/<run-id>/<job-id>; merge-back on PASS is an index-based patch that includes new files (git -C <wt> add -A && git -C <wt> diff --cached --binary HEAD | (cd <repo> && git apply --index)) into the main tree — a plain git diff HEAD | git apply would drop allowed untracked additions.
  • Honestly not auto-tested (documented + manually verified, no CI gate): the worker-prompt pre-emptive STOP behaviour (only the post-hoc scope-check is gated), Codex-session resume re-attachment, the /v:init flag-probe, capability-cache staleness, and the Workflows probe-fails→fallback path.

[0.1.3] — 2026-05-18

Changed

  • Marketplace name renamed from superpowers-v-marketplace to procoders. End-user install command is now /plugin install superpowers-v@procoders (was the awkward superpowers-v@superpowers-v-marketplace). The procoders name is also future-proof — additional procoders plugins can ship via the same marketplace.
  • README install section trimmed to one path at the top; local-clone / --plugin-dir dev flows moved to a new Development section lower in the doc.

[0.1.2] — 2026-05-18

Fixed (critical)

  • Install instructions in README were wrong. Claimed /plugin install <github-url> works directly; it does not. Real path is the documented two-step: /plugin marketplace add <url-or-path> first, then /plugin install <plugin>@<marketplace-name>. Reported by user trying to install v0.1.1 from GitHub and getting "Marketplace not found."

Changed

  • Marketplace name renamed from superpowers-v-dev to superpowers-v-marketplace (mirrors the upstream obra/superpowerssuperpowers-marketplace naming convention; cleaner for end-user-facing install command).
  • README install section now shows three install paths: marketplace + GitHub, marketplace + local clone, and --plugin-dir live-edit mode.

[0.1.1] — 2026-05-18

Honesty pass after an independent verification audit caught several fabricated CLI/env-var references that I had baked into hooks and docs without verifying against the official Claude Code documentation.

Fixed (critical — load-bearing)

  • Hook scripts no longer read fabricated environment variables. Rewrote session-banner.sh and plan-saved-nudge.sh to follow the documented Claude Code hook interface: input read from JSON on stdin (via jq), output emitted as JSON for additionalContext context injection. Pattern adapted from upstream obra/superpowers v5.1.0 reference hooks. Previous scripts read $CLAUDE_HOOK_MATCHER and $CLAUDE_TOOL_INPUT_FILE_PATH, neither of which exists in the official hook spec — the hooks were technically running but always silently no-op'd.
  • SessionStart matcher corrected from * to the documented pattern startup|clear|compact (matches upstream superpowers).

Removed

  • compound-v:doctor agent + /v:doctor slash command — clutter for typical sessions; manual debug instructions in TROUBLESHOOTING.md cover the same ground.
  • SubagentStop hook configuration + sidekick-nudge.sh script — the SubagentStop event is not in the official Claude Code hooks reference and the reference plugin obra/superpowers does not use it. Replaced with description-based auto-fire (which was always the primary mechanism) plus the PostToolUse(Write) plan-saved nudge.
  • gemini-extension.json — manifest schema was not verifiable against official Gemini CLI docs; removed rather than ship a fabricated config.

Changed

  • Multi-harness shims (AGENTS.md, GEMINI.md) marked 🧪 experimental / untested. Previous wording implied verified support; honest reality is the shims are based on documentation patterns but were not exercised on a real Codex or Gemini install. The README compatibility table now reflects this.
  • README install steps: removed fictional /mcp add context7 command; correct install path is /plugin install context7@claude-plugins-official or manual ~/.claude.json MCP config. Context7 demoted from step 1 to step 3 (recommended, not required).
  • Phase 3 dispatcher announce string toned down (was "going Supe"; now neutral "dispatching N implementers").
  • SKILL.md auto-fire caveat rewritten honestly: skill invocation is description-driven; hooks provide reminders but do NOT enforce the trigger.
  • .github/workflows/validate.yml no longer validates gemini-extension.json (file removed).

Added

  • Hard citation-rigor rules in agents/domain-expert.md: ≥10 distinct community posts OR 1 official source for consensus claims; isolated reports flagged explicitly; no fabricated URLs; verbatim quotes only; empty section > padded section.

Notes on the honesty audit

The verifier could not find official documentation for several Task tool parameters used throughout the plugin (subagent_type: "<plugin>:<agent>" plugin-namespaced syntax, maxTurns, run_in_background: true). These remain in the plugin's prompts and docs because they are observably functional in Claude Code as of v0.1.1, but should be revisited if they break in a future CC version. Tracked for future verification.

[0.1.0] — 2026-05-18

Initial public release.

Added

Core skill (skills/compound-v/):

  • Three-trigger interceptor for Superpowers transitions (after brainstorming, inside writing-plans, before execution)
  • Phase 1A: code-archaeology pre-flight (five-phase audit of existing-code reality)
  • Phase 1B: domain-expert advisor with three-layer parallel WebSearch (official docs, practitioner channels, audience/persona forums)
  • Phase 1C: library/doc validator via Context7 MCP (catches stale deps, abandoned libraries, outdated API signatures)
  • Phase 2: Disjoint File Partition Map enforcement inside writing-plans
  • Phase 3: batched parallel Opus dispatch with strict scope locks; model: opus by default, model: sonnet only when a task ticks every box of the strict 8-box junior-task taxonomy

6 first-class agents (agents/) — invokable as subagent_type: "compound-v:<name>":

  • code-archaeologist, domain-expert, doc-validator, partition-reviewer, parallel-dispatcher, spec-reviewer

2 slash commands (commands/):

  • /v:archaeology <topic>, /v:dispatch <plan-path>

Hooks (hooks/) — sidekick auto-fire (text-printer only, no side effects):

  • SessionStart banner reminding parent Claude that Compound V is loaded
  • PostToolUse matcher=Write nudges when a plan or spec is saved

Operational:

  • .github/workflows/validate.yml — JSON schema, agent frontmatter (with no-Haiku project policy), dead-link scan, shellcheck on hooks
  • scripts/lint-frontmatter.py — Python frontmatter linter for local pre-commit
  • evals/evals.json — 8 trigger eval test cases (3 positive, 2 negative, 3 edge) for the compound-v skill
  • .cclintrc.json — config for @felixgeelhaar/cclint
  • TROUBLESHOOTING.md — common issues
  • All code blocks tagged with explicit language

Realistic concurrency limits documented: 4-6 foreground / 5-10 background Task calls per message; batched dispatch for larger plans; maxTurns: 15 cap; run_in_background: true recommended for implementer batch.

Output convention: docs/superpowers/{archaeology,expert,library-audit}/ with _knowledge-base/ subdirectories for cross-feature knowledge persistence.

[0.1.0] — 2026-05-18

Initial public release.

Added

Core skill (skills/compound-v/):

  • Three-trigger interceptor for Superpowers transitions (after brainstorming, inside writing-plans, before execution)
  • Phase 1A: code-archaeology pre-flight (five-phase audit of existing-code reality)
  • Phase 1B: domain-expert advisor with three-layer parallel WebSearch (official docs, practitioner channels, audience/persona forums)
  • Phase 1C: library/doc validator via Context7 MCP (catches stale deps, abandoned libraries, outdated API signatures)
  • Phase 2: Disjoint File Partition Map enforcement inside writing-plans
  • Phase 3: batched parallel Opus dispatch with strict scope locks; model: opus by default, model: sonnet only when a task ticks every box of the strict 8-box junior-task taxonomy

6 first-class agents (agents/) — invokable as subagent_type: "compound-v:<name>":

  • code-archaeologist, domain-expert, doc-validator, partition-reviewer, parallel-dispatcher, spec-reviewer

2 slash commands (commands/):

  • /v:archaeology <topic>, /v:dispatch <plan-path>

Hooks (hooks/) — sidekick auto-fire (text-printer only, no side effects):

  • SessionStart banner reminding parent Claude that Compound V is loaded
  • SubagentStop matcher=brainstorming|writing-plans nudges with next-step dispatch
  • PostToolUse matcher=Write nudges when a plan or spec is saved

Multi-harness compatibility shims (experimental):

  • AGENTS.md (Codex CLI)
  • GEMINI.md + gemini-extension.json (Gemini CLI)

Operational:

  • .github/workflows/validate.yml — JSON schema, agent frontmatter (with no-Haiku project policy), dead-link scan, shellcheck on hooks
  • scripts/lint-frontmatter.py — Python frontmatter linter for local pre-commit
  • evals/evals.json — 8 trigger eval test cases (3 positive, 2 negative, 3 edge) for the compound-v skill
  • .cclintrc.json — config for @felixgeelhaar/cclint (silences CLAUDE.md-specific false-positives)
  • TROUBLESHOOTING.md — 11 documented common issues
  • All code blocks tagged with explicit language (plaintext, markdown, etc.)

Realistic concurrency limits documented: 4-6 foreground / 5-10 background Task calls per message; batched dispatch for larger plans; maxTurns: 15 cap; run_in_background: true recommended for implementer batch.

Output convention: docs/superpowers/{archaeology,expert,library-audit}/ with _knowledge-base/ subdirectories for cross-feature knowledge persistence.