Skip to content

M3.5: multi-model (maker/checker) loops — roles, agent compiler, inter-stage/intra-run orchestration - #4

Open
dpickem wants to merge 7 commits into
mainfrom
feat/m3.5-multi-model
Open

M3.5: multi-model (maker/checker) loops — roles, agent compiler, inter-stage/intra-run orchestration#4
dpickem wants to merge 7 commits into
mainfrom
feat/m3.5-multi-model

Conversation

@dpickem

@dpickem dpickem commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

M3.5 makes a loop able to decompose into per-role agents on different
providers
— e.g. a gpt-5.5 implementer and an opus reviewer — and adds the
runtime plumbing to make that portable and safe. A role binds a vendor-neutral
agent definition (behavior) to an execution binding (vendor + model); the
agent definition is the single source of truth for behavior and the engine is a
swappable binding on top of it.

Two execution modes:

  • inter-stage (portable default): each role runs as its own ordered adapter
    invocation and hands a structured artifact (status, promoted ledger output
    paths + sha256 digests, stdout) to the next stage through the memory ledger.
  • intra-run: role agent definitions are compiled into the harness runtime's
    native sub-agent format and one invocation spawns them as sub-agents.
    Cross-provider intra-run is native only on Cursor.

A single normalized ExecutionPlan (resolving the --vendor override, per-role
vendor/model, read-only policy, and output ownership) drives dry-run, preflight,
and execution so the paths cannot drift.

Cross-provider Cursor spawn — verified live

The exit criterion "a Cursor loop spawns a cross-provider sub-agent" is
demonstrated against a real cursor-agent: a gpt-5.5-high main agent spawned
the compiler-emitted reviewer sub-agent running on claude-opus-4-8-high
(confirmed via the run's structured taskToolCall, which carries
subagentType.custom.name = reviewer and model = claude-opus-4-8-high). The
opt-in smoke test reproduces it and is skipped offline per CONTRIBUTING.md:

LOOPCRAFT_LIVE_CURSOR=1 uv run pytest tests/test_cursor_live.py -q

Caveat: per-sub-agent model selection is plan-dependent (Max Mode / usage-based);
legacy request-based plans without Max Mode may fall back to the parent model.

What's included

  • Manifest: roles block (Role = agent + vendor/model + own outputs),
    execution mode, role-name vocabulary, role-output validation, and role
    outputs in fleet producer-collision/DAG analysis.
  • Agent definitions (agents.py) and compiler (agent_compiler.py):
    compiles a role def + model into the runtimes' current native schemas —
    .cursor/agents/*.md and .claude/agents/*.md (Markdown + YAML frontmatter),
    .codex/agents/*.toml (developer_instructions + sandbox_mode); compiled
    name = role key (unique destinations); verify compiles into the instructions.
  • Orchestrator (orchestrator.py): normalized plan; inter-stage + intra-run;
    mode-correct preflight; reviewer verdict gating; read-only enforcement;
    aggregate runtime budget; structured handoff persisted to the ledger.
  • Worktree-local outputs + safe promotion (outputs.py): outputs staged in
    the worktree and promoted by the control plane (no out-of-worktree writes);
    TOCTOU-safe (O_NOFOLLOW + fstat, unique mkstemp + atomic replace,
    validate-all-before-replace).
  • Shared run/apply/deps check preflight; --vendor override propagation;
    durable per-stage StageRunResult records; corrected Cursor docstring.

Enforced vs deferred (M3.5 scope)

Enforced: per-role vendor/model; output ownership consistent across
modes/dry-run/fleet; read-only reviewer (control-plane hash check inter-stage;
native readonly/sandbox_mode intra-run; read-only role rejected under a
Claude harness); a single explicit reviewer Verdict: PASS/FAIL
(missing/conflicting/FAIL fails and stops the pipeline); safe, success-gated
promotion; aggregate runtime budget from pipeline start; live Cursor
cross-provider sub-agent spawn
(above). Role tools are policy-validated
(READ/EXECUTE/WRITE), not yet mapped to runtime-native allowlists.

Deferred (documented, not dropped): a code maker/checker against a real Git
worktree/diff (with L4); max_turns/max_tokens enforcement (needs adapter
usage telemetry) and max_consecutive_failures (scheduler/store boundary).

Review history

Two review rounds are addressed in-branch, each with a report + response under
docs/review_notes/:

  • Review 01 (0a75645): shared preflight; mode-correct preflight; read-only
    enforcement; verify/tools; success-gated + symlink-safe promotion; structured
    handoff; normalized ownership plan; --vendor propagation; current runtime
    schemas; role-name/stage-log containment; aggregate runtime budget; unique
    compiled destinations; CLI-level tests; typed signatures.
  • Review 02 (c00ef10): verdict gating + pipeline stop; intra-run verdict +
    harness read-only/model-compat gating; promotion TOCTOU hardening;
    plan-consistent effective_outputs; ledger-persisted handoff + untrusted-stdout
    fencing; durable typed stage records; dry-run uses the plan; Pydantic models;
    role-tool policy validation; fail-closed direct execution.
  • Live Cursor verification (92005e9): the cross-provider spawn demonstrated
    end-to-end + opt-in smoke test.

Test plan

  • make test410 passing, 1 skipped (the opt-in live test), fully offline
  • make compile / make validate / make check
  • Live (optional, paid): LOOPCRAFT_LIVE_CURSOR=1 uv run pytest tests/test_cursor_live.py -q

Note: two offline tests write .cursor/agents/...; they pass in CI and with
the sandbox disabled, but fail under a local Cursor sandbox that protects
.cursor paths.

Daniel Pickem added 5 commits July 8, 2026 17:12
Introduce per-role maker/checker loops that run different models on
different providers, plus the runtime plumbing to make them portable and
safe.

- Manifest: `roles` block (agent + vendor/model binding) and `execution`
  mode (inter-stage default / intra-run); `Role.outputs` so a read-only
  reviewer can write its own review notes without touching code or the
  maker's outputs. Skill is optional when roles are present. Validation
  covers role agent paths, role state outputs, and the intra-run
  cross-provider -> Cursor rule.
- Agent definitions (`agents.py`): vendor-neutral markdown-with-frontmatter
  behavior specs (name/description/readonly/tools/verify + body).
- Agent compiler (`agent_compiler.py`): compile a role def + model into
  `.codex/agents/*.toml`, `.claude/agents/*.md`, `.cursor/agents/*.yaml`.
- Orchestrator (`orchestrator.py`): inter-stage (ordered adapter runs,
  handing output through the ledger) and intra-run (compiled sub-agents in
  one Cursor harness); roles preflight.
- Worktree-local outputs + promotion (`outputs.py`): declared outputs are
  staged inside the worktree and promoted to the ledger by the control
  plane after the run. No adapter writes outside its worktree, so
  Codex/Claude drop `--add-dir` and Cursor keeps its sandbox — removing the
  coarse `--sandbox disabled` grant from the normal path.
- Cursor writable-root parity (out-of-worktree targets still supported).
- Example agent defs (`agents/implementer.md`, `agents/reviewer.md`) folding
  in Andrej Karpathy's LLM-coding principles.
- Tests for manifest roles, agent parsing/compiling, and orchestration.
- README + design-doc updates.
…ane wiring)

Resolves findings 1-19 of the M3.5 review.

- Shared preflight dispatch (deploy.resolve_preflight) used by run, apply, and
  deps check, so a roles loop is validated through the multi-model path
  everywhere (F1). --vendor override is propagated to inherited role vendors
  (F8), and preflight/execution share one normalized ExecutionPlan (F7).
- Mode-correct preflight: intra-run checks the harness binary + compiles every
  role for it; inter-stage preflights each role's own adapter via its
  single-stage manifest (F2, F13).
- Read-only reviewer enforced by the control plane: a checker that modifies any
  protected worktree file fails the run and is not promoted (F3).
- Agent verify + tools now govern runs: verify compiles into the instructions
  and is verdict-parsed (PASS/FAIL); tools are classified and a read-only role
  may not hold a writing tool; unmappable tools fail preflight (F4).
- Promotion is transactional and success-gated: outputs promote only when a
  stage/run fully succeeds, via temp-file + atomic replace, and symlink/
  non-regular outputs are refused (lstat) (F5, F10).
- Structured inter-stage handoff (status + promoted paths/digests + stdout);
  Git-diff code maker/checker explicitly deferred with L4 (F6).
- Compiler tracks current runtime schemas: Cursor/Claude Markdown+frontmatter,
  Codex TOML developer_instructions + sandbox_mode; compiled name = role key
  (unique destinations) (F9, F16).
- Role names validated to a safe vocabulary; stage-log paths asserted contained
  (F11). Role outputs participate in producer-collision/DAG validation (F15).
- Aggregate runtime budget enforced across stages; deterministic aggregate
  status and preserved per-stage metrics (F12, F14).
- CLI-level roles tests (run/apply/deps, reviewer mutation, failed promotion),
  fully typed test signatures + typed call records (F17, F18). Cursor docstring
  corrected (F19). README + design doc updated.
…nsistency)

Resolves review-02 blocking findings 1-8 and significant findings 9-15.

- Reviewer verdict now gates the pipeline: a read-only role with a verify
  rubric must emit exactly one explicit `Verdict: PASS|FAIL`; missing,
  conflicting, or FAIL fails the stage before promotion (B1). Applies to both
  inter-stage and intra-run (B3).
- The pipeline stops on any non-success stage, including a failed/ rejecting
  reviewer, so later mutating roles never run (B2).
- Intra-run enforces read-only support per harness (rejects a read-only role
  under a Claude harness) and validates harness/role model+provider
  compatibility, including cross-provider-needs-explicit-model (B3, B5).
- Promotion is TOCTOU-safe and transaction-validated: sources open with
  O_NOFOLLOW + fstat, copy via a unique mkstemp temp + atomic replace, all
  bindings validated before any destination is replaced, and ledger containment
  re-asserted (B4).
- One normalized ExecutionPlan.effective_outputs drives intra-run bindings,
  inter-stage provenance, dry-run, and run-record declared outputs; manifest
  effective_outputs excludes unowned top-level outputs (B6).
- Structured handoff is persisted to (and reconstructed from) the ledger, and
  prior-stage stdout is fenced+labelled untrusted to resist prompt injection
  (B7, S14). Design/README M3.5 scope + budget reconciled (B7, B8).
- Aggregate runtime budget measured from pipeline start incl. overhead (B8).
- Durable typed StageRunResult persisted in the run record (S9); dry-run uses
  the plan (S10); execution-plan/handoff/stage models are Pydantic and new test
  signatures are fully typed (S11).
- Role tools reframed as policy validation with READ/EXECUTE/WRITE classes: a
  read-only reviewer may spawn sub-reviewers and run tests; connectors are not
  auto-classified as writing; unknown tools fail (S12).
- run_multi_model fails closed on planning problems (S13); cursor preflight
  docstring corrected (S15).
- New regression tests: verdict FAIL/missing + pipeline stop, durable stages,
  explicit maker outputs + dry-run, intra-run harness/model gating,
  promotion symlink/prevalidate-all, fail-closed planning, handoff delimiter.
@dpickem dpickem changed the title M3.5: multi-model loops (roles, agent compiler, inter-stage/intra-run orchestration) M3.5: multi-model (maker/checker) loops — roles, agent compiler, inter-stage/intra-run orchestration Jul 9, 2026
Daniel Pickem added 2 commits July 9, 2026 15:01
Verified end-to-end against a live cursor-agent: a gpt-5.5-high main agent
spawns the compiler-emitted `reviewer` sub-agent running on
claude-opus-4-8-high (confirmed via the run's structured taskToolCall),
satisfying the M3.5 cross-provider exit criterion.

- Add opt-in live smoke test tests/test_cursor_live.py, skipped by default
  (LOOPCRAFT_LIVE_CURSOR=1) so the suite stays offline per CONTRIBUTING.md; it
  drives the real agent_compiler output through cursor-agent and asserts the
  cross-provider sub-agent spawn from stream-json.
- Remove the "not demonstrated / schema-tested only" limitation from README and
  the design doc; note the plan/Max-Mode caveat for per-sub-agent model honoring.
  The Git-diff code maker/checker remains deferred to L4.
Document the remaining correctness and safety gaps after the Review 02 fixes so the next iteration has an explicit merge gate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant