type: meta

slug: mega-plan-harness

topic: provider-agnostic plan-execution harness: shared shell core + standalone Node runner + DynWF driver

exec_mode: ship

scheduler: dag-parallel

seat: codex

land_mode: merge-to-main

base_branch: main

status_enum: BLOCKED PENDING WORKING WRITTEN REVIEWED COMMITTED

truth_rule: this file is ground truth for INTENT; git is ground truth for DONE-NESS — reconcile statuses against git, never trust a COMMITTED line with no commit

refresh_how: native Read of THIS file — NEVER ctx_execute/ctx_search

refresh_what: meta + every goal/methodology/intent/direction record + all WORKING and BLOCKED tasks

refresh_when:
wave/phase boundary
any task status change
after a compaction system-reminder
before calling advisor

update_rule: on status change, rewrite that task's single line in place; append new tasks/session_memory as new lines

report_rule: at session end emit brief: done / blocked / deferred / canceled — NO next-action

glue_model: haiku

codex_impl_effort: low

codex_review_effort: low


type: goal

text: Build mega-plan-harness Plan A: shared shell core (resolve-seat, wrappers incl codex, gates, journal) + standalone anthropic-less Node runner + DynWF driver + presets + tests. ~/.claude run-plan.js cutover AND its sonnet->haiku declassify are Plan B (separate run).


type: methodology

text: Contract-first per spec/ docs (WRAPPER-CONTRACT, PRESETS, FORK, schemas — single source of truth, never duplicate). Each shared-core unit = a CLI both planes invoke identically; control planes hold ONLY control flow. Test both branches (success + fail-closed) per unit. Vendor existing na.sh/ca.sh/cx.sh/risk-router.sh + the tested gate0 lib, adapt to contract.


type: intent

text: Execution must run standalone outside Claude Code (droppable into opencode/codex), engine-agnostic + per-run configurable via presets. Anthropic only plans/launches. Standalone runner is the day-1 product; DynWF is an optional thin front-end sharing the same core.


type: direction

verbatim: Fail-closed everywhere: unexpected state → error+detail, never guess/force. Env scoped to the subprocess, no leak to caller.


verbatim: Deterministic gates (gate0=tsc/lint/test, risk-router) are NOT preset seats — always run, never bound/omitted. Only model-bound seats (coder/reviewer/fixer) are bindable.


verbatim: No stubs/placeholders/workarounds in DELIVERABLE code — full functionality. A contract/spec that pins the seam is NOT a stub.


verbatim: Comments document WHAT is non-obvious about code, NEVER why-you-chose-it. Default zero comments.


verbatim: Standalone runner has ZERO Anthropic dependency and NO model anywhere in its loop; shared core is shell CLIs (DynWF script body cannot require a JS module).


verbatim: Plan node vocabulary = seat + tier, NEVER an engine id (no task.executor). The preset maps tier->engine. The Anthropic planner pins tier at author time; no runtime classify model in either plane.


verbatim: Binding.model = the ENGINE model, pinned IDENTICALLY by both planes (runner passes it to spawn, does NOT ignore it — the ca.sh wrong-model regression). The only model that drifts is the DynWF dispatch agent's own model:'haiku', which lives in the ~10-line dispatch glue, never in the binding.


verbatim: haiku (DynWF dispatch agent) and tier:low->north (engine binding) are DIFFERENT layers — never conflate 'haiku' with the low-coder seat; that is a category error that misresolves bindings.


type: anchor

what: fork contract (2 planes, shared core, journal schema)


what: uniform engine wrapper CLI + exit codes


type: deferred

text: Optional anthropic-less pre-flight: invoke na.sh directly in a disposable repo (zero model, pure wrapper) to harvest real engine exit-code vocabulary and verify WRAPPER-CONTRACT 0/124/2/3 + 'any other nonzero' coverage before the runner consumes those codes.

reason: contract-completeness validation, not a build dependency — run before/alongside wave 1 if desired


type: task

seat: coder

tier: medium

desc: Vendor wrappers to wrappers/: na.sh (verbatim, already contract-clean), ca.sh (adapt rc to emit 0/124/2/3 distinctly — currently set -e), codex.sh (vendor+adapt from ~/.claude/workflows/lib/cx.sh). Add wrappers/_contract-probe.sh <wrapper> asserting the fixed flag set + exit-code map against a mock engine. Each MUST satisfy WRAPPER-CONTRACT.md.

status: COMMITTED


tier: high

desc: Build lib/resolve-seat.sh: --plan <jsonl> --runconfig <json> --node <id> -> stdout binding JSON exit 0; resolution ladder PRESETS.md rungs 1-3 (override->tiered->flat), rung 4 unresolvable -> exit 2 + stderr {ok:false,detail} fail-closed; MUST reject gate0/risk as non-seats (exit 2). Pure fn of (plan,runconfig,node). lib/test-resolve-seat.sh asserts every rung + gate-rejection + unknown/cyclic fail-closed (both branches), run-plan-lib.sh test pattern.


desc: Build lib/journal.sh: append <jsonl> <record> (one line, never pretty), state <jsonl> <task> -> last state, reconcile <jsonl> <repoRoot> <branch> -> re-derive done-ness from git + downgrade phantom COMMITTED. runstate/v1 schema per FORK.md. lib/test-journal.sh both branches.


desc: Build lib/gates.sh wrapping the EXISTING tested gate0 (vendor gate0_* funcs from ~/.claude/workflows/lib/run-plan-lib.sh; modes strict + baseline-ratchet, default strict) + vendor risk-router.sh to lib/. Deterministic, NEVER a seat; repo-agnostic check discovery, fail-closed if none. lib/test-gates.sh reusing the existing lib's tests as vendoring fidelity check.


desc: Author presets/anthropic-less.json + presets/codex.json (preset/v1), wrapper paths repo-relative wrappers/<x>.sh. Build presets/_validate.mjs (zero-dep) asserting every preset + example runconfig vs spec/{presets,runconfig}.schema.json AND every bound wrapper path resolves to an existing executable (no vapor).


desc: Build src/runner.js: harness run --plan --runconfig [--concurrency N] [--resume]. Control flow ONLY (FORK iron rule): parse->wave groups->bounded Promise pool; per task lease->resolve-seat->child_process.spawn(wrapper) passing binding.model->gate0 bounded retry-fix->risk->[review if seat bound]->commit; journal each transition; compute base/head shas itself; fail-closed halts (wrapper 2/3, gate-not-green-after-N, resolver error); fallback on 3/repeated-124 bounded 4 hops cycle-detected; --resume = journal.reconcile then advance to next APPLICABLE state. NO model anywhere. Imports lib/*.sh via child_process, never a JS port.

requires_decision: g-protected-src


desc: Build src/dynwf-driver.js: Workflow-script form of the SAME loop, allowed drift only (FORK.md). Plan via args injection (no FS); dispatch = agent(prompt,{model:'haiku',schema}) whose prompt shells out to resolve-seat.sh + the wrapper and transcribes rc (pure dispatch+transcribe, NEVER judgment); concurrency/resume via Workflow parallel/runId; journals SAME runstate/v1 at SAME per-task granularity; re-derive in-flight state from git+JSONL on compaction.


desc: Runner integration test: fixture plan + stub wrapper (echoes a diff) -> assert journal transitions leased->...->committed AND a fail-closed halt on stub exit 3.


desc: DynWF drift-guard dry-run: assert the DynWF driver shells the SAME resolve-seat.sh + wrapper paths as the runner (two planes MUST call identical core CLIs — the FORK delete-and-rebuild seam).


type: gated

category: input

needs: Source paths for na.sh and ca.sh vendoring

why: Task desc mentioned ~/.claude/workflows/lib/ paths that do not exist

blast_radius: w1.p1.t1 vendoring

status: RESOLVED

answer: proceed

resolved_by: preflight-scan


needs: Source path for risk-router.sh

why: Task desc gave no source path

blast_radius: w1.p4.t1 gates.sh build

answer: proceed


category: architecture

needs: codex.sh invocation shape

why: Task says vendor+adapt from cx.sh but cx.sh has review|integrate mode interface, not WRAPPER-CONTRACT.md interface

blast_radius: codex.sh interface mismatch breaks all codex-preset runs

answer: proceed


needs: How codex.sh parses compound model strings like gpt-5.5-high

why: codex exec takes separate -m <model> -c model_reasoning_effort=<effort>; presets pass gpt-5.5-high as --model

blast_radius: wrong effort dispatched on every codex seat

answer: proceed


w1.p1.t1 vendoring paths: na.sh vendor from ~/.claude/skills/north-orchestrator/na.sh; ca.sh vendor from ~/.claude/skills/cursor-orchestrator/ca.sh. Task description paths (~/.claude/workflows/lib/) do not exist.


w1.p4.t1 risk-router.sh vendor from ~/.claude/skills/multi-orchestrator/risk-router.sh.


w1.p1.t1 codex.sh MUST implement WRAPPER-CONTRACT.md interface (--workspace --trust --task-slug [--model] [--timeout]). Borrow cx.sh patterns for timeout/stdin/test-seam discipline only. Do NOT copy cx.sh review|integrate CLI shape.


codex.sh model string parsing: split on last dash. gpt-5.5-high -> model=gpt-5.5 effort=high. Document <model>-<effort> convention in WRAPPER-CONTRACT.md. Unknown suffix -> exit 2.


category: policy

needs: Allow Wave 2 source tasks to modify their declared src/ implementation and test files

why: Harness protects src/; these tasks' declared deliverables are in src/.

blast_radius: w2.p2.t1 and w2.p3.t1 only

resolved_by: user