Files
stack/docs/guides/T3-AGENT-COMMS.md
T
jason.woltjeandClaude Opus 5.5 21e3e908b6 docs(comms): T3 threads as the temporary development channel beside tmux
Jason, 2026-09-26: while Mosaic Stack development runs in T3, development
agents message each other through T3 threads with the t3 MCP tools, until
Mosaic Stack has its own internal comms. ms-communications now picks the
transport by where the recipient runs, carries the T3 header and reply
rules, and counts a returned turnId as the delivery receipt.
docs/guides/T3-AGENT-COMMS.md is adapted to this repository: status,
thread lookup by agent-name title, replies with wait off, and record
locations; references to guides absent here are replaced.

Suites green before commit: config 24, task 90, foundation 43,
conductor 17, release 14, auth 15, discord 63. unslop-check clean on
both files. Reviewed by Sage (T3 thread 1ef1e4f8).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 14:33:24 -05:00

11 KiB

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

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.

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:

[from: <sender-role> (<sender-thread-id>) -> to: <recipient-role> (<recipient-thread-id>)]
<message body>

A triage class from ms-communications may follow the recipient, inside the brackets:

[from: darkwing (<id>) -> to: sage (<id>) 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.

t3_send_message {threadId:"<sender-thread-id>",
                 prompt:"[from: sage (<my-id>) -> to: darkwing (<sender-thread-id>)]\nACK. <answer>",
                 idempotencyKey:"sage-reply-<topic>-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

t3_list_harnesses
t3_create_thread {project:"mosaic-stack", harness:"codex", model:"gpt-5.6-sol",
                  title:"review: <topic>",
                  prompt:"[from: coordinator (<source-id>) -> to: reviewer (new-thread)]\n<task>",
                  idempotencyKey:"<lane>-<task>-<date>", wait:true, timeoutSeconds:600}
t3_send_message  {threadId:"<id>",
                  prompt:"[from: coordinator (<source-id>) -> to: reviewer (<id>)]\n<next round>",
                  idempotencyKey:"<lane>-<next-round>-<date>", 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 <lane>-<purpose>-<date>. 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: <topic>, plan: <topic>. 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/<name>/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: <sender-role> (<sender-thread-id>) -> to: <recipient-role> (<recipient-thread-id>)]. 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):

t3 auth pairing create                      # prints a short code
node /mnt/storage/src/t3-comms/t3-code-agent-mcp/dist/cli.js pair <code>

Rebuild after pulling the server repo:

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.