---
LLM: Claude
type: blueprint
slug: ai-team-across-engines
lang: en
date: 2026-09-05
title: "Blueprint: AI Team Across Engines"
tagline: HQ on a strong model, workers priced to the task, every role written once and run on any engine
description: One long-lived HQ session holds context and decisions, headless workers do the work on models priced to the task, and roles are described once and run on Claude, Codex, Grok and Gemini. The file is the unit of work, not the chat; code holds the discipline.
audience: For people running several projects on their own who want their AI sessions to stop dying along with their context
---

# Blueprint: AI Team Across Engines

> **Status: living · v2.0, October 13, 2026.** This is how a team of one person and several hundred AI runs a week works: HQ (headquarters — the coordinating session) on Claude Opus 5.5, the hands on Opus and Sonnet, and Codex, Grok and Gemini each on a genre of its own. For scale, one week, October 5 – 11, 2026: 260 teammate runs, 22 roles at work across four engines, 189 tasks closed. Everything below comes out of practice, mistakes included. Until v2 this Blueprint was called "AI Team on Fable + Codex": back then HQ lived on Fable, and there were two engines.

You open Claude Code, pick the strongest model, and do everything in one session: code, writing, research, correspondence. A day later the context is full, the decisions have dissolved into chat, and half your tokens went on routine a model three times cheaper would have handled. There are Codex and other subscriptions sitting right there, but the tools live in different worlds and none of them knows what the others did. The session dies, and everything it "remembered" dies with it.

This Blueprint describes a different shape: **one long-lived HQ session on a strong model holds context and decisions, the work is done by disposable headless workers on models priced to the task, roles are described once and run on any engine you've wired in, and everything that matters lives in files rather than chats.** HQ is a manager, not a doer. The file is the unit of work. The human has the last word on a short list of irreversible actions. Discipline is held by code, not by the model's promises.

## What you get

- **An HQ session that doesn't die**: it lives through resume, gets a "state of the world" block on startup, and picks up where it left off yesterday. There is one HQ: the standard launch switches background forks off, and the startup hook spots a duplicate and protects the main session's state.
- **A fleet of workers**: every task is a separate headless run in tmux driven by a brief file, with a report file, an exit marker and a watcher; the model is chosen explicitly for the job.
- **A model matrix**: HQ on Opus 5.5 at max effort, substantive work on Opus 5.5 (effort high), mechanics on Sonnet 5.5 at medium effort. Codex has the same two tiers: Astra for substantive work, Sol for mechanics. Grok is the third voice in disputes and does mechanics against an exact brief; Gemini does mechanics only, for now. Background jobs (cross-session memory, for one) run on a cheap cloud model (our memory watcher is set to Haiku 4.5) — or on a local one, if you have the hardware.
- **Teammates beyond any one vendor**: a role is described once, as a card in your notes base, its memory sits next to it, and the launcher hands the same role to any engine on its list.
- **A decision registry with a ball**: every fork that needs the human becomes a card with a default and a path to the artifact, instead of a question in a chat that sinks. The card knows whose move it is and what exactly the human is being asked for.
- **Discipline gates in code**: an answer without a card, a fork in chat, HQ doing the work by hand, a dead inbox monitor, a secret printed to the screen — a hook catches it, not the model's memory.
- **Memory that outlives sessions and vendors**: repo maps, role memory, HQ's file memory, the team constitution.
- **A sync rule**: what one engine did is always visible to the others through a trace in files.

## How to set it up

1. Open a coding agent (Claude Code) **in your home directory or at the root of your notes** — HQ lives where all the projects meet, not inside one repo.
2. Show it this Blueprint: "Build me an AI team following this Blueprint. Start with the section 'Questions to adapt it to you'."
3. The agent assembles the first layer: an HQ card with the rules, a global `CLAUDE.md` with the mechanics, a map of your first repo, a model registry, a worker launcher, a decisions file. That's day one.
4. Week one is the habit: every task longer than half an hour goes to a worker with a brief; HQ does by hand only what would cost more to brief than to do.
5. Week two is roles and a second engine: you set up two or three roles as cards in your notes base, write a constitution of five to eight articles, and wire in Codex (or another CLI) through the same launcher.
6. Week three is gates: every rule the model has broken twice moves into a hook.

## When to use it

- You work alone, but you have more than three projects and they run in parallel: site, content, product, operations.
- You pay for more than one AI tool (Claude, Codex, Grok, Gemini) and you want them working as one team rather than in turns.
- You care about decisions and history — what was decided, why, where the artifact is — not just about output.
- You're willing to accept that the file is the unit of work, and to write briefs instead of handing out instructions in chat.

## When **not** to use it

- One project, one repo, linear work — one session with a good `CLAUDE.md` is enough.
- You don't want to keep tmux, launch scripts, hooks and state files around: this Blueprint is about operations, not about a clever prompt.
- You want a fully autonomous agent with no human in the loop: here the human is in the loop by choice, not because the setup hasn't grown up yet.

## The core idea

**HQ is a manager, not a doer.** HQ's model is expensive in context, not in tokens: every bit of routine done by its own hands pushes out of the window the thing you keep it for — decisions, history, judgement. So the line is written down as a "do it yourself or hand it off" matrix. HQ itself keeps the decision registry, writes briefs, accepts reports, and makes an edit of a couple of calls when the executor is obvious. An agent gets any new artifact meant for the human, code beyond a single line, a deploy, research longer than two searches, and any work in a repo whose thread already has an owner. Exceptions are said out loud only, with the phrase "doing it myself: <reason>".

**Model by task, not by habit.** Substantive work — code design, product, money, research that ends in a conclusion — goes to Opus 5.5 at effort high. Mechanics against an exact checklist — smoke tests, a deploy that already has a plan, moving files, regenerating from ready prompts — goes to Sonnet 5.5 at medium effort. HQ runs on Opus 5.5 at max effort, because its mistakes cost the most. The other engines split into the same tiers. The model is named explicitly in the launch command, its id lives in one registry; a silent substitution is forbidden.

**Files, not chats.** The brief is a file. The report is a file. A decision is a card with a path to its artifact. The team rule: there's an artifact, so there was work; vague means not done. Chat is noise that burns off at the next compaction; a file outlives the session, the model and the vendor.

**One role, many engines.** A role is tied to a genre, not to an engine: it is described once, and Claude, Codex, Grok and Gemini all get the same one. A second engine isn't there as a spare HQ, it's there as a different head: review, independent criticism, long generations, cheap mechanics. The demand on each is the same — it has to see what the others did. Which means the exchange runs through files in a shared format — briefs, reports, cards — rather than copy-paste; what each engine is allowed to read is set separately.

**A second opinion priced to the decision.** The default is "Opus does, Astra reads": the executor on one vendor, the reviewer on another. A full council of three voices only when the decision is irreversible or changes how the human works with the system. The third voice (Grok, in our case) is called when the first two disagree, not to make a quorum.

**The human has the last word, but the list is short.** Not "ask about everything" — one explicit list: sending messages to people, publishing, payments, deploying new systems, migrations on the production database, production configuration, deleting data. Everything else: do it and report. One named exception to "sending messages to people": scheduled recurring columns (in our case a weekly column in two Team2Team spaces, fired by launchd) go out with no human at the moment of posting, but under a previously recorded human decision covering that column, that space and that cadence, The column's opener is a template; if the week has findings, the digest is written by an LLM with no tools at all, while a wrapper script controls the conditions for sending, the address and the network call itself, within a column, audience and schedule approved in advance. The exception lives in a document, not in a head: unrecorded, it is a violation.

**Discipline lives in code, not in promises.** A model that said "I won't do that again" doesn't remember the promise after a compaction. A rule broken twice becomes a hook: it sees HQ's turn and stops it, or at least reminds, until the violation is fixed or named out loud. The details are in "Discipline gates in code".

## Architecture

```
Human
  │  decision cards (dashboard) + chat + mobile bridge
  ▼
HQ — Claude Code, Opus 5.5, effort max, one endless session through resume
  │  writes briefs, reads reports, keeps the decision registry, memory, handoff
  ├──► Launcher: role card + brief → engine and model from the registry
  │      ├─ Claude — `claude -p` in tmux, Opus 5.5 / Sonnet 5.5
  │      ├─ Codex  — `codex exec` in tmux, Astra / Sol
  │      ├─ Grok   — third voice and mechanics against an exact brief
  │      └─ Gemini — mechanics against an exact brief only
  │      brief → report file → EXIT in the log → a message or a section in HQ's inbox
  ├──► The human's Codex threads — right in the notes base; HQ → Codex — a feed file
  └──► Watchers — a Monitor on the inbox, job watchers, launchd jobs, Stop gates
Common ground — one format, access by role and engine: role cards ·
briefs, reports, repo maps · constitution; the notes base, inboxes,
the decision registry and the journal — per the rights of each role
```

**HQ.** One interactive Claude Code session on Opus 5.5. To restart it you use a wrapper command: it resumes the live id from a state file and immediately feeds a startup message, "read the rules and the state of the world". On every start, resume and compaction a hook drops a "state of the world" block into context: the last handoff, decisions that are due, unread inbox sections, the state of the roles, orphaned processes, the path and hash of the card holding HQ's rules. After a compaction HQ rereads its card in full: the summary remembers that the rules were read, not the rules themselves. Once a day or two HQ writes a handoff note: what's hot, what's waiting on the human, what to do first. There is one HQ: the wrapper switches background forks off, the startup hook takes a lock, and a second copy gets a stop on its first line and leaves the main session's state alone — why that had to be coded, and where the protection ends, is in the gotchas.

**Workers.** Every task is a tmux session `job-<slug>` running headless from a brief file. The log goes to a file through `tee`, and the last line is an `EXIT=<code>` marker in that same file — the watcher reads the file, not the screen. The report is a file in the repo's `scratchpad/`, not in a temp folder. Every job has a card in the registry, and the job's slug is the card's id: the launch writes an attempt onto the card, and the exit marker hands the move back to HQ for acceptance by itself. The name of the HQ session the worker reports to is filled in by the launcher from HQ's state file — the code never prints a placeholder "main".

**Roles.** A role is a card in the notes base: mission, zone, canons, boundaries, which engines it may run on and what it runs on by default. Next to it sits `Memory.md` — recurring mistakes, facts, the human's decisions — and the role keeps it itself, on any engine. The session ids of a particular engine live in `state.json` in the agent's home folder: that's an address, not knowledge. Resume-first only when the role's context is genuinely needed — a multi-step task, knowledge of the codebase; a short self-contained task gets a fresh session, because dragging a fat history around costs. The details are in "Named teammates and plain workers" and "Teammates beyond any one vendor".

**The other engines.** A Codex, Grok or Gemini worker is brought up by the same launcher under the same protocol: brief file, report file, exit marker. Codex doesn't have Claude's cross-session messages, so its push to HQ is a small script that appends a section to the inbox file, and HQ's Monitor on that file wakes it up. The other direction is an append-only feed into the Codex inbox: any Codex thread the human has opened in the notes base reads it. Delivered means a trace came back: a report, an artifact or a section in HQ's inbox. We built a long-lived main Codex session with a cursor and then folded it — that's in "Scaling up".

**The decision registry.** A JSON file of cards. Mandatory fields: type (decide / approve / think / do), the question with a paragraph of context, the default, a cost on "approve" cards, the path to the artifact. On top of that a card has a ball — a recorded fact of whose move it is — and the kind of request to the human, from which the dashboard draws the main button. The human answers with a button or a line, the answer is written back into the same file and into the inbox — HQ wakes up and acts. A card without a default is work handed back to the human; an "approve" card without a cost is an automatic yes. The details are in "Cards: the ball, the request, the queue".

**Memory.** Three layers: repo maps (`CLAUDE.md` at the root — stack, structure, entry points, how to restart and how to check), role memory next to the role cards, and HQ's file memory (one fact per file, index loaded at startup). Plus cross-session memory from a plugin: its background watcher makes thousands of calls a day, so it lives on the cheapest model going — something in the Haiku class. We tried a local one and rolled it back: a 27B model held 30 GB of memory and spent its life loading and unloading under eight sessions; we'll come back to it with something smaller.

## Named teammates and plain workers

A worker is a process. A named teammate is a role with a name, memory and a thread. The difference comes down to three things: what survives the task, who owns the project thread, and how HQ addresses the executor.

**A plain worker** is a one-off headless run driven by a brief. Fresh session, the whole context fits in the brief, and once the report is in, the process dies leaving nothing behind but artifacts — a report, a commit — and a line in the team journal. That's the right tool for a self-contained task under half an hour: regenerate images from ready prompts, run a smoke test against a checklist, move files, gather data from known paths, apply an edit that's described exactly. The model follows the genre of the task: Sonnet for mechanics, Opus for a substantive one-off.

**A named teammate** is a role like producer, ops, web, designer, toolsmith, analyst, envoy, or a product role on the "one product, one engineer" principle. A role has five things a worker doesn't:

- **A role definition.** A card in the notes base: who this is, what it owns, which canons it reads first, which engines it may run on. For web that's the deploy canon and the OG gate; for ops, "back up before any surgery on data"; for envoy, "draft, never send".
- **Role memory.** `Memory.md` next to the card: recurring mistakes, facts, the human's decisions in that genre. The role updates its own memory at the end of every task, whatever engine it ran on, and HQ adds to it from the reports. It isn't a diary — it's a list of "what I know that is neither in the code nor in the brief": where the production backups live, which cloud project is the right one, what the human has forbidden for good. The budget is about 40 KB: past it, the launcher tells the role to move the old entries into a monthly archive.
- **State.** `state.json`: the id of the last session, the repo, the date, the last task. That's what makes resume possible: the next task on the same thread continues a session that already carries the codebase and the previous moves, instead of getting introduced from scratch.
- **Ownership of the thread.** Executor continuity: whoever runs a thread — a chain of related tasks — gets the next task on it, even when the genre would suggest a different role. Handing it over takes a written reason and a handoff: status, artifacts, open risks, next move. That's how a product ends up with "its own engineer" who remembers why it was built this way.
- **An address.** HQ addresses the role by name through the launcher (`--role web --brief …`), and the protocol — role, memory, constitution, report — is written into the prompt by the launcher itself. People on the team know the address too: "that's one for ops".

| | Worker | Named teammate |
|---|---|---|
| Lives for | one task | a thread of many tasks |
| Context | all of it in the brief | brief + role card + memory + session |
| Memory | none: journal and artifacts | `Memory.md` by the card + `state.json` |
| Launch | always a fresh session | resume-first, fresh when the context isn't needed |
| Model | by the genre of the task | from the role card, the brief can override |
| Answers for | the result of the task | the project thread, the repo map, the canons |
| When | under half an hour, self-contained | a recurring genre, a codebase, long threads |

**When to create a role.** The rule of three: the genre has come up three times, it has a repo or a canon of its own, and the same mistakes keep repeating because nobody is there to remember them. A role without recurrence is one more thing to feed. A memoryless worker in a recurring genre makes the same mistake every week.

**What a role does better than a worker.** It remembers production: where the backups are, how to restart, which smoke tests are mandatory. It reads the repo map like someone coming back, not like a newcomer. It catches what changed since its last visit with a `git log` at the start of the task. It knows the human's decisions in its genre: what's forbidden, what's approved standing. It carries on a multi-step task without a retelling of the history in the brief.

**What it costs you.** Resume drags the session history along — slower and more expensive — so a short self-contained task goes to the role as a fresh session rather than a continuation. Memory rots if nobody reviews it. Two instances of one role at the same time corrupt its state: the session id gets overwritten, so parallel tasks for one role either queue up or the second one goes to an anonymous worker. And a role without a human owner turns into a dumping ground for notes.

**Life cycle.** Birth: a role card from the template, empty memory, and a first task that writes the repo map. Working life: resume-first when context is needed; at the end of every task — memory, report, message to HQ. A weekly review: HQ reads the role's memory and decides what's stale, what's ready to be codified into a hook or a repo map, and what to delete. Retirement: the genre is gone, the role is archived, the memory stays as a reference.

**Roles and vendors.** A role is tied to a genre, not to an engine: our curator, who owns the encyclopedias and decks, runs on Codex by default, while web and toolsmith run on Claude — and any of them can move to another engine on its list. How that works is the next section.

## Teammates beyond any one vendor: one role, any engine

Until October 8, 2026 a role lived in Claude's files: the agent definition in its folder, the memory in `~/.claude/teammates/<role>/MEMORY.md`. Other engines saw it through those files or through a separate instruction. Now there's one canon, and it lives where everyone reads it — in the notes base.

**The role card.** `Teammates/<Role>/<Role>.md` in the notes base: mission, zone, the canons of the genre, boundaries, the shape of the result, escalation. The frontmatter carries `platforms` (which engines the role may run on), `executor` (the default model alias) and `contour` (whether the role works inside an open or a closed access boundary). You edit the card in words, like a document, not like a config.

**The launcher puts the card into the prompt for any engine.** As a "Role" section — the same for Claude, Codex, Grok and Gemini. An engine outside `platforms` is a refusal in code, not a warning: a role that isn't allowed on Gemini won't start on Gemini even if a brief asks for it by mistake. A model alias belonging to another engine (`--model sol`) switches the engine by itself. The same role card doesn't mean the same rights: `platforms` decides whether a role may be launched on an engine, while each engine's access to the notes base and to data is set separately — Gemini, for instance, gets only tasks without secrets or people's data: the launcher rejects closed roles, briefs and folders before it even starts.

**Engine-specific files are derived.** The agent definition for Claude is generated from the card by a sync script; nobody edits those files by hand, and a hook blocks the edit. The engine's native mechanics (the agent type, subagents) keep working, and the truth stays in one place.

**Any engine writes the role's memory.** `Memory.md` next to the card, its history in the notes base's git. The agent's home folder keeps only `state.json` with the session ids: an address, not knowledge.

**Closed roles.** A role that runs a personal, closed workspace is built the same way but lives in a closed folder: in the shared roster it shows up only as a count, and its memory doesn't get into shared reports or reach roles behind another access boundary.

**Tiers, not brands.** There's one model registry for everyone — `models.json`: the aliases `opus`, `sonnet`, `astra`, `sol`, `grok`, `gemini`, `gemini-flash`, plus `hq` — "HQ does it itself". It also holds what each engine can do in our integration: plan mode for Gemini is switched off for now — its plan file isn't wired into the cards — so the dashboard doesn't offer it to a Gemini executor. The split goes by tier: Opus and Astra for substantive work; Sonnet, Sol and Gemini Flash for mechanics against a checklist. Grok, for us, is the third voice in disputes and does mechanics against an exact brief. Gemini does mechanics only, for now: in a single comparative audit on October 8, 2026 (checking documentation against code), 3 of Gemini 3.1 Pro's 5 findings held up, one was partial and one was false, while all 11 of Grok 4.7's held up. One run — a pointer, not a measurement.

**The Trickster.** A separate role on Grok with a provocateur persona: it flips the board and looks for the move everyone missed. It's called only when the human explicitly asks — with the button on a card or the phrase "ask the trickster"; HQ never brings it up on its own initiative. The executor gets from its opinion only what the human explicitly took — retold in a line or two, without the persona's voice.

**What it bought us.** In the week of October 5 – 11, 2026 runs split across engines like this: Claude 194, Codex 51, Grok 10, Gemini 5. A role with two engines in `platforms` moves between them without a rewrite: one line of the launch changes.

## Cards: the ball, the request, the queue

The decision registry in the first version answered the question "what needs deciding". In practice that wasn't enough: cards hung around because it wasn't clear whose move it was and what exactly to press. A typical case: a landing page sat for six days as "a manual step for the human", when the agent could have built it itself and was only waiting for a yes.

**The ball is a recorded fact.** Every card has a field for who holds the move — the human, HQ, a worker or the team queue — plus a log of the handovers. Commands move the ball, not the model's inference: launching a worker on a card records an attempt, the exit marker hands the ball back to HQ for acceptance by itself, the human's answer hands it to HQ to deal with. A ball held by a worker or the queue for more than a day becomes a line in HQ's alerts.

**The kind of request.** When the ball goes to the human, the reply has to say what is expected of them, as one of five kinds. The dashboard draws the main button from it:

- **accept** a finished result — "✓ Accept" closes the card, edits go in as text;
- **permit** the next piece of work — the button says what happens after the yes;
- **hand** — a manual step for the human, the button is "✓ Done";
- **text** — an answer in words is needed, a field with the question above it;
- **choose** — buttons for the options.

A reply without a kind of request is refused by the script. There's a way around it, but with the reason written to a log, and the number of bypasses goes into the weekly review.

**Tabs follow the ball.** The human's tabs: "Do" (a choice HQ has no right to make itself, or a manual step), "Approve" (HQ is ready to do it itself, the human holds a veto), "Think" (nothing is blocked, but there's a trigger — a date or an event; without a trigger it's an idea, not a card). The team queue lives in a view of its own and doesn't count towards the human's tabs.

**The human reviews before a close.** A result the human asked for isn't closed by HQ on its own: it needs the human's yes — a button, a "yes/ok" reply, or a separate approve card on the same artifact. The reason: an image and a page went off to "done" and the human never saw them.

**Threads.** Related cards gather into a thread — a project with a passport: "where we are now" and "the next move". Accepting a report on a thread's card updates "where we are" in the same turn: a week later the human opens the thread instead of rereading ten conversations. The human can write straight into the thread, and HQ has to deal with the message: a copy into a card, a new card, an edit to the passport, or "nothing to do" with a reason.

**Plan first.** For a task where a mistake is expensive, the worker goes in plan mode first: it reads, writes nothing, and hands back a plan. The plan's questions become buttons on the card, the human answers, and execution continues the same session. While the card has unanswered questions, the launcher won't start the execution. A plan worker runs without the permissions bypass (otherwise plan mode doesn't hold), so its report is a file and an exit marker, not a message.

**The team queue and quiet hours.** Cards where the team holds the ball get worked through on a schedule, not whenever HQ feels like it: early in the morning, before the working day, up to six cards; late in the evening, up to three. Priority topics (money, secrets, security) and deadlines first, then the oldest, one per repo, and only if at least half of the subscription's weekly limit is left and the human isn't waiting on anything. For the active queue we keep a guideline of twenty open cards: going over it raises a warning, and HQ does the sorting out. Once a week, a review of everything that hasn't moved for over two weeks: close it as "won't do", move it to ideas, or batch it up for a single role.

**Results go to the card.** A task's result, a summary, a deadline — as a reply on the card. HQ writes to the messenger only when the human asked for it or the task came from there: the human sees the results in the cards anyway, and a second channel nobody asked for turns into noise.

## Discipline gates in code

The constitution says "codify, don't memorise". In practice that means a rule HQ has broken twice gets a hook. The hook doesn't argue with the model. A blocking one won't let the turn end until the violation is fixed or named out loud with a phrase that goes into a log; others only remind, or raise an alert after the fact. The escape phrase matters: a hard gate with no way out is one the model starts getting round quietly.

What code catches for us:

- **An answer without a card.** The human asked in chat, HQ answered in text, and the turn has neither a registry command nor a link to a card — the turn doesn't end. There's one chat for everything and answers sink in it: a reference answer goes into the answers log, a decision into an approve card. The escape is "no card: <reason>".
- **A fork in chat.** The last message of the turn carries a choice marker — "yes or no", "pick an option", a numbered list with a question — and there's no card in the same turn. The turn doesn't end: open a card or rewrite it as information. It started when HQ asked for a "yes" on a Cloudflare setting right in the chat.
- **The ball not handed over.** HQ read the human's answer on a card but didn't record whose move it is now — the turn doesn't end.
- **"Myself or an agent".** A soft gate: more than three edits to one file outside the "myself" list, or a new artifact for the human, with no worker launched in the turn — one reminder, "delegate or name the reason". Not a block; the count goes into the weekly review.
- **A dead inbox monitor.** HQ wakes up from a monitor on the inbox file, and the monitor writes a heartbeat. Once a heartbeat exists, if it goes stale or the watcher is orphaned, the turn doesn't end until the monitor is re-armed; before the first heartbeat, and when the check itself errors, the gate lets the turn through. There's one allowed monitor loop: home-made loops lost sections that arrived seconds before a re-arm.
- **Printing secrets.** Before a command runs, a hook blocks anything that would put a secret on screen: `docker compose config` without the quiet flag, reading `.env` with a printing command, `env` with no filter, `echo` of a secret variable, the key helper's output going to the screen. The block catches known ways of printing, not every leak. After every command a second hook scans the output for key patterns (14 kinds) and, if it finds one, sends HQ an alert — without the value itself; that's a signal that it happened, not protection. It started when, in a single day, a secret's value ended up in a worker's transcript twice. An honest caveat: these are Claude hooks, and other engines aren't covered by them. For Grok and Gemini the secrets helper additionally refuses to hand out values, but that's a speed bump on specific commands, not isolation of the environment or the keychain; Codex has no such restriction.
- **One HQ.** A lock at startup, a stop on the first line for a second copy, prompts blocked for a background copy; an interactive copy only gets a warning. The details are in the gotchas.
- **The registry — scripts only.** Editing the JSON directly is blocked. The add script refuses a card without context, a "think" card without a trigger, and a decision whose default is just "yes/no"; the close script refuses a close without an artifact.

How to choose: block when the violation is quiet and expensive (a lost answer, a printed secret); remind when it calls for judgement (myself or an agent); detect after the fact when a block is impossible. Each gate has its own kind of reaction, escape and config; most have an off switch in the environment and markers in a config outside the code, which change without a release.

## Models inside the Codex track: Astra and Sol

The same "model priced to the task" principle applies at the second vendor too, and there it gives you two layers that don't rule each other out.

**Layer 1 — HQ picks the model at launch.** A Codex worker starts as `codex exec -m <model> -c model_reasoning_effort=<level>` driven by a brief file. Model aliases live in one registry shared by every engine (ours is `models.json`: `opus`, `sonnet`, `astra`, `sol`, `grok`, `gemini` and more), and both the launcher and the executor selector in the dashboard read it; an alias belonging to another engine switches the engine by itself. HQ doesn't remember model ids and doesn't type them into briefs by hand — it says "mechanics" or "substantive", and the registry turns that into a model.

**Layer 2 — subagents inside one Codex session, each on its own model.** Codex ships a `multi_agent` flag and custom agents: one TOML file per agent in `~/.codex/agents/` (personal) or in `.codex/agents/` in the project (shared with the team, loaded only in a trusted project). The file holds `name`, `description`, `developer_instructions`, plus the ordinary config keys: `model`, `model_reasoning_effort`, `sandbox_mode`, `mcp_servers`. Everything below, both examples included, is the configuration of build v0.153.3 that we checked on September 9, 2026, not the current CLI contract: on that build a key you left out was inherited from the parent, the limits were `[agents] max_threads` (6 by default) and `max_depth` (1 by default: a child doesn't spawn grandchildren), the built-in roles were `default`, `worker`, `explorer`, and your own role with the same name overrode the built-in one. Key names and defaults have been changing since — check the reference for your Codex version before you build.

```toml
# .codex/agents/scout.toml — cheap scouting, read-only
name = "scout"
description = "Read-only scout across the codebase, on a cheap model."
model = "gpt-6.1-sol"
model_reasoning_effort = "low"
sandbox_mode = "read-only"
developer_instructions = """
Search precisely, don't scan whole directories. Hand back facts and paths; the parent does the synthesis.
"""
```

```toml
# .codex/config.toml — the registry and the limits
[features]
multi_agent = true

[agents]
max_threads = 4
max_depth = 1

[agents.scout]
description = "Read-only scout on a cheap model."
config_file = "agents/scout.toml"
```

Verified live on September 9, 2026 on Codex v0.153.3: a parent on `gpt-6-astra` (effort high) brought up two subagents from files like these, and in the session logs each of them had its own model and its own effort — `scout` on `gpt-5.6-sol` / low, `builder` on `gpt-6-astra` / medium. The forum complaint from July 2026, that subagents have inherited the parent's model since 5.6, doesn't reproduce on this build. And you check that in the logs (`~/.codex/sessions/…/rollout-*.jsonl`, the `model` field in `turn_context`), not by asking the subagent about itself. Since October 1, 2026 our `sol` alias points at `gpt-6.1-sol`; we haven't repeated the probe on the new model.

**What we know about price and quality.** An overnight benchmark on our own tasks, September 6, 2026: where the source sits right in front of the model (checking facts, counting over data), Opus, Astra and Sol all hit the same ceiling in every repeat, while a substantive task that calls for judgement (a month of transcripts: promises, the threads running through them, a decision) pulled them apart — Opus 0.865, Astra 0.761, Sol 0.698, at $0.77 / $1.01 / $0.39 per run. The conclusion is the same as for the Opus/Sonnet pair: hand mechanics to the cheap model and lose nothing, keep judgement on the strong one.

**Where the saving is and where it isn't.** Subagents burn more tokens between them than a single session does: each has its own context and makes its own tool calls. The win doesn't come from running things in parallel, it comes from a cheap model on a cheap role: an explorer on Sol read-only, a worker on a middling model, the judge or the parent on a strong one. The classic mistake is to put a strong model on the parent and say nothing about the children: they silently inherit it, and the "economical" setup ends up costing more than one session would have.

**How to choose a layer.** Layer 1 is for a task that stands on its own and can be written down as a brief: HQ sees the model in the launch command, in the team journal and on the card; that's our default. Layer 2 is for when a single Codex session breaks the work into scouting and building by itself and needs the parallelism inside the task; then the children's models are pinned in the project's TOML files and travel into the repo along with the code.

## Key principles

1. **A brief is only the body.** The task, the boundaries, the delta, the trace. The protocol — role, memory, repo map, constitution, `git log / status`, the report path, HQ's name, the memory update, codifying recurring mistakes — is written into the prompt next to the brief by the launcher. The reason: the boilerplate had grown from 17 to 41 % of a brief, and HQ was writing it from scratch every time. The code always prints the protocol lines — the body of the brief can't switch them off.
2. **Model explicit, effort explicit.** HQ at max, Opus workers at high, Sonnet mechanics at medium. A worker's effort is set explicitly (Opus through the model's setting, Sonnet through an environment variable of its process), and HQ's variable must not leak into the workers through the tmux server — the launcher strips it. A silent fallback to another model is forbidden: if it wouldn't launch, say so.
3. **Anything over thirty seconds goes into tmux.** Not foreground (it blocks your turn), not a background shell (it dies with the session). The watcher is an `until` loop with a timeout on the log file, one per job; a single watcher covering many jobs goes blind.
4. **Artifacts live in permanent places.** Reports go into the repo's `scratchpad/`, not `/tmp`: a reboot wipes temp folders along with the history of the work.
5. **One repo, one writer.** Before a build or a deploy: the inbox and `git status` — somebody else's uncommitted files ride along. And if the human is sitting in that repo in an interactive session, don't start a worker there; give the task to that session.
6. **Secrets live in the keychain and the environment, nowhere else.** No `.env` in the code, no keys in reports, logs or commits. Scripts pull keys through a helper; the guards lower the risk of printing them but don't replace access restrictions (see "Gates").
7. **Codify, don't memorise.** A rule that has fired twice goes into a hook, a gate, a script or a process manifest. Anything volatile — model, price, path, limit — goes into config, not into the body of the code or the prompt.
8. **Reversible by default.** Back up before changing, roll back in one move. Irreversible things happen only through the human's list.
9. **A broken assumption is not a reason to go quiet.** The approved approach hit a new fact: if the replacement is reversible and the goal is the same, do it and report; if the goal, the money, the people, the publicity or the boundaries shift, stop and ask.
10. **Engine sync.** Every piece of substantive work leaves a trace the others read: a report or a commit, the daily note, the team journal, a current-context file for Codex. Every Codex brief carries a line about that trace.
11. **A second opinion priced to the decision.** Opus does, Astra reads; three voices for an irreversible decision or a change to how the human works with the system; Grok when the first two disagree.
12. **Results go to the card.** The messenger only when the human asks.

## Workflow

**Morning.** Before the human is even up, a script drops the morning team queue into the inbox, and HQ brings up workers for it if the limit allows. Restart HQ: the wrapper feeds the startup message, the hook shows the handoff, cards that are due, the inbox, the roles, orphans in tmux, and cards where the ball got stuck. One or two clean-up moves (re-arm the inbox monitor, kill the orphans), then the actual work.

**A task arrives.** HQ decides whether to do it itself or hand it off — by the matrix. Then whose thread it is: whoever runs it (reports, commits, role memory, the Codex context) gets the next task, unless the human said otherwise. A card for the task, a brief body with context, boundaries and acceptance criteria, a launch tied to the card, a watcher. An expensive mistake means plan first. A fork means a card with a default, right then.

**A report arrives.** HQ checks the facts that clash with its own context (the date in a filename is not the date of the event; "done" without a path is not done). A result meant for the human's hands means the ball goes to the human with a kind of request; anything else is closed only against an artifact. The thread's passport, in the same turn. It writes up the daily note and the context for Codex. It kills the tmux job once the result is collected.

**The human answered some cards.** Answer → action (close it into the log, or launch a worker), a reply in the card's thread, the ball to whoever holds the move now, and the inbox section marked as handled. An answer doesn't close a card — HQ closes it with an artifact, or the human with a yes.

**Evening.** A handoff note: what's hot, what's waiting on the human, what to do first tomorrow. The evening team queue. Compaction by feel — the drift starts well before the ceiling.

**Weekly.** A review of everything that hasn't moved for over two weeks, of role memory, of gate bypasses, and of the "myself or an agent" count: where HQ did an agent's work by hand. Rules that are ready to be codified.

## What the system is made of

- **The HQ card** — HQ's rules for any platform: the mission, what isn't delegated, the channel for choices, executors, continuity, councils, reporting. It lives in the notes base next to the role cards.
- **A global `CLAUDE.md` and skills** — the mechanics: commands, flags, paths, thresholds. HQ's rules aren't repeated there, only linked: keeping two copies has already let drift in. Skills load on demand — before a brief, before a card.
- **Repo maps** — a `CLAUDE.md` at the root of every active repo. A worker starts with its cwd in the repo and picks the map up by itself; no map means the first worker writes one before doing the task; change the topology and you update the map with it.
- **Roles** — a card and `Memory.md` in the notes base, `state.json` with the agent; a sync script generates the engine-specific files from the cards.
- **A model registry** — `models.json`: alias, id, engine, what the engine can do. The registry is shared by worker launches and the executor selector in the dashboard; HQ's own model is still pinned separately, in its wrapper.
- **A launcher** — one script: `--role`, `--brief`, `--model`, `--effort`, `--card`, `--mode plan|exec`, `--fresh`, `--dry-run`. It reads the role card and checks `platforms`, picks the engine from the alias, decides resume or fresh, writes the protocol boilerplate next to the brief, the log with the exit marker, an event in the team journal and an attempt on the card, and retries on overload. You assemble a command by hand only for the cases it doesn't cover.
- **Briefs and reports** — `scratchpad/brief-<slug>.md` (the body), `brief-<slug>.prompt.md` (the boilerplate the launcher writes) and `scratchpad/report-<slug>.md` in the repo the task belongs to; `scratchpad/` sits in `.gitignore` and in the deploy exclusions.
- **A decision registry** — `pending-decisions.json` with the ball, the kind of request, threads, deadlines and priority; `decision-add` / `decision-reply` / `decision-close` / `decision-link` scripts with gates; a dashboard with buttons.
- **Inbox files** — HQ's inbox: markdown with sections `## <source> <date time> — <subject>`; the writers are the messenger bridge, production bot alerts, Codex, answers on cards, the morning queue. HQ keeps one Monitor on it and marks the sections it has handled. The feed for Codex is append-only, with no cursor.
- **A team journal** — the launcher writes "started / done" events with the role, the engine, the model and the task into jsonl; both the viewer in the dashboard and the team's weekly summary are built from it.
- **Hook gates** — the "Discipline gates in code" section: blocking ones, reminders and after-the-fact detectors; each has its own config, off switch and escape.
- **A constitution** — eight short articles, each with its own "evidence": the human has the last word (and one list of human-only actions); a claim rests on a source; reversible by default; a broken assumption is not a reason to go quiet; there's an artifact, so there was work; codify rather than memorise; access boundaries stay isolated (closed audiences don't get mixed); executor continuity (a thread stays with whoever is running it). It changes only on the human's word, with a version and a history.
- **Bridges** — messenger → inbox (for things that arrive on your phone), and "send this as me" only through a confirmation card with a one-time token.
- **The memory watcher** on a cheap cloud model (ours is Haiku 4.5) or on a local one: an OpenAI-compatible endpoint on a local server, with thinking switched off at the proxy, because background summarising doesn't need it and it cuts the time by a factor of six. The local route only pays off with a model that fits in memory alongside everything else you are running.

### Starter kit

This is a specification for building your own system, not an installable package: `run-teammate`, `decision-*` and the dashboard are the names of our own scripts, and your agent will have to write their equivalents for you.

A brief is only the body:

```markdown
---
decision: <link to the card>
---
# Brief for <role>: <what to do>
Card: <link>. What the human decided: "<quote>".
## What to do
1. … (how it will be checked, how to roll back)
## Boundaries
- what NOT to touch; what needs the human's word
## Trace
Report: `<repo>/scratchpad/report-<slug>.md`. Attach to the card: …
```

The boilerplate the launcher writes next to it (`brief-<slug>.prompt.md`), which is what the worker reads:

```markdown
## Boilerplate
- Role: **<role>** — the card is below. First thing: read your memory at `Teammates/<Role>/Memory.md`.
- Read the repo map at `<repo>/CLAUDE.md`; if you change the topology, update it in the same move.
- Read the constitution at `<path>` and work by it.
- At the start: `git log --oneline -8` and `git status`.
- Do it yourself: don't bring up subagents. Anything the brief doesn't name is out of bounds.
- Wait for your own subprocess in this same turn: once you exit, nobody will wake you.
- Report: `<repo>/scratchpad/report-<slug>.md`, attached to the card.
- At the end, update the role memory precisely; a mistake that recurred ≥ 2 times goes into code, a gate or the map, not into memory.
- Final report: the launcher fills in the channel per engine — Claude: SendMessage to HQ's name **<name from HQ's state file>**; other engines: a section in HQ's inbox through their own adapter.
## Role
<the body of the role card>
## Brief
<the body of the brief>
```

Launching through the launcher:

```fish
run-teammate --role web --brief <repo>/scratchpad/brief-<slug>.md --card <id> --model opus
```

Launching by hand (fish inside tmux; for Sonnet mechanics, `CLAUDE_CODE_EFFORT_LEVEL=medium` in the process environment — for us the CLI's `--effort` flag didn't override it, we checked in the transcripts):

```fish
tmux new-session -d -s job-x 'claude -p --dangerously-skip-permissions --model claude-opus-5-5 \
  --settings \'{"crossSessionInbound":"accept"}\' "Read <path>.prompt.md and carry it out in full." \
  2>&1 | tee /tmp/tmux-job-x.log; echo "EXIT=$pipestatus[1]" | tee -a /tmp/tmux-job-x.log; exec fish'
```

A watcher (in HQ's background, a window of ten minutes or less, then re-hang it):

```bash
t=0; until grep -Eq '^EXIT=-?[0-9]+[[:space:]]*$' /tmp/tmux-job-x.log || [ $t -ge 560 ]; do sleep 20; t=$((t+20)); done
```

A decision card:

```json
{"id":"site-og-v2","type":"approve","owner":"max",
 "question":"The v2 OG cards are ready in preview: new typeface, EN headlines.\n\nyes → I ship them to the site; no → v1 stays",
 "default":"yes","cost":"30 min of the web worker, reversible","artifact":"~/Vibe/site/scratchpad/report-og-v2.md",
 "ball":{"holder":"max","ask":{"kind":"permit","yes":"I ship OG v2 and check the previews"}},
 "executor":{"role":"web","model":"sonnet"}}
```

## Questions to adapt it to you

1. How many projects do you run in parallel, and where do their files meet — home folder, notes, a monorepo? That's where HQ lives.
2. Which subscriptions and CLIs do you have: Claude (Max/Pro), Codex, Grok, Gemini, API keys? That decides the model tiers and which roles can live on which engine.
3. What is human-only for you? Write down five to seven actions you only ever do yourself. Agents do everything else by default.
4. Are you alone or working with people? With people, the decision registry and the inbox become shared, and roles get owners.
5. Do you have local hardware for local models? Then some of the background work drops to zero — but do the arithmetic honestly: a 27B model with a long context takes 30 GB, and on 64 GB it gets in the way of everything else. Without the hardware, the background runs on Haiku for pennies.
6. Where do your notes and decisions live now? HQ needs a base the human reads and agents reach under the rights of their role and engine — an Obsidian vault fits perfectly: the role cards and their memory will live there too.
7. What's your rhythm — you work during the day and want things to happen overnight? Then launchd/cron jobs, with the same briefs and the same reports, and a team queue in the quiet hours.
8. Which rules has your agent already broken twice? Those are your first candidates for gates.

## Gotchas

- **A headless session ends the moment it stops calling tools.** A worker that finished its turn with "waiting for the render to complete" has simply exited. Waiting can only be done with a shell loop and a timeout — that rule sits in the boilerplate of every brief.
- **A headless worker's log is empty until the very end.** Zero bytes after two minutes isn't death; death is the absence of a process. The watcher looks at the log *and* at tmux.
- **A report sent to a placeholder session name is a report sent nowhere.** That's why HQ's name is filled in by the launcher from the state file, not by whoever writes the brief.
- **`pkill -f <script>` kills the tmux server** if the string matches its arguments. Before any pkill, look at `pgrep` with your own eyes.
- **A shared repo and parallel workers** — somebody else's files end up in your commit and in your deploy. Inbox and `git status` first, build second; one writer per tree.
- **`--fresh` overwrites the role's state.** For two instances of one role, start the second one without a role or restore the id by hand.
- **Ctrl+Z is not an exit.** An HQ stopped with Ctrl+Z stays a live process and holds the "one HQ" lock. The new launch honestly takes itself for a duplicate and won't work. The cure is to end the frozen copy along with its orphaned watcher: once the old process is dead and the same session resumes, the lock comes back cleanly.
- **The CLI itself was spawning HQ duplicates.** Exiting with a live monitor offered to "move the work to the background and exit": the conversation forked into a background copy, and the monitor moved with it. For nine days, almost every morning, a copy of HQ with the same context was running next to the live one. The fix has three layers: the wrapper switches background mode off for the HQ process, the startup hook takes a lock, prints a stop to the second copy and won't let it overwrite the main session's state, and the prompt hook blocks the background copy. A second interactive copy isn't forbidden by these layers, only warned — technically it can still work. Nothing gets killed automatically: show it, don't shoot it.
- **Workers print secrets without meaning to.** `docker compose config` expands the variables, a debugging `echo` shows the token, and the value travels into the transcript, the logs and memory. A guard before the command and a detector after it — see "Gates".
- **launchd, TCC and macOS notifications.** Background launchd jobs run into two systems. The first shows "can run in the background" by the name of the file being launched and repeats it on every rescan of the agents folder — and any change in that folder triggers a rescan. The second, folder access, treats the job's own process as responsible, not whatever it launches. The fix: all 36 of our jobs start through symlinks to one small launcher binary — it forwards signals and passes on the child's exit code, and one grant of folder access covers them all. Rebuilding the launcher is off limits: a new signature means a new grant and a new batch of notifications.
- **It's easy to start duplicating results into the messenger.** The bot is right there and sending summaries to it is convenient, but a second channel nobody asked for turns into noise: the human sees the results in the cards anyway. On October 12, 2026 the rule went into HQ's card: results go to the card, the bot only when the human asks or in reply to a task that came from there.
- **A model id in code is a hidden decision.** Between late September and early October the models in the registry changed four times: HQ moved from Fable to Opus 5.5, Opus 5 was retired, Sonnet 5 was replaced by 5.5, Sol moved to a new version. Where the id lived in the registry, the change was one line; where it was hard-coded into a script or a text, it was an edit across files that's easy to leave half-done. This Blueprint was one of those places: its v1 was named after HQ's model.
- **Plugin auto-updates wipe local patches.** Anything you patched inside a plugin's cache goes into memory with a path to the original and a check to run after every update.
- **Price depends on input length.** For some models the rate goes up once the input passes a threshold, and the thresholds differ between vendors and models; subscriptions have terms of their own. Check the rate for the specific model on the day you build. The conclusion stays the same: keep briefs short, resume only when you actually need it, don't drag a fat history around.
- **A second agent agreeing with the first one is not yet a fact.** Agreement is a claim too: you accept it after the same check — what it rests on, and what would make it false.
- **A card with no default, or an "approve" card with no cost** — that's work pushed back onto the human, and cards like that stop getting read fast.
- **Yours and theirs.** What's inside closed spaces, chats and client folders doesn't travel across access boundaries — not as a retelling, not as a hint; only your own goes out. One worker serving every project is the most common way to break this.

## Scaling up

- **One worker → a fleet.** As soon as you're past two jobs a day: a launcher, one watcher per job, `job-*` killed once the result is collected, `dev-*` left alone.
- **Roles.** When the same genre keeps coming back — the site, a product, content, production incidents — create a role as a card with memory, and the same mistakes stop repeating.
- **A dashboard.** Decision registry, threads, the team queue, inbox, journal, service health — one local page; your phone talks to it through the messenger bridge.
- **Other engines.** Workers driven by briefs through the same launcher first, then roles with several engines in `platforms`. We built a long-lived main Codex session with an inbox cursor and a queue "nudge" on September 1 and folded it on the 16th: in two weeks the human never once wrote into its canonical thread, opened 22 direct threads instead, and the cursor was six days behind. What lives on is the human's direct threads and an append-only feed from HQ; delivered means a trace came back.
- **Local models.** Background calls — memory, classification, summarising — can move to a local server once the model fits in memory next to your actual work; until then a cheap cloud model carries them, and the bigger cloud is left for judgement.
- **The night shift.** Launchd/cron jobs with the same briefs: digests, watchers, backups, note syncs, the morning and evening team queue; their results get linked into the daily note by the same job.

## What you end up with

What the coding agent builds with you from this Blueprint:

- An HQ card with the rules and a global `CLAUDE.md` with the mechanics.
- A map of your first repo.
- A roles folder in your notes base: two or three cards, each with an empty `Memory.md`.
- `models.json` with the model aliases.
- A launcher that writes the protocol boilerplate, and a template for the brief body.
- `pending-decisions.json` and the card scripts, with the ball and the kind of request.
- An inbox file, one HQ Monitor on it, and the first Stop gate — "a fork in chat".
- A constitution v0.1 of five articles, the first being the human-only list — changed only on your word.
- A first handoff note, so tomorrow's HQ doesn't start from nothing.
