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.mdevery turn. - Codex (
codexMCP server, registered user-scope; orcodex execvia 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-loadsAGENTS.mdonly (capped byproject_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
| Layer | Bytes / budget | Claude reads | Codex reads | Holds |
|---|---|---|---|---|
AGENTS.md | ≤ 28,672 (lint-enforced) | referenced | yes, natively | Hard, mechanically-enforced constraints (the ID | Rule | enforcement tables) |
CLAUDE.md | thin (orchestration core) | yes, auto every turn | no | How-I-Work, workflow, delegation, terminology, compaction invariants, + a pointer index to canon |
docs/canon/* | on-demand | via Read / doc-router | via injected task spec | The 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.mdnever 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:
- 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 Codexstatus-and-recruitment.md, not all canon. - Codex reads the file as a task step. For larger tasks, the spec instructs Codex to
Read docs/canon/<topic>.mdbefore 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 → OTANon-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 inheritCLAUDE.mdautomatically (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):
- Locate the topic's blocks in
CLAUDE.md(exact line numbers; note interleaved bullets that belong to a different topic and must stay). - 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.tsfiles; this matchesscreen-blueprint.md. - Thin
CLAUDE.md— replace the moved blocks with a one-line pointer that keeps the single hardest invariant inline + links to the canon doc. - Register in
scripts/doc-state-config.mjs: add toCURRENT_ACTIVE_DOCS(tracked + stale-linted) and to the Conventions group inSITE_REFERENCE_GROUPS(VitePress sidebar). - Wire the sidebar — the
Conventionssection already exists indocs/.vitepress/site-sidebar.mjs; new canon docs only need theSITE_REFERENCE_GROUPSentry from step 4. - Verify:
yarn docs:generate→yarn docs:check(state + stale + rule-docs + vitepress build) →yarn lint:agents-md→yarn check. - 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
enforcementvalue). 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:
Statusheader + registered indoc-state-config.mjs+docs:checkgreen? - [ ] If Codex will touch the affected area: is the canon doc in the handoff spec?
Venue closeout coordination — 2026-09-07
Codex completed local venue closeout in the isolated /home/sungkyu08/Dev/twomore-v2-venue-pipeline worktree, starting from a024d5b4. The bounded source retries, completed collector connection, acceptance evidence and Claude release actions are tracked in docs/audits/venue-closure-2026-09-07.md in that worktree. Source completeness and live deployment are separate from local implementation acceptance. Wider backend work remains paused. This notice and the queue notice below are the only Codex changes to the main checkout; runtime work stays isolated. The final yarn check, focused strict lint and collector review pass. The exact Naver record still lacks evidence (2,324/2,325); the bulk refresh stays blocked. Claude owns the three venue-component merge conflicts and the subsequent release proof.
Active queue integration coordination — 2026-09-07
Codex has completed local implementation and verification of the account-switching/ offline-queue slice in the isolated /home/sungkyu08/Dev/twomore-v2-venue-pipeline worktree on codex/venue-pipeline-20260906, starting at 9e5d67c7. Its scope is session/auth ownership, mutation queue/replay, the 15 existing queue producers, scoped adapters, and their tests. Shared integration points are packages/app/src/{index,registry}.ts, ports/index.ts, apps/mobile/app/_layout.tsx, and apps/web/app/providers.tsx. Avoid concurrent edits to those points until the handoff is reviewed. Claude's current wireframe/UI work remains in the main checkout. No push, hosted migration, or deployment is part of this slice.
The live plan, acceptance evidence, remaining gaps and next owner action are in /home/sungkyu08/Dev/twomore-v2-venue-pipeline/docs/audits/account-queue-orchestration-2026-09-07.md. Codex self-verifies and hands the diff to Claude for independent orchestration and merge/release review. This notice is copied to both worktrees; it is the only Codex edit to the main checkout in this continuation.
Active session boundaries (2026-09-05, flat detail-page migration × venue integrity work)
Two agents edit this worktree at once. Ownership is by path; neither stages, reverts, or reformats the other's files, and neither runs supabase db push or an OTA while the other has uncommitted work.
| Owner | Paths | Notes |
|---|---|---|
| Codex (venue integrity verification) | packages/app/src/domain/entities/venue*, adapters/supabase/venue*, packages/features/sessions/src/directory-venue-detail/**, venue-correction/**, venue-*, packages/features/clubs/src/club-venue*, scripts/audit/**, scripts/lib/**, supabase/functions/{enrich,ingest,corroborate}-venues/**, supabase/migrations/005[89]*+, docs/history/venue-*, docs/audits/venue-*, root package.json test scripts | The 2,347-row legacy Naver Place refetch cohort stays here unless explicitly handed over. |
| Claude (flat detail pages, waves P→1→3) | packages/ui/**, packages/eslint-plugin/**, packages/features/sessions/src/session-detail/** + session-detail-screen.tsx, packages/features/profile/**, packages/features/records/**, packages/features/clubs/src/{join-review-detail-screen,public-club-profile*,post-detail*}, docs/design/detail-pages-*, docs/twomore_design_system/wireframes/detail-flat-language.jsx | Wave 2 (venue detail screens) is deferred until Codex's venue pass lands; it will start from the then-current directory-venue-detail/**. |
Shared files (packages/app/src/index.ts, domain/index.ts, docs/README.md, generated state docs): commit only your own hunks; regenerate with yarn docs:generate right before committing.
See also
- AGENTS.md — the hard-constraint contract both agents load.
- Conventions › Status & Recruitment — the first extracted canon doc (the pilot).
- Change Routing — what to read / update / verify by change type.
- CLAUDE.md — orchestration core + canon pointer index.