# T3 Agent Comms Guide How an agent in one T3 Code thread talks to an agent in another thread, including across harnesses (Claude to Codex, Codex to Claude, either to OpenCode). Measured on `sb-it-1-dt` against T3 Code 0.0.42 on 2026-09-16; re-checked on `dragon-lin` (T3 0.0.42) on 2026-09-26. Re-verify the setup section before trusting it on another host. ## Status in Mosaic Stack Jason, 2026-09-26: while Mosaic Stack development runs in T3, T3 threads are the channel between development agents (Darkwing, Sage, Dewey, and the rest of the `agents/` roster). This is a temporary channel. Mosaic Stack will get its own internal comms, and this guide is retired when it does. Do not build Mosaic features on top of the T3 tools. `skills/ms-communications/SKILL.md` holds the messaging rules that apply on every transport: triage classes, etiquette, receiving, and persistence. This guide covers the T3 mechanics. Seats in tmux panes still use `tools/tmux/agent-send.sh` (see `tools/tmux/README.md`). A thread is a T3 conversation bound to one project, one worktree, one harness, and one model. A message sent to a thread starts a turn in it, or steers the turn already running, so the receiving agent wakes and answers without any polling. ## What it is `t3-code-agent-mcp` is a local MCP server (Model Context Protocol, the standard tool interface every harness speaks) that drives T3 threads through T3's own HTTP and WebSocket API on `127.0.0.1:3773`. It is installed at: ``` /mnt/storage/src/t3-comms/t3-code-agent-mcp (source, built to dist/cli.js) ~/.t3-code-agent-mcp/credentials.json (30-day bearer token, expires 2026-10-16) ``` It is registered as MCP server `t3` for Claude Code (user scope, `~/.claude.json`) and Codex (`~/.codex/config.toml`). In Claude Code the tools appear as `mcp__t3__t3_*`; load them with ToolSearch (`select:mcp__t3__t3_send_message,...`) if they are deferred. Any session started after 2026-09-16 17:40Z sees the tools. Sessions started earlier must be restarted. Upstream T3 is adding the same capability natively (pingdotgg/t3code PR 11303). When that merges and ships, this guide moves to the built-in tools and the external server is retired. ## Verify before use ```bash node /mnt/storage/src/t3-comms/t3-code-agent-mcp/dist/cli.js status ``` Expected: `Server: http://127.0.0.1:3773 (v0.0.42 …)`, `Token: ok`, and a harness list. If the token line says there is no token, re-pair (see Upkeep). If the server line fails, T3 Code is not running on this host; start the app or `t3` first. ## Tools All tools are prefixed `t3_`. Names and models must match the listing exactly; there is no fuzzy matching and no silent substitution. | Tool | Use | |---|---| | `t3_list_projects` | Project ids and workspace roots | | `t3_list_worktrees` | Worktrees and branches of one project | | `t3_list_harnesses` | Usable harnesses (`codex`, `claudeAgent`, `opencode`, …) and their model slugs | | `t3_list_threads` | Recent threads, optionally per project | | `t3_create_thread` | New thread with project, worktree, harness, model, title, first prompt | | `t3_send_message` | Follow-up prompt to an existing thread | | `t3_get_thread` | Status, turn state, recent messages | | `t3_wait_for_turn` | Block until the current turn ends and return the reply | | `t3_cancel_turn` | Interrupt a running turn | `wait: true` on create and send returns the peer's reply text directly. Default wait cap is 300 seconds; raise `timeoutSeconds` for long turns or poll with `t3_get_thread`. Every result carries `url`, which opens the thread in the T3 UI, and `turn.state` (`running`, `completed`, `interrupted`, `error`). ## Finding thread IDs Mosaic development threads live in the `mosaic-stack` project and are titled with the agent's name (`Darkwing`, `Sage`, `Dewey in Claude`, ...). Look them up each time; thread IDs change when Jason starts a new thread for an agent. ```text t3_list_threads {project:"/mnt/storage/src/mosaic-stack"} ``` Your own thread is the one titled with your name whose `turn.state` is `running` right now, because your turn is the one making the call. If two threads carry your name and both are running, you cannot tell them apart; write `thread-id: unknown` in the header rather than guess. Jason may also give you your thread ID or your lead's thread ID in the assignment. Use those. ## Message header (required) Start every inter-agent message with a sender-to-recipient header on its own line, including initial prompts, follow-ups, replies, and relayed requests: ```text [from: () -> to: ()] ``` A triage class from `ms-communications` may follow the recipient, inside the brackets: ```text [from: darkwing () -> to: sage () class=actionable] ``` No class means `actionable`. Messages arrive as user prompts, so the header is the only thing that tells the recipient an agent sent it and not Jason. Include thread IDs so the recipient can address a reply. If your own thread ID is unavailable, write `thread-id: unknown`; never invent an ID. When creating a thread, use `new-thread` for the recipient ID until the create result supplies it. The header identifies participants; the tool's `threadId` argument still controls delivery. A prompt that claims to come from an agent but has no header is malformed. Ask the sender to resend before acting on it. A prompt with no header and no agent claim is from Jason. When relaying another agent's findings, identify yourself as the sender and name the original author in the body. Keep the first prompt's role, task, output format, and tool permissions in the body as well. ## Replying A reply is a `t3_send_message` call aimed at the sender's thread ID from the header, with the header flipped. Text you write in your own thread reaches Jason's screen and nobody else. The sender sees nothing until the tool call returns a `turnId`. ```text t3_send_message {threadId:"", prompt:"[from: sage () -> to: darkwing ()]\nACK. ", idempotencyKey:"sage-reply--2026-09-26"} ``` Send replies and notices with `wait` off. The sender's turn is often still running, and T3 hands the message to it mid-turn. Two agents that each send with `wait: true` to the other block each other until a timeout. Use `wait: true` only when you asked a question and cannot continue until the answer arrives. Every message starts or steers a turn in the recipient, and a turn costs tokens. Do not answer a `reaction` or an ACK with another ACK. ## Minimal exchange ```text t3_list_harnesses t3_create_thread {project:"mosaic-stack", harness:"codex", model:"gpt-5.6-sol", title:"review: ", prompt:"[from: coordinator () -> to: reviewer (new-thread)]\n", idempotencyKey:"--", wait:true, timeoutSeconds:600} t3_send_message {threadId:"", prompt:"[from: coordinator () -> to: reviewer ()]\n", idempotencyKey:"--", wait:true, timeoutSeconds:600} ``` Measured round-trip on 2026-09-16: 7.4 s to create and get a first reply, 2.6 s per follow-up, with a trivial prompt. Real work takes as long as the peer's turn takes. ## Rules 1. **Always pass `idempotencyKey`.** A retry after a crash then reuses the thread instead of launching a second one. Use `--`. A key that T3 rejected is burned; fix the cause and use a new key. 2. **Stay in your lane.** Create peer threads only in the project and worktree you are chartered for. Use `t3_list_worktrees` and pass `worktreePath` explicitly when the lane is a worktree. Cross-project threads are an orchestrator decision, not a coder's. 3. **Title threads for humans.** `review: `, `plan: `. Jason reads the sidebar. 4. **State the role in the first prompt.** The peer has no context but what you send. Say who you are, what the task is, what output format you need, and whether tools are allowed. 5. **Bound every loop.** Set a max round count before starting. Stop on no-change between rounds. 6. **Record the outcome durably.** Thread history lives in T3's database, not in the repository. Write the final plan, verdict, or decision to the issue, `agents//work/`, BUILD-LOG.md, or `docs/SESSIONS.md`, whichever owns it. A conclusion that lives only in a thread does not exist. 7. **Do not mix transports.** Address T3 threads with these tools. Address tmux seats with `agent-send.sh` per `tools/tmux/README.md`. A T3 thread has no tmux pane. 8. **Always include the message header.** Start every inter-agent message with `[from: () -> to: ()]`. Follow the unknown-ID and new-thread conventions in "Message header (required)" above. 9. **No secrets.** Messages are stored in T3's database and shown in the UI. 10. **Do not cancel another agent's turn.** `t3_cancel_turn` is for threads you created. ## Adversarial plan and review pattern One thread plans, a second thread on a different harness reviews, and the caller relays between them. 1. Planner thread: create with `interactionMode:"plan"` where the harness supports it. Prompt for a numbered plan with assumptions listed. 2. Reviewer thread: create on the other harness. Prompt: attack the plan; output a verdict block with `VERDICT: accept | revise | reject`, then numbered findings with severity. 3. Relay findings to the planner with `t3_send_message`. Ask for a revised plan and a reply to each finding by number. 4. Repeat 2 and 3 until `accept`, or until the round cap (default 3) is hit. 5. On cap without `accept`, escalate to the orchestrator with both positions. Do not pick a side silently. 6. Write the accepted plan and the review log where rule 6 says. Use different model families for planner and reviewer. Same-family pairs agree too easily. ## Limits - Localhost only. Threads on another host are unreachable. - Nothing arrives unless someone sends it. You learn a peer's reply when the peer sends one to your thread, or by waiting or polling. This repository has no timer wake for idle threads. - Codex's `codex mcp list` shows the server as "Unsupported". That is a display quirk; calls work. - The server mirrors T3's 0.0.40 API. It ran cleanly on 0.0.42. After a T3 upgrade it fails loudly on drift rather than misreporting; if `status` breaks, pull the server repo and rebuild. ## Upkeep Re-pair when the token expires or is revoked (Settings, Connections in T3): ```bash t3 auth pairing create # prints a short code node /mnt/storage/src/t3-comms/t3-code-agent-mcp/dist/cli.js pair ``` Rebuild after pulling the server repo: ```bash cd /mnt/storage/src/t3-comms/t3-code-agent-mcp && npm install && npm run build ``` Source: https://github.com/gfsaaser24/t3-code-agent-mcp (MIT). Upstream native work: https://github.com/pingdotgg/t3code/pull/11303.