Skip to content

Multi-Agent Operating Model (Claude Code + Codex)

Status: Active Last reviewed: 2026-06-30

TwoMore is worked by two agent systems — Claude Code (planning / orchestration / verification) and Codex (frontier implementation editor). This doc is the contract that keeps them reading the same rules and prevents the two instruction systems from drifting apart. If this conflicts with AGENTS.md, AGENTS.md wins.

Why two agents

  • Claude Code — plans, designs, reviews, verifies, commits, and runs the OTA flow. Auto-loads CLAUDE.md + AGENTS.md every turn.
  • Codex (codex MCP server, registered user-scope; or codex exec via shell) — a frontier implementation model used as the editor for hard, self-contained, logic-heavy work, and as a second-model reviewer for risky surfaces. Auto-loads AGENTS.md only (capped by project_doc_max_bytes).

Model diversity is the prize: a different model catches different things and shoulders implementation load when Claude is rate-limited. The risk is drift — the two systems silently diverging on the rules. The three layers below exist to prevent that.

The three instruction layers

LayerBytes / budgetClaude readsCodex readsHolds
AGENTS.md≤ 28,672 (lint-enforced)referencedyes, nativelyHard, mechanically-enforced constraints (the ID | Rule | enforcement tables)
CLAUDE.mdthin (orchestration core)yes, auto every turnnoHow-I-Work, workflow, delegation, terminology, compaction invariants, + a pointer index to canon
docs/canon/*on-demandvia Read / doc-routervia injected task specThe soft canon (design + implementation conventions) — single source, loaded only when relevant

The rule that prevents drift: every rule lives in exactly one layer.

  • A mechanically-enforceable hard constraint → AGENTS.md (both agents auto-load it).
  • A soft convention (design judgment, IA, naming, patterns) → docs/canon/* (loaded on demand).
  • CLAUDE.md never restates canon — it only points to it. If you find yourself copying a canon rule into CLAUDE.md, stop: leave a pointer instead.
  • Never duplicate a rule across layers. Duplication is the drift.

How canon reaches Codex

Codex has no @import/include directive (verified against the Codex config reference — it loads AGENTS.md up to project_doc_max_bytes, with project_doc_fallback_filenames as the only extension). So canon does not auto-reach Codex. Two sanctioned mechanisms:

  1. Orchestrator injection (default). When Claude hands Codex a task, Claude pastes the relevant docs/canon/* file(s) into the task spec. The split-by-topic canon makes this precise — hand Codex status-and-recruitment.md, not all canon.
  2. Codex reads the file as a task step. For larger tasks, the spec instructs Codex to Read docs/canon/<topic>.md before editing.

Do not try to solve this by importing all canon into AGENTS.md — it would blow the 28,672-byte lint budget and bloat every Codex call.

Codex-as-editor handoff protocol

Claude (orchestrator)  → research → plan → write a scoped task spec
                         (inject the governing AGENTS.md IDs + relevant docs/canon/* slice)
Codex (editor)         → implement in a workspace-write sandbox → self-run `yarn check`
Claude (orchestrator)  → independently run `yarn check` + `yarn lint:strict`
                         → review the diff against canon → commit → push → OTA

Non-negotiables:

  • The verify + commit + OTA gates stay with Claude (AOR-7 / AOR-8). Claude never claims done on Codex's word.
  • Codex review is read-only (--sandbox read-only); the second-model reviewer is input, never an editor and never authority.
  • Codex-as-editor is scoped to hard, self-contained, logic-heavy work. Pattern-application and design-system-touching work stays with Claude Agent(model: "sonnet") subagents, which inherit CLAUDE.md automatically (no canon-injection gap).
  • Reach for a second-model review on risky surfaces: auth, RLS / SECURITY DEFINER migrations, payments (Portone / session_payments), PIPA / consent, concurrency, or 5+ file refactors.

Canon extraction recipe (proven by the pilot)

Use these exact steps to move a topic out of CLAUDE.md into docs/canon/ (validated on status-and-recruitment.md):

  1. Locate the topic's blocks in CLAUDE.md (exact line numbers; note interleaved bullets that belong to a different topic and must stay).
  2. Create docs/canon/<topic>.md — dual-audience: a # Title + **Status:** Active / **Last reviewed:** header (required by the doc-inventory audit), a one-paragraph intro for humans, ##/### sections for the VitePress outline, then the rules verbatim. Convert [text](packages/…) source links to code spans (preserving the path) — VitePress dead-link checking fails on links to non-page .ts files; this matches screen-blueprint.md.
  3. Thin CLAUDE.md — replace the moved blocks with a one-line pointer that keeps the single hardest invariant inline + links to the canon doc.
  4. Register in scripts/doc-state-config.mjs: add to CURRENT_ACTIVE_DOCS (tracked + stale-linted) and to the Conventions group in SITE_REFERENCE_GROUPS (VitePress sidebar).
  5. Wire the sidebar — the Conventions section already exists in docs/.vitepress/site-sidebar.mjs; new canon docs only need the SITE_REFERENCE_GROUPS entry from step 4.
  6. Verify: yarn docs:generateyarn docs:check (state + stale + rule-docs + vitepress build) → yarn lint:agents-mdyarn check.
  7. Commit (docs-only → no OTA; the OTA-after-change rule is for shipped app behavior, not docs).

Drift-prevention checklist (run when adding or changing a rule)

  • [ ] Is this a hard constraint? → AGENTS.md (with an enforcement value). Soft? → docs/canon/*.
  • [ ] Did I avoid restating it in CLAUDE.md? (pointer only)
  • [ ] Is it in exactly one layer? (no duplication)
  • [ ] If it's a new canon doc: Status header + registered in doc-state-config.mjs + docs:check green?
  • [ ] If Codex will touch the affected area: is the canon doc in the handoff spec?

See also

Markdown remains the source of truth. Run yarn docs:check before handoff.