| name | anu-talk |
| description | Message another agent's tmux pane and get its reply — reliably, with one command. Use to talk to / prompt / relay to / coordinate with another agent or pane ("tell the codex pane to…", "ask the claude in %82…", relaying between agents), to get an answer back from a sibling agent, or when a pane received text but did not act on it (staged "[Pasted Content]" / unsubmitted). The tool is `pane` (send / ask / read / wait / ls / id); this covers it, how to pass messages containing awkward characters safely, finding panes, and the swarm send / swarm read wrappers. |
anu-talk: message a pane, get the reply
One command. Don't hand-roll tmux send-keys, and don't sleep N and poll to wait.
Send, or send-and-get-the-reply
pane send <target> "<message>"
pane ask <target> "<message>"
pane send resolves the target, sends the text, submits with a separate Enter, and verifies it landed (retrying if a TUI staged it as a paste).
pane ask does all that, then waits for the pane's reply to appear and settle, and prints it — so you never hand-roll sleep; pane read.
<target> = %NN (a pane id — most reliable) · agent-N (swarm) · next (the
other pane in your window) · codex/claude/opencode/pi (the one pane running
it). Find them with pane ls.
Is it working, or done? — pane status (don't scrape the screen)
To know whether a sibling is still generating or has finished, don't pane read
and eyeball it — that guesses wrong mid-turn (an agent streaming its answer briefly
looks "done"). Use the crisp, non-blocking check:
pane status <target>
pane status <target> --json
pane status
pane status reads the CLI's own title spinner, so it stays correct through
answer streaming — where the bottom "esc to interrupt" hint disappears — and across
codex / claude / cursor / opencode / pi. To block until a pane is done (and get its
reply), use pane wait <target> (or pane ask <target> "…") — both built on the same
detection. Never until pane read | grep …; sleep — that is exactly what guesses wrong.
Talk to another model — pane consult (one command)
Want a second opinion, a sanity check, or an independent review from another model —
classically a Claude pane consulting codex? Don't hand-orchestrate spawn → send →
poll → read. One command does all of it and returns just the answer:
pane consult codex "<question>"
pane consult codex -f plan.md
pane consult --fresh codex "<q>"
It reuses a consultant you created (a private lease — it never grabs the human's own
codex pane), keeps it alive for cheap follow-ups with shared context, and waits through
the whole turn (built on the done-detection above). Works the other way too —
pane consult claude "…" from a codex pane. Default consultant is host full-auto
(cdxx/cxx); set PANE_CONSULT_CODEX / PANE_CONSULT_CLAUDE to a sandboxed alias if
you prefer least-privilege.
Reach for it proactively. When a hard judgment call would benefit from an independent
read — a design tradeoff, a plan you're unsure of, a review before you finalize, a gnarly
bug — consult another model and weigh its answer as critique, not authority. Skip it for
trivial or mechanical work where latency matters more than a second opinion.
Message or collect a team (1 → many)
Once a team is labelled (pane fan 4 cxc --as worker …, or pane name %82 reviewer),
drive the group — always with an explicit scope (--role/--cli), never the
whole session:
pane broadcast --role worker "<message>"
pane gather --role worker
pane status
pane gather is best-effort screen capture, not confirmed results. A shared
label names the whole team; address one member by %id (or pane ask reviewer "…"
when a label is unique).
Messages with awkward characters — don't fight quoting
Apostrophes, quotes, $, backticks, newlines? Don't inline-quote them — that's
the #1 way a send blows up (unexpected EOF, $VAR expanding, a stray backtick
running a command). Pass the text without it going through shell quoting at all:
pane send %93 -f /tmp/msg.txt
pane ask %93 -f /tmp/msg.txt
pane send %93 - <<'EOF'
It's reality's "promiscuous" $compression `etc` — sent verbatim.
EOF
pane flattens newlines, sends literally (-l), and strips control bytes, so the
text arrives exactly as written.
Find a pane / read a screen
pane ls
pane id codex
pane read <target> [n]
pane status <target>
pane wait <target> [s]
In a swarm, swarm status lists agent-N → PANE; swarm send/swarm read use the
durable mailbox. The human can yank a pane id to your clipboard with prefix y/Y.
Steer a pane — state, approve, stop, wait-for
pane status <target> [--json]
pane state <target> [--json]
pane respond <target> yes|no|N
pane stop <target>
pane wait <target> --for <re>
For "is it working or done?" reach for pane status (one word, non-blocking). When a
pane is at an approval / permission prompt (codex "Press enter to confirm…", claude's
numbered menu), don't tmux send-keys a guessed key: pane status/pane state detect
it (with the choices) and pane respond sends the right one. To wait for a specific
signal (a build line, a prompt) use pane wait --for, never until pane read | grep.
What can go wrong — and how pane handles it
| Failure mode | handled by |
|---|
Text staged, never sent — TUIs absorb a welded C-m into the paste | separate Enter + retry, verify by composer state |
| Multi-line submits early (newline = submit) | flattens newlines/tabs |
Quotes / $ / backticks break the call | -f file or - stdin input (above) |
Enter/C-c literal in the text sent as a keystroke | -l literal send |
| Control bytes could drive the terminal | stripped |
| Copy-mode / view active | cancelled first |
| Wrong/dead pane, or yourself | validated; self refused |
| Concurrent senders interleave | per-pane lock |
| Not an agent prompt (bash/vim/less) | warns you |
| Returning before the reply | ask waits for change-then-settle |
| "Is it done?" guessed from a screen scrape (false-idle while it streams) | pane status reads the title spinner — correct mid-stream |
Limits — handle these yourself
- A booting agent (auth / model-picker) can eat a send —
pane status reports booting; wait a beat (or pane wait) after spawning.
- Approval dialogs: spawn full-auto agents (
cxx/cxc) so there are none, or answer one with pane send <pane> "1".
- Remote / mesh / nested-tmux panes: local
pane drives the local server only; use swarm send (it routes over tailscale ssh … tmux) for another device.
Under the hood (manual fallback)
If you ever drive a pane by hand, this is what pane automates — stage literal
text, a separate Enter, then capture to confirm (a welded C-m gets absorbed
by a TUI's paste and won't submit):
tmux send-keys -t %93 -l "$(printf '%s' "$msg" | tr '\n' ' ')"
tmux send-keys -t %93 Enter
tmux capture-pane -t %93 -p | tail
Checklist