/dev-framework-rl — Experiential-RL Orchestrator
Runs a development problem as an episode: brainstorm a framing, walk the /dev-framework stages, gate each stage with a critic sub-agent, log the whole trajectory to SQLite, and (later phases) compute a reward and learn from it.
The policy is prompts + memories — Claude's weights are frozen. This is experiential-RL: the system improves by accumulating trajectories and updating skill prompts, not by gradient descent.
Current state
All phases through Tier 8 are shipped and tested (real-DB suite under tests/).
Full tier history, ship dates, and design detail live in RL-PLAN.md (v0.7) and
README.md — this file holds only operating instructions. Running today: episode
lifecycle + host locks (episodes.db), per-stage manifests, 7 verdict critics, 8
per-type reward rubrics, secret scrubbing on every DB write, per-episode +
cross-episode learning, the batch ritual, critic-trust attribution
(observation-only), and every command in the CLI table at the bottom.
Post-deploy outcomes: finalize auto-schedules a 7-day check; the devrl-post-deploy
cron (daily 09:00 Europe/London, prompt at
C:/Users/skf_s/clawd/memory/cron-prompts/devrl-post-deploy.md) runs the
verification protocol (gh pr checks + revert-grep per episode). HARD GUARD:
never mass-mark --clean to clear the queue — uncertain outcomes stay unknown
and go to the human via Telegram.
Prerequisites
episodes.db must be migrated:
python ~/.claude/dev-framework/scripts/migrate.py
Invoking devrl — absolute path, never a persisting cd (CRITICAL anti-drift
rule). The Bash-tool cwd PERSISTS across calls: a bare cd ~/.claude/dev-framework
silently re-homes every later feature-repo command — the single most recurring
orchestrator friction, and memory-recalled discipline demonstrably fails under load.
Mechanics: python ~/.claude/dev-framework/scripts/devrl.py <cmd> run FROM the
feature repo (the python scripts/devrl.py snippets below are shorthand for that
absolute form), OR a non-persisting subshell ( cd ~/.claude/dev-framework && ... );
give EVERY feature-repo command its own explicit cd <repo> && in the SAME call.
Full incident detail: AUDIT-RULES.md "cwd-drift".
Episode lifecycle
1. Init and lock
python scripts/devrl.py episode-init "<problem statement>" --token-budget 200000 --wallclock-budget-sec 5400
Capture the printed 26-char episode id as $EID. Then claim the host lock:
python scripts/devrl.py lock-acquire $EID --session "<this-session-id>"
Exit 1 / "denied" → another session owns this episode. Stop. Do not proceed.
Heartbeat the lock (lock-heartbeat $EID) at least every few minutes during long stages — a lock un-heartbeated for 5 minutes is reaped and the episode marked stalled.
Background-op heartbeat discipline. Long background ops (Workflow builds, full
test suites, codex reviews) silently burn the 5-minute lock window: heartbeat
immediately BEFORE and AFTER every such op; on lock-vanished, re-acquire and
continue. Never &&-chain a manifest write (or any required step) after
lock-heartbeat — a vanished lock exits non-zero and aborts the chain; write the
manifest unconditionally on its own line. Full incident: AUDIT-RULES.md
"background-op heartbeat".
Isolate into a dedicated worktree at episode START for high-contention repos.
TRIGGER: git worktree list shows active .claude/worktrees/ agents, or another
session may checkout the shared tree. Right after lock-acquire:
git worktree add -b <feat-branch> <path> origin/master, then npm install
npm run buildin the worktree (do NOT junctionnode_modules: npm destroys a non-directory junction on its first install, arriving-empty cost a build round on 2026-08-02; a real install is seconds on this repo), do ALL edits/commits/codex/build/test there; remove at close-out (if a legacy junction exists,rmdirit BEFOREgit worktree removeor the removal can follow it into the main repo's node_modules). Before any version bump:git fetch origin && git show origin/master:package.json | grep versionand bump PAST a concurrent merge. Full incidents: AUDIT-RULES.md "episode-start worktree isolation".
Probation-memory exposure (R9, 2026-06-09). Right after lock-acquire, run python scripts/devrl.py memory-list --status probation. Carry the relevant memories into this episode's stage briefs tagged [PROBATION] — they are unconfirmed hints, not settled law — and record each one's id on the steps where it was in scope (step-record ... --memory-ref <id>). This is what lets a useful memory earn its 3 shipped-episode confirmations and a useless one earn its deprecation; a probation memory kept out of context can never do either.
1.5 Codex availability probe (recommended)
The review stage gates on codex-review-critic, which requires the codex CLI. Probe at episode-init so an unreachable codex doesn't surface as a surprise blocker mid-episode. Run:
_CODEX_BIN=$(which codex 2>/dev/null || echo "")
if [ -z "$_CODEX_BIN" ]; then
echo "WARN: codex CLI not installed. codex-review-critic at the review stage will fail."
echo " Either install: npm install -g @openai/codex"
echo " Or proceed knowing the review stage will need manual /codex from another session"
echo " (paste the verdict back to the orchestrator)."
python scripts/devrl.py episode-friction $EID --note "codex CLI not installed at episode-init; codex-review-critic will need manual /codex from another session."
fi
If codex is missing, decide upfront whether to (a) install it, (b) skip codex-review-critic with explicit human override at the review stage, or (c) defer the episode entirely. Surfacing this at init beats surfacing it at review-stage round 1.
(Incident 2026-05-26, hippo C5: mid-episode codex unavailability paused the review stage; an init-time probe would have caught it upfront.)
Pin cwd for codex review --uncommitted — use the wrapper. codex review --uncommitted reviews the CURRENT cwd's repo; after any devrl command that can
mean dev-framework itself. Never call it bare from an orchestrator session — invoke
bash ~/.claude/dev-framework/scripts/codex-review-pinned.sh <feature-repo> [args]
(subshell-cds, verifies codex's workdir line, exit 3 = review VOID). Full
incident: AUDIT-RULES.md "codex review cwd pinning".
Codex-on-Windows root cause + hard timeout (2026-08-02, episode 01KZ1FHCK).
Codex's Windows sandbox helper receives its policy on the command line; at
~33.9KB payload it exceeds the 32,767-char CreateProcess limit (os error 206),
EVERY shell exec fails, and codex review stalls forever instead of failing
fast — a 2h14m silent hang. The wrapper now defaults
-c 'sandbox_mode="danger-full-access"' (bypasses the broken helper),
-c 'notify=[]' (disables the computer-use turn-end hook), and a hard
timeout (default 600s, override CODEX_REVIEW_TIMEOUT; 124 => exit 3 VOID).
The old -c "mcp_servers={}" guard no longer disables MCP in codex 0.144.x —
do not rely on it. NEVER run codex as an unbounded background job: watchdog by
output-file mtime, not just content.
Base-aware invocation (2026-08-15, episode 01M025CW434ZAPVSFC61BGFGCT).
Check git status in the feature repo BEFORE invoking the wrapper:
- Work already committed =>
--uncommittedreviews NOTHING ("working tree is clean") and wastes a round. Pass--base origin/master(or the base sha). Codex rejects--basecombined with a positional prompt — use the flag alone. - Re-review rounds after fix commits => scope to the DELTA with
--base <prior-commit-sha>. A grown multi-commit branch (~4k insertions) blew a 900s timeout on a full re-review; the delta-scoped run completed. - Full-branch reviews of substantial diffs => set
CODEX_REVIEW_TIMEOUT=900or higher. The 600s default killed one review AFTER it had written complete findings (VOID by wrapper contract; findings salvageable only as unverified input, re-verify against source). Memory:feedback_codex_review_base_aware.md(tier-1, probation).
1.6 Publish credentials probe (recommended for library / package releases)
If the episode will publish a package at the deploy stage (npm, PyPI, crates,
etc.), the publish credentials live with the human, not the orchestration
session. An episode that bumps versions, passes every gate, and merges, only to
hit a 401 at npm publish, has surfaced an avoidable blocker after the work is
already done. Probe at episode-init, the same way §1.5 probes codex:
# npm — only if this release publishes to npm
npm whoami >/dev/null 2>&1 || {
echo "WARN: not authenticated to npm; deploy-stage 'npm publish' will 401."
python scripts/devrl.py episode-friction $EID --note "npm not authenticated at episode-init; publish will be a manual operator step or needs 'npm login' first."
}
# PyPI — only if this release publishes a Python package
[ -n "$TWINE_PASSWORD" ] || [ -f ~/.pypirc ] || {
echo "WARN: no PyPI token in env or ~/.pypirc; deploy-stage twine upload will hang/fail."
python scripts/devrl.py episode-friction $EID --note "no PyPI token at episode-init; SDK publish will be a manual operator step (TWINE_USERNAME=__token__ TWINE_PASSWORD=pypi-... --non-interactive)."
}
If creds are missing, decide upfront whether to (a) have the operator authenticate (! npm login, export the PyPI token) so the deploy stage can publish, (b) treat publish as a documented manual handoff and tag-only, or (c) defer. Either way the deploy-gate human checkpoint should state the publish path explicitly rather than discovering the 401 after merge.
(Incident 2026-05-28, hippo v1.15.0: all gates passed and the PR merged, then npm publish 401'd — publish became a manual after-the-fact operator step.)
2. Brainstorm pre-stage
Run /office-hours (builder mode) or /brainstorming to generate 3-5 candidate framings of the problem. Pick the strongest.
Then work your own pick, twice: build it out, then break it.
Build it out with /grilling. Map the framing as a design tree and work the frontier: every decision whose prerequisites are already settled. Ask the whole frontier in one round, numbered, each question carrying your recommended answer. Then answer your own round — the orchestrator is the respondent here, and the recommendations exist so it can decide without a human. Escalate only a question whose answer is on the ASK-FIRST list (cost, destructive, live-schema, a genuine two-readings fork); everything else takes the recommendation and records it. Finding facts is the orchestrator's job: dispatch a sub-agent for anything the repo, the DB or a tool can answer, and ask the rest of the frontier while it runs. The pre-stage is done when the frontier is empty, so nothing reaches plan silently assumed.
Then break it with /grill-me. "Me" is the orchestrator (you). The grill is adversarial: interrogate the assumptions in your own selection, name the weakest premise, surface what would have to be true for this framing to win, and what would falsify it. If the grill breaks the framing, return to the candidate list and pick a different one (or refine).
Two passes, not one. /grill-me attacks the answers you already have; it never surfaces the question you failed to ask. Every brainstorm concern from either pass is carried forward into plan under the §4 rule, so an unvisited branch here is an unvisited branch the plan-eng-critic will never see. Record the chosen framing + the grill's strongest counter-point + your response in the step summary:
python scripts/devrl.py step-record $EID brainstorm --skill /office-hours --critic-status n/a --summary "<chosen framing + grill's strongest objection + how you addressed it>"
(The brainstorm-judge critic that ranks candidates automatically is a separate follow-up — it needs a ranking contract distinct from the pass/fail verdict critics. For now, choose deliberately, grill your own choice, and record your reasoning in the summary.)
3. Discover and stage plan
Invoke /dev-framework discover with $EID in context. It emits trajectories/$EID/stage-plan.json. Validate it:
python scripts/validate_manifest.py plan trajectories/$EID/stage-plan.json
Read the plan's project_type and rubric_file, then:
python scripts/devrl.py set-project-type $EID <project_type> <rubric_file>
python scripts/devrl.py step-record $EID discover --skill /dev-framework --critic-status n/a --summary "<what discover found>"
3b. Pre-plan codebase audit (mandatory between discover and the first plan stage)
A deterministic audit pass between discover and the first plan invocation: greps are
free; the same drifts cost a critic round each when found later. Run the applicable
rules in ONE batch of parallel Grep calls before invoking /dev-framework plan.
Each rule: TRIGGER → action. Full detail + incidents: AUDIT-RULES.md (read a rule's
section when it fires or the plan matches its shape).
- TODOS staleness reproduce-check — TRIGGER: the brief references TODO/backlog
items. Grep each item's named symbol/test/CLI-flag/file; already shipped → abort
the episode as a reproduce-check WIN (sync TODOS.md, finalize
aborted; a WIN is a successful episode and breaker-exempt). → AUDIT-RULES.md #1 - Parallel allow-list grep — TRIGGER: the plan adds an entry to ANY
allow-list/registry/
Set/Map(incl. repeatable-CLI-flag allow-lists in argv parsers). Grep the exact pattern repo-wide; N>1 sites → the plan must enumerate all N (a repeatable flag missing from the parser list is silently last-wins). → AUDIT-RULES.md #2 - Version-bump target count — TRIGGER: the plan ships a version bump. Enumerate every manifest via git grep; for version CONSTANTS in code, also grep the TEST assertions that hard-code the old number. → AUDIT-RULES.md #3
- Roadmap-sync sweep — TRIGGER: the episode cites a canonical-roadmap claim
("never measured", "Track X blocked"). Grep
docs/evals/for results docs newer than the canonical doc's mtime. → AUDIT-RULES.md #4 - Public-API caller audit — TRIGGER: the plan changes a function signature.
Grep callers at EVERY import surface (
from X import,sys.pathinserts,spec_from_file_location, dynamicrequire()), not just internal helpers. → AUDIT-RULES.md #5 - Functional-duplicate check — TRIGGER: the plan ADDS a user-facing artifact (page/calculator/route/endpoint). Grep existing artifacts' titles AND descriptions for the same CAPABILITY — a slug/name collision check alone is insufficient. → AUDIT-RULES.md #6
- Temporal / as-of query check — TRIGGER: the plan builds a "what was X at time
T" query. Mirror an existing temporal pattern (hippo
src/recall-history.tssuccessor-awareasOf); the plan must enumerate valid-time vs transaction-time, which row statuses are included, and the date-granularity contract. → AUDIT-RULES.md #7 - Sibling-clone audit — TRIGGER: the plan mirrors an existing sibling
route/module/handler. Audit the pattern being cloned for latent bugs before
replicating (e.g.
?limit=needsNumber.isInteger); prefer one shared helper over an Nth copy. → AUDIT-RULES.md #8 - Cross-cap consistency — TRIGGER: the plan generates/assembles a value stored
into a length-capped field. Prove
N × per_item_cap + overhead <= column_capor require budget-aware assembly. → AUDIT-RULES.md #9 - Reserved-word column check — TRIGGER: a migration adds a column. Check each
name against SQL reserved words (
trigger,order,group, ...); rename with a safe suffix and map back to the domain field. → AUDIT-RULES.md #10 - Bidirectional denormalized-value guard — TRIGGER: a child row denormalizes a parent value with a "child matches parent" guard. A forward guard on the child is NOT sufficient — also spec a parent-side reverse guard (or explicitly accept parent immutability). Cover BOTH directions. → AUDIT-RULES.md #11
- Fail-soft post-commit side-effect — TRIGGER: the plan adds a best-effort side-effect after a committed write (enqueue/mark-dirty/notify/invalidate). Enumerate the loss windows UP FRONT; state per window: closed, or accepted self-healing (and how). → AUDIT-RULES.md #12
- Bounded-neighbourhood / focus query — TRIGGER: the plan builds a focus/subgraph/k-hop query with a limit. Run the six-point correctness checklist UP FRONT (seed, edges, SQL-pushed bound, truncation flags, cap alignment, one snapshot). → AUDIT-RULES.md #13
- FK-action / trigger firing — verify empirically — TRIGGER: a migration
combines FK
ON DELETEactions withBEFOREtriggers on the same table. Do NOT reason from docs; probe in a:memory:db (node:sqlitefires BEFORE UPDATE fromON DELETE SET NULLeven with recursive_triggers OFF). → AUDIT-RULES.md #14 - Dual-provenance invariant matrix — TRIGGER: row validity depends on >1 provenance source or a denormalized copy. Enumerate the guard matrix at plan time; ONE shared invariant helper at EVERY write path. → AUDIT-RULES.md #15
- Already-shipped / already-fixed check — TRIGGER: every episode, before
brainstorm (direct invocations included).
git fetch origin; resolve the DEFAULT branch (never hardcoded); diffHEAD..origin/<default>+ grep the feature's key terms across the origin tree;gh pr list --search "<terms>". Hit → STOP and reframe to the user. Network/auth failure → warn and proceed. → AUDIT-RULES.md #16 - Per-site fix-plan greps — TRIGGER: the plan maps fixes to specific sites. BEFORE writing the mapping, grep: existing helpers with the same purpose; the real call chain into each edited function; the enclosing function at each cited line; same-function siblings sharing the defect class. Names/line-proximity reasoning is reliably wrong. → AUDIT-RULES.md #17
- Search-first for external solutions — TRIGGER: the plan BUILDS new non-trivial machinery (parser, scheduler, diff engine, retry/queue layer, protocol client, algorithm implementation). Before the plan stage, search for an existing library/built-in/pattern (" built-in", " best practice ") and state in the plan what was found and why build-vs-adopt. Rules 6/16 catch internal and already-shipped duplicates; this catches reinventing an external wheel. → AUDIT-RULES.md #18
- Dataset-invariant audit (eval episodes) — TRIGGER: the episode builds or
pre-registers an eval harness/protocol over a dataset. BEFORE any pre-reg doc
locks, script three <5-min checks against the REAL data: (a) temporal ordering
(any context timestamps after the evaluation timestamp?), (b) per-feature
variance through the real ingest path on a small sample, (c) duplicate-content
rates (tie-break stress). Paste the outputs into the plan. Memory:
feedback_eval_prereg_dataset_invariant_audit. (LC2-E1 2026-08-09: skipping this cost 2 protocol amendments + two 77-minute full reruns; a critic and codex each found one of the missed invariants empirically.) → AUDIT-RULES.md #19 - Researched-dataset verifier pass — TRIGGER: the plan builds a facts table (vendor terms, prices, fees, perks) by sub-agent research from web sources. The plan must add a separate READ-ONLY verifier task: a second sub-agent re-opens each row's cited source and reports MATCH / MISMATCH per field before the execute manifest emits; the producer never grades its own rows. (boring-maths card rewards 2026-09-02: a 5-row spot-check of a 22-row Sonnet dataset found 3 field errors.) → AUDIT-RULES.md #20
Record the audit as a step:
python scripts/devrl.py step-record $EID codebase-audit --skill /dev-framework-rl --critic-status n/a --summary "<grep results: N TODOS items reproduce-checked; M allow-list sites identified; K version-bump targets enumerated; J docs/evals/ results-docs scanned; L public-API caller surfaces audited>"
Then record every rule you RAN, and say whether it found anything (C1 policy decay). Record the ones that ran clean too, not only the ones that hit:
python scripts/devrl.py audit-record $EID \
--rule <slug>[:what-you-checked] \ # ran, found nothing (repeatable)
--caught <slug>[:what-it-found] # ran and found something (repeatable)
A rule that runs every episode and never once catches anything costs tokens forever and scores highest on firing count alone, so --rule vs --caught is the whole measurement. Passing the same slug to both exits 2. Only the FIRST colon splits, so a note may contain file.ts:42.
Stable slugs (never renumbered; rule № → slug): 1=todos-staleness, 2=parallel-allow-list, 3=version-bump-targets, 4=roadmap-evals-freshness, 5=public-api-callers, 6=functional-duplicate, 7=temporal-as-of, 8=sibling-clone, 9=cross-cap-consistency, 10=reserved-word-column, 11=bidirectional-guard, 12=fail-soft-post-commit, 13=bounded-neighbourhood, 14=fk-trigger-empirical, 15=dual-provenance-matrix, 16=already-shipped-origin, 17=per-site-plan-greps, 18=search-first-external, 19=dataset-invariant-audit, 20=researched-dataset-verify. policy-compact-report proposes two kinds of retirement, both propose-only, and absence alone never demotes: demotion_candidates never fire at all, never_caught_candidates fire but have never found anything across at least --min-scored scored firings. Firings recorded before migration 0017 carry no verdict and count as unscored, never as clean, so they can never retire a rule.
If the audit surfaces a reproduce-check WIN, jump to finalize (skip plan/execute/verify/review/ship). The win IS the deliverable.
4. Stage loop
Iterate the stages list from stage-plan.json (NOT a hardcoded 9). For each stage after discover:
Invoke
/dev-framework <stage>with$EIDin context.Validate the emitted manifest:
python scripts/validate_manifest.py manifest trajectories/$EID/<stage>.manifest.jsonValidation failure → record the step with
--critic-status errorand escalate to the human.If the stage has critic(s) —
critic_registry.STAGE_CRITICSmaps each gated stage to its critics (plan→plan-eng-critic+plan-design-critic,execute→code-review-critic,review→independent-review-critic+codex-review-critic,ship→ship-readiness-critic,deploy→canary-monitor). These are the exact namescritic-checkaccepts — pass them verbatim (every critic carries the-criticsuffix exceptcanary-monitor). For each critic of this stage:- Launch a
senior-code-reviewersub-agent. Brief it with the full contents of that critic's briefing (prompts/critic-<role>.md) plus the milestone goal and the stage's artifacts from the manifest. Pass the briefing's findings shape through verbatim —{"severity", "message", "location"}per finding, extra keys forbidden — and never restate the output contract in your own words: a brief that asked for{severity, section, issue, fix}madecritic-checkreject a real plan-eng verdict and cost a round (2026-09-02, boring-maths01M1H905JWGMPA1GGC9PR24JBB). (plan-design-criticruns only for UI projects.) Exception:independent-review-criticgets NO sub-agent wrapper — the orchestrator runs/code-reviewdirectly and grades its findings into the critic contract (see thereviewbullet in §4a); the zero-tool-calls check below applies to sub-agent critics only. - If the plan artifact is an existing repo doc (e.g.
docs/.../plans/<date>-<name>.md) rather than an in-episode draft, brief the critic explicitly that anyStatus: Draftornot yet reviewedmarker means the doc has NOT been engineering-reviewed yet; fresh-eyes scrutiny is the point. A pre-existing plan author's reasoning is not pre-vetted, and the orchestrator should not defer to its existing prose. (Incident 2026-05-23, resona Phase A: fresh-eyes briefing caught a cross-org schema leak in a 5-day-old draft.) - For the
planstage specifically: pre-stage brainstorm concerns must be carried forward into the revised plan. When enteringplan, re-read the brainstorm step'ssummaryfield (viaepisode-steps). Each concern surfaced there must be either explicitly addressed in the revised plan artifact OR explicitly noted as out-of-scope in the plan manifest. Don't let brainstorm-stage framing dissolve before the plan-eng-critic runs — the critic only judges what's IN the revised plan, not what was flagged during brainstorm. (Incident 2026-05-23, resona Phase B: brainstorm-flagged rate-limiting never reached the revised plan; the gap surfaced at review and cost a retry.) - Confirm the sub-agent actually read the artifacts. If its result reports zero tool calls, it produced a verdict from the prompt text without opening the diff / plan / files — discard it, do NOT
step-recordit, and re-launch the critic. If a re-launched critic again returns zero tool calls, record--critic-status errorand escalate. A critic that read nothing has not reviewed; the critic briefings mandate file reads for the same reason. - Save the sub-agent's response to a temp file, then:
python scripts/devrl.py critic-check <critic-name> <temp-file> - Exit 0 (pass) →
step-record ... --critic <critic-name> --critic-status pass --critic-score <n>. - Exit 1 (fail) →
step-record ... --critic <critic-name> --critic-status fail --critic-score <n> --must-fix "...". Re-run the stage with the must-fix fed back, up to the per-stage cap (plan 3, execute 2, review 1, ship 1;--retry-count <n+1> --retry-strategy revise_with_feedback). Cap hit → escalate to the human. Root-cause pass before the final retry (added 2026-07-18): when a stage's critic has failed twice consecutively AND the must-fix describes a DEFECT (failing test, wrong behavior, crash) rather than a plan/scope gap, run/investigateon the defect BEFORE the last permitted retry — the final attempt must be built on a named root cause, never a third revise-with-feedback guess (global rule: after 2 failed iterations, reconsider instead of retry). Record the investigation's one-line cause in the retry step's summary. Cap-extension carve-out (learned 2026-06-02, hippo A7 recall-trace): when a plan round returns score ≥ 75, 0crit, and the SOLE remaining finding is a one-clause fix the orchestrator introduced in its OWN prior revision, a single one-round cap extension (with operator notification) is permitted before full escalation; escalate if that extension round also fails or introduces a new finding. The cap exists to stop thrashing on a broken plan, not to block a converged one over a self-inflicted typo. - Exit 2 (parse error) →
step-record ... --critic <critic-name> --critic-status error, escalate to the human.
--criticis mandatory on everypassandfailandstep-recordexits 2 without it. Pass the same registry name you gavecritic-check. A verdict with no critic named cannot be attributed, andcritic_pass_rateandcritic-trustboth read exactly these rows. Between 2026-05 and 2026-09-01 the flag was optional and 548 of 658 graded steps went unattributed (all 47 of July's), which is why no per-critic trend can be reconstructed for that period. The stage advances only when all of its critics pass.CI gate (
ship/deploystages) — a critic verdict is not the repo's CI. Before theshipstage opens a PR and before thedeploystage merges one, rungh pr checks <PR>and require every required check green. A red required check blocks — do not merge. A red non-required check must be explicitly classified as pre-existing (gh run listevidence it failed on the base branch before this episode) or fixed first. Never tell the human "all gates passed" meaning the critic gates while repo CI is red — they are different gates; report both.Stacked PRs on a squash-merge repo (2026-09-02, boring-maths #25 → #26 → #27). Squashing the base PR rewrites the commits the next PR still carries, so GitHub reports that PR CONFLICTING the moment it is retargeted. For each next PR, BEFORE
gh pr edit <N> --base master:git rebase --onto origin/master <old-base-tip> <branch>, confirmgit diff --stat <old-tip> <branch>is empty, thengit push --force-with-lease=refs/heads/<branch>:<old-sha>. Never--delete-branchon an intermediate merge — GitHub auto-closes every PR stacked on a deleted base (memoryfeedback_gh_pr_merge_delete_branch_cascade).- Launch a
If the stage has no critic →
step-record $EID <stage> --critic-status n/a --summary "...", advance.Heartbeat the lock.
4a. Mandatory skill hooks per stage
Three Keith-validated release-chain skills are wired into the stage loop. They are NOT critics (no critic-check parsing) — they run before the stage's critics so the diff arriving at each critic has already been self-reviewed and sanity-checked. Skip them and the critics waste sub-agent budget on issues the skill would have caught.
executestage — run/self-reviewas the tail step before manifest emit. Same-session pass over the diff just produced. Catches missed requirements, regressions, and forgotten edge cases thatcode-review-criticwould otherwise spend a sub-agent finding. Record the summary in the manifest'sself_review_summaryfield — the schema enforces this atstage: execute, status: completed, so the validator will reject the manifest without it. If/self-reviewsurfaces a must-fix, address it in-stage before emitting the manifest — do not advance.verifystage — drive the affected flow end-to-end as the tail step before manifest emit (reworded 2026-08-02; the 2026-07-18 text named a/verifyskill that was never installed). Re-running the test suite is necessary but not sufficient: exercise the AFFECTED FLOW in the real app/CLI and observe behavior — the class of runtime regression that green tests andgh pr checksboth miss (the CI-red-merge incident's root cause). For UI projects use/qa-only(browser QA, report-only) as the driver; for CLIs/APIs run the real commands/requests against the built artifact. Record what was driven + observed in the verify manifest'sverify_skill_summaryfield (optional schema field today; may be promoted to required once the workflow shape stabilises). A behavioral mismatch found here is fixed in-stage before the manifest emits — do not advance.reviewstage — the official/code-reviewplugin implementsindependent-review-critic(rewired 2026-08-02, no fallback — Keith directive). Sequence: commit the episode's work in the worktree, push the branch, open a DRAFT PR (gh pr create --draft), then invoke the plugin (claude-plugins-official:code-review— its command carriesdisable-model-invocation: false, so the orchestrator CAN launch it; pass the PR number). It fans out 5 parallel Sonnet reviewers + per-issue confidence scorers and filters findings below 80/100 — adversarially verified findings, which matters because the review stage has a retry cap of 1 and one false positive burns the only retry. NEVER use Haiku anywhere in this skill (Keith directive 2026-09-13). The plugin's prose prescribes Haiku for the eligibility check, the guidance-file list, the PR summary and the per-issue scorers; run every one of those onmodel: "sonnet". Measured 2026-09-13 on hippo PR 191: the Haiku PR summary called a pre-existing file new, one Haiku scorer gave a comment-length nitpick 75, and another gave a real one-token bug 90 that Sonnet re-scored at 75 with better evidence. A judge that misfires in both directions defeats the 80 filter. Grade the surviving findings into the critic contract (findings ->--must-fix, score perprompts/critic-independent-review.md, thencritic-check independent-review-critic); pass the briefing's house blind-spot checklist (SQL safety, LLM trust boundaries, conditional side effects, CLI dual-write patterns) in the invocation args. TWO TRAPS, both verified 2026-08-02: (a) the BUNDLED skill also namedcode-reviewis operator-only (disable-model-invocation) — a bareSkill(code-review)call errors; use the plugin-qualified name; (b) NEVER wire/code-review ultra— billed cloud review, user-triggered only. Theshipstage then marks the PR ready-for-review instead of creating it. Bothindependent-review-criticandcodex-review-criticstill gate independently; codex stays the cross-model second opinion.shipstage — run/ship-checkas the first step. Pre-PR sanity pass: what shipped, is it worth shipping, did we do enough QA? Save the output to the manifest'sship_check_summaryfield — the schema enforces this atstage: ship, status: completed, so the validator will reject the manifest without it. Pass the summary toship-readiness-criticas input. A blocker from/ship-checkshort-circuits the stage — escalate to the human rather than asking the critic to rubber-stamp it.shipstage — Fable final-review pass for the hardest changes (Keith directive, 2026-08-23). TRIGGER (any): a schema migration; security- or tenant-isolation-touched code; a change to a core write-path / invariant primitive (theupsertEntryRowclass); or a diff over ~500 changed lines. When it fires, after/ship-checkbut BEFOREship-readiness-critic: spawn exactly ONE Agent sub-agent withmodel: "fable", briefed with the full diff, the plan artifact, and all prior critic + codex verdicts. Its job is a fresh adversarial "would you ship this?" pass — surface what every earlier gate missed, not re-run their checklists. Real defects it finds are must-fix in-stage beforeship-readiness-criticruns; append its one-line verdict to the ship step's--summary. This bullet is the standing explicit ask the global routing rule requires ("fablesub-agents: never unprompted") — it authorises this ONE pass at this ONE point only: never at earlier stages, never as a fan-out, never more than one per episode. Non-triggering episodes skip it silently — Sonnet critics + codex already cover routine diffs (A/B verdict, §4b). Cost context: one Fable review pass is a fraction of Fable orchestrating an episode; run orchestrator sessions on Opus/Sonnet and let this bullet be Fable's only slot.shipstage — record deploy metadata right after the PR opens.python ~/.claude/dev-framework/scripts/devrl.py episode-deploy-record $EID --pr-url <PR-URL>(the ship manifest schema now REQUIRES apr_urlartifact atstatus: completed; a sanctioned no-PR ship — direct-commit / quant pipelines — records the literalnone). At thedeploystage after merge, re-run with--merge-commit <SHA>. This is the producer feedingepisode-deploy-meta, thedevrl-post-deploycron, and every outcome-weighted learning leg — an episode that skips it can never resolve a post-deploy outcome (the 0/95 outcome-starvation root cause, fixed 2026-06-09, PLAN-continuous-loop Phase A).shipstage — run/quiz-me from-diff HEADafter/ship-check, beforeship-readiness-critic. Operator-knowledge gate. Generates 5 MC + 1 explain-back from the episode's diff, quizzes the human operator interactively, grades honestly. Then runspython ~/.claude/skills/quiz-me/scripts/quiz.py gate— exit 1 blocks the ship stage until the operator clears any failed cards via a follow-up/quiz-mesession. Save the quiz summary in the manifest'squiz_me_summaryfield (optional schema field today; may be promoted to required in a future iteration once the workflow shape stabilises). This is what enforces "no new features until the operator understands the last one" — the orchestrator's other gates protect against bad code, this one protects against bad operator mental models. Skip this gate in headless / spawned-session mode (no human at the keyboard to quiz); recordquiz_me_summary: "skipped (headless)"in the manifest so the gap is visible. Loop mode: defer, don't skip — recordquiz_me_summary: "deferred to batch gate (loop mode)"and run the accumulated quizzes (plusquiz.py gate) at the batch deploy gate, one sitting with the human present, before the deploy decision.planstage — run/grill-meas the tail step before plan-eng-critic. "Me" here is the orchestrator (you). The grill interrogates the orchestrator's own plan: weakest premise, hidden assumptions, what would have to be true for this plan to work, what would falsify it, which scope claims are unsupported. The grill output is INPUT to plan-eng-critic — the critic should judge whether the plan addresses the grill's objections or explicitly accepts them as out-of-scope. Save the grill summary in the manifest'sself_grill_summaryfield (optional schema field today; may be promoted to required in a future iteration once the workflow shape stabilises). If the grill destroys the plan (a premise can't be defended), revise the plan before plan-eng-critic runs — do not present a known-broken plan to the critic.planstage — run/domain-modelingagainst the repo'sCONTEXT.mdbefore the plan artifact is written. If the repo has aCONTEXT.md, the plan uses its terms and no synonyms; a term the plan needs that the glossary does not define is a gap, and the fix is to settle it and write it there inline, not to invent a second word for it in the plan. If the repo has noCONTEXT.md, create one at the first term the episode settles and leave it at that: lazy creation, glossary only, no implementation detail, never a spec. Offer an ADR only when all three of the skill's tests hold (hard to reverse, surprising without context, a real trade-off with alternatives). Record the terms touched in the plan manifest'sself_grill_summaryalongside the grill. This is the cheapest defence the orchestrator has against multi-session drift: episodes on one target span compactions, and a glossary on disk survives what the context window does not.planandexecutecritic briefings — pass the/codebase-designvocabulary verbatim. Briefplan-eng-criticandcode-review-criticto phrase every structural finding in that skill's terms: module, interface, implementation, depth, seam, adapter, leverage, locality, plus the deletion test and "one adapter is a hypothetical seam, two is a real one". Do not let a critic reach for component, service, API or boundary. The reason is the learn step, not style: §6 clusters findings across episodes, and clustering is string-shaped, so two critics describing one defect in two vocabularies produce two clusters of one instead of one cluster of two, and the delta never crosses the tier threshold. Findings shape is unchanged ({"severity", "message", "location"}); this constrains the wording insidemessage.(Optional, opt-in) Meta-critic mode — when a critic returns
pass, the orchestrator MAY run/grill-meagainst the critic's verdict + reasoning, asking "did this pass actually hold up under adversarial pressure?" If the grill breaks the pass (surfaces an issue the critic missed), the verdict becomes provisional: record asfrictionviaepisode-frictionand either re-run the stage with the missed concern in the must-fix, or escalate to the human. This is expensive (extra sub-agent per pass) and OFF by default — opt-in viaepisode-init --meta-critic-grill. Reserve for high-stakes episodes (production deploys, schema migrations, security-touched diffs). Tier 10'slearn-evolvereadsfrictionnotes flagged this way to propose critic-prompt mutations.
/full-power is d
…(truncated)