The loop
tty7 wait
Exit codes are made for scripts:
The reply carries the agent’s own message and its native session id, so a
wake-up is directly actionable.
The states
Four of them are the agent’s own status. The other three are about the pane, because not everything worth waiting on is an agent:Waiting on a command instead of an agent
An agent says when it is done. Acargo test does not — so for a plain pane the
question is whether anything is still running in front of the shell, which is
what free answers:
free costs one extra request per poll, so it is only checked when you name it —
and only once the agent ladder has not already answered, so pairing it with
waiting,done never costs you a state you asked for.
A pane with no agent reports
no-agent, not idle. That distinction is
why --until idle cannot be used to mean “the command finished” — idle is a
thing an agent says about itself, and a busy shell never says it.Why --changed matters
The status the server keeps is a level, not an event. done stands until
the next turn begins; waiting stands until the agent moves again.
So a wait issued immediately after a send can answer with the previous
turn’s state, before the worker has even read the input. --changed refuses the
state the pane was already in, which is what every round after the first needs.
Without it, the JSON’s stale flag tells you whether that happened.
free has the same problem and a different fix: a shell that goes free → busy →
free ends up where it started, so there is no new state to compare against.
There --changed means “something ran while I was watching”, which is exactly
what you want in the line after a send.
That does mean a command which starts and finishes between two polls is never
seen running, and the wait sits there until it times out. If the thing you are
waiting on can be that quick, poll faster (--interval 100) or drop --changed
and let a sentinel file carry the answer. The timeout says as much when it
happens.
Answering a prompt
A worker that stops atwaiting is usually showing something that keystrokes,
not text, are the answer to — a permission prompt driven by the arrow keys, a
menu, a TUI to be dismissed. send --key presses keys:
When an agent never moves
Iftty7 wait times out and tty7 agents shows a status that never changes,
the likely cause is that the agent’s status hooks are not installed or are out
of date — the agent is working fine, it just has no way to say so. tty7 doctor
reports where every agent’s hooks stand, and tty7 agents names the specific
one when it can see the gap.
Watching everything at once
Teaching an agent to do this
tty7 installs nothing into~/.claude for it — no switch in Settings →
Agents writes a skill, and none ever will. What the agent needs to know ships
in the repository instead, as a skill you install yourself:
wait step is documented on this page.
A skill rather than a global instruction, on purpose: only its one-line
description rides in context until something reaches for it, so an agent that
never touches another pane pays nothing for it.
Rules of the road
- Never
sendinto a pane you did not open. Checktty7 agentsfirst. - Never close a pane, tab, or workspace you did not create.
- Never
server stoporserver restart. Every pane on the machine dies with it. - Clean up what you did create —
tty7 pane close %83when you are done. An interruptedrunleaves its pane behind;tty7 pane ls --allshows those, andtty7 pane close --orphansclears them. That last one is a human’s broom, not an agent’s: it closes every orphan on the machine, including ones somebody else abandoned mid-command.