Inbox and Review

One list of everything your agents are waiting on, a view of every agent with its conversation and the forms it showed you, answers from wherever you are, safer approvals, replies queued for a busy agent, and a review of what an agent changed.

The Inbox is one list of everything waiting for you, in every session and on every linked machine: approvals and questions an agent is blocked on, questions an agent put to you, mail, agents that errored, conversations to resume after a restart, and finished turns you have not looked at. From it you answer prompts, reply to agents and review what they changed.

The daemon keeps the Inbox, so every attached client sees the same list, and tuios list-attention prints it from a shell. The daemon can also send an item to your phone when nobody is at a client. See Push Notifications.

Setting up

Wire each harness you use to report its state. Its hooks then say when it works, waits and finishes:

tuios integration install claude-code    # or codex, gemini-cli, opencode, ..., or --all
tuios doctor agents                      # what is installed, and agent panes missing one

Without an integration, TUIOS still reads the process, the screen and the title, but it can say less. See Agents.

A person who never runs an agent is not shown any of this. Until an agent has been seen, the Inbox lines of the prefix menu, the palette's agent entries and the help's Agents section stay hidden. The keys work before that too.

Opening it

KeyDoes
Ctrl+B iOpen the agents view. The Inbox is its Needs you group
Ctrl+B oGo to the oldest item that needs you, switching session and workspace. o again goes to the next
Ctrl+B OGo to the newest finished turn you have not seen. O again goes to the next older one
Ctrl+B MOpen the agents view on the mail for you. m there opens the whole mailbox

The palette has them too: type agent.

The Inbox items are the Needs you group at the top of the agents view: approvals, questions, plans, mail for you, errors and conversations to resume. Mail to another machine whose link is down waits under Waiting to send. A row shows the pane's name, what it asks, its session and how long it has waited. The footer offers only the keys that act on the row under the cursor. An item closes by itself when what opened it stops being true: the agent leaves needs_input, the mail is read, or someone looks at the pane that finished.

f shows only the items, then one kind at a time, then every agent again. / narrows the list with a selector, such as harness:codex needs:you or session:api-fan-*. See Selectors.

Every key in the agents view is rebindable. The full list is on the Keybindings page.

From a shell:

tuios list-attention
tuios list-attention --kind approval --kind question
tuios list-attention --select 'harness:codex group:fan/add-retry'
tuios list-attention --snoozed
Approvals
   35s  #2     api/claude  approve Bash: make

Questions
   46s  #1     docs/claude  which retry policy?

2 waiting. Open the agents view with the prefix key then i, or jump to the oldest with the prefix key then o.

Only a person at an attached client can dismiss, snooze or answer an item. An agent cannot empty the list you read to find out what the agents want.

Answering a prompt from the Inbox

Space on an approval or a question opens the prompt as the pane shows it, with its numbered options and how long the agent has waited:

KeyDoes
1 to 9Choose that option
aApprove
AApprove and do not ask again, when the menu offers it
dReject
TabType an answer
rRead the prompt again
EnterGo to the pane instead
Esc, q, SpaceBack to the list

The keys are the ones the harness's manifest declares for that prompt. An answer is bound to an option's label, not its number, so A is offered only where the menu really has an "always" option. Before it presses anything, the daemon reads the prompt again and refuses if it changed. When two people answer the same prompt, the first answer wins.

The same two steps work from a shell outside every pane:

tuios peek-prompt -w review
tuios respond -w review --prompt-id 75f8b9fadb5b5dfc approve
tuios respond -w review choose 2

Crush permission prompts

Crush draws its permission prompt as a "Permission Required" dialog. TUIOS reads the dialog from the screen:

  • The pane goes to needs_input, and the Inbox lists it under Approvals.
  • The message names the tool and what it acts on, such as approve bash: touch hello.txt: the command for bash, the file for edit and write, and the URL or folder for the others.
  • Space on the row shows the dialog. a allows, A allows for the rest of the Crush session, and d denies. TUIOS presses Crush's own keys for each: a, s and d.
  • The dialog does not always show the whole call. A long command scrolls in the dialog, and a narrow dialog shows only Crush's description of the command. Then the message ends with (not all shown), and allowing it takes a second press, as for a risky call. Read the dialog before you allow it.
  • TUIOS answers only the dialog itself. The dialog's words in Crush's chat, with no box around them, are not a prompt. When two boxes on the screen hold the dialog's words, TUIOS offers no answers.
  • TUIOS answers only when it sees a Crush process in the pane. Any program can report to the herdr socket as Crush.

Crush v0.97.1 and earlier can report working while the dialog is still up. TUIOS then reads the screen, and the pane stays on needs_input until the dialog closes. If Crush stops at its dialog, for example after a crash, the pane clears when it is back at its shell.

Who may answer

respond acts as you, so the daemon takes it only from your attached client, or from a shell outside every pane when [daemon] respond_from_shell = true is set in the config file. A program inside a pane is refused with not_human, unless you gave that pane the respond grant.

Approvals the Inbox holds

The peek presses keys into a prompt on the pane's screen. For Claude Code, opencode, Kilo and Qwen Code, the Inbox can also hold a permission prompt before the harness shows it, and answer it for you. Turn it on per harness:

[agents.approvals]
enabled = ["claude-code", "opencode"]
hold_seconds = 120

Then run tuios integration install claude-code (or opencode, kilo, qwen) again, so its hook is the version that waits.

While a prompt is held, the harness shows nothing in its pane. The row under Needs you shows the request, such as approve Bash: go test ./..., and its card beside the list shows the whole line:

KeyDoes
a, 1Allow once
A, 2Always allow. Offered only when every rule it adds can be shown, and the rules are shown
r, 3Reject
RReject with a reason you type, which the model reads

A key answers only what you have read: the digits do nothing until the item has been on screen, unchanged, for 0.4 seconds. Only a request that fits on one line whole is held, such as a shell command or a file read. An edit, an MCP tool call or a long command is answered in the pane as before.

The hold ends with no answer, and the harness asks in its own pane, when hold_seconds passes, when you go to the pane, when you dismiss the item, or when the pane moves on. Any error on the way (no daemon, a restart, an unreadable reply) also falls back to the harness's own prompt. A failure can never approve.

Risk rules

An approval whose command matches a risk rule is marked risky: its row reads risky:, the rail's word for it is risky, and the card names each rule. 1 and 2 then allow it only on a second press of the same key within 3 seconds. The first press sends nothing and says when it lapses. 3 rejects with one press. The daemon enforces this too: an allow of a risky call that does not name the rules it matched is refused.

The shipped rules are matched against every command of a shell line, after sudo, env and similar wrappers, and inside sh -c, $( ), backticks and eval:

RuleMatches
recursive deleterm with -r and -f, in any order
force pushgit push with --force, -f, --force-with-lease, or a + refspec
hard resetgit reset --hard
cleangit clean -f, -fd, -fx
discard changesgit checkout -- ., git checkout ., git restore .
pipe to shellcurl or wget piped to a shell or interpreter, or run through one with a substitution
sudoany command under sudo or doas
diskdd of=, mkfs, a redirect to a disk device
wide permissionschmod -R 777, chown -R on / or ~
databaseDROP TABLE, DROP DATABASE, TRUNCATE TABLE
infrastructureterraform apply or destroy, kubectl delete, docker system prune, npm publish, cargo publish
outside the worktreea write, copy, move or delete of a path outside the pane's worktree, or a Write or Edit of one

Add your own, or turn the shipped ones off:

[agents.approvals.risk]
builtin = true

[[agents.approvals.risk.rule]]
name = "kubectl apply"
tools = ["Bash"]
pattern = '\bkubectl\s+(apply|delete)\b'

A speed bump, not a sandbox

A command written to hide what it does (a variable holding rm, an alias, a script) passes the rules. The harness's own permission system stays the boundary. The rules make allowing a dangerous call take two deliberate presses.

Plans

With approvals on for Claude Code, a plan it asks you to approve when it leaves plan mode is held too. The row is the plan's title and length, and its card beside the list shows the whole plan. J and K scroll it.

KeyDoes
1Approve. Claude Code leaves plan mode and still asks before each edit
2Approve and accept edits for this session, when Claude Code offers that
3Keep planning
RKeep planning, with a reason you type

1 and 2 work only once the plan's last line has been on screen. 1 is the safest answer, which differs from Claude Code's own menu on purpose. Set hold_plans = false under [agents.approvals] to answer plans in the pane.

Questions an agent asks you

An agent, or a script, that needs a decision asks with fixed answers:

tuios ask-human 'Deploy the branch to staging?' -o yes -o no -o later

The question waits in the Inbox under Questions. When your client shows the pane that asked, the Inbox opens on it at once, and a digit picks the answer. From any other pane it raises the usual alert and waits. The command prints your answer and exits 0. If its --timeout runs out first it exits 2, the question stays, and your answer is mailed to the asking pane when you give it. Only you can answer: an agent calling it gets not_human.

While the question waits, the pane that asked shows needs_input, with the question as its note. The rail, list-agents and wait-for agent-state see it. When the call returns, the pane shows its earlier state again. A pane that is already on needs_input keeps its own prompt. A question from outside every pane changes no pane's state.

tuios list-agents -s work
╭───────────┬────────┬────────────────────────┬─────────┬────────┬──────┬───────────────────────────────╮
│ ID        │ NAME   │ STATE                  │ HARNESS │ SOURCE │ MAIL │ NOTE                          │
├───────────┼────────┼────────────────────────┼─────────┼────────┼──────┼───────────────────────────────┤
│ *a021e941 │ caller │ needs_input (question) │ (none)  │ report │      │ Deploy the branch to staging? │
╰───────────┴────────┴────────────────────────┴─────────┴────────┴──────┴───────────────────────────────╯

A script that waits for needs_input now also wakes on such a question. To tell the two apart, read list-attention: the question is an item of kind ask.

The question is one line of at most 160 bytes, and each answer at most 60 bytes. A longer question is refused, and the error names the next step:

ask-human failed: the question is 200 bytes, and the limit is 160 bytes.
Most likely cause: Nothing was asked. Send the details to the person in a
message, then ask a short question.
Fix: run 'tuios send-agent-message -s work -w human "<the details>"'.

Snoozing, undo and unread

Some of what lands in the Inbox is for later.

  • z snoozes the item, then 1 for 15 minutes, 2 for an hour, 3 until 9:00 tomorrow, or 4 until it changes. A snoozed item leaves the list and the counts, and comes back early when the pane reports something new.
  • S shows the snoozed items under a Snoozed heading. z on one wakes it now.
  • d dismisses. u undoes the last dismiss or snooze for 10 seconds.
  • On the rail, u on an agent row marks its finished turn unread again, for every client, and z opens the Inbox on it to snooze.

An approval the Inbox holds, a plan, and a question from ask-human cannot be snoozed, because an agent is waiting on them.

Try the keys on a pretend Inbox. Focus the list, then allow the risky command, snooze the finished turn and undo it:

Inbox, a model with the real keys
Inbox
Approvals 2
clauderisky: approve Bash: rm -rf build dist4m
codexapprove Bash: go test ./...2m
Questions 1
release[1-3] Deploy the branch to staging?1m
Errored 1
opencodego build failed: undefined: retryPolicy9m
Done 1
geminiRewrote the install page and fixed two broken links12m

approve Bash: rm -rf build dist

Risky: recursive delete, deletes a tree of files without asking

Keys for the item under the cursor↵answer in paneescclose
Click the list, then use the keys, or press the buttons. The first approval is risky: 1 only arms it, and a second 1 within 3 seconds allows it. Any other key disarms it, and 3 denies at once. z snoozes the errored or finished item, d dismisses, and u brings back the last dismiss or snooze for 10 seconds. Held approvals and questions cannot be snoozed, because an agent is waiting on them.

The agents view

Ctrl+B i opens one full-screen view of every agent: the agents of this session, of the other sessions, and of linked machines. The agents are grouped by what each one needs from you:

GroupHolds
Needs youThe Inbox items: approvals, questions, plans, mail for you, errors and conversations to resume
Ready for reviewA finished turn you have not looked at
WorkingAgents in the middle of a turn
IdleAgents at rest
Settled Added in v0.12.0Agents you put away, and agents at rest for more than an hour. See Settling an agent
SnoozedThe items you snoozed, when S shows them
The agents view. Agents are grouped under Needs you, Working and Idle. Beside the list, the thread of the Claude Code agent api shows its answer, an edit to retry.go as a diff with line numbers, a test run and its last answer. The reply area is at the foot.

On a wide screen each row has two lines. The first has the state mark, the name, the harness, the session (or the machine, for an agent on another one) and how long the agent has been in its state. The second says the one thing worth reading: what a Needs you row asks, what a working agent does now, or the branch of one ready for review, with its pull request and checks. Subagents hang under their agent. The attempts of a fan sit under one row with the fan's task. The rows come from the rail's agents section, so the two lists always agree.

Beside the list, the focus shows the selected agent: its name, harness and state, its branch, machine and folder, then a row of tabs, and at the bottom the card of what it asks. A held approval's card shows the whole command, where it runs, and the buttons that answer it. The card stays under every tab. [ and ] switch the tab:

TabShows
ThreadThe agent's conversation. See The thread
ChangesEvery edit of the last turn, whole. It shows once tuios reads the agent's transcript
Artifacts Added in v0.11.0The forms, dashboards and screenshots the agent showed you. It shows once the agent has shown something. See Artifacts
CheckpointsThe agent's checkpoints, newest first
PaneThe agent's live pane

A tab with items shows the count, such as Artifacts 3. At 170 columns and wider, a side column beside the focus also shows the live pane, the files the last turn changed, and the checkpoints.

KeyDoes
j, kMove
EnterGo to the agent's pane and close the view. On mail, open the thread
a A r ROn a held approval: allow once, always allow, reject, reject and say why. 1 2 3 still work
r, iWith no approval waiting: write a reply. See Replying and the queue
Tab, Shift+Tab UnreleasedGive the keys to the next or previous region: the list, the focus, the reply, the side column. See Regions
N UnreleasedGo to the next agent that needs you, and from the top again after the last
g, GGo to the first or last agent. When the thread is scrolled up, G first shows its newest lines and follows it again
SpaceRead an approval's or a question's prompt and answer it here
n Added in v0.11.0Start a new agent. See Starting an Agent
c Added in v0.11.0On an attempt of a fan: compare the attempts. See Fans, compare and judge
o Added in v0.11.0Open what the agent showed you, such as a form, on its Artifacts tab, and use it. Esc goes back to the list
x, *Mark the agent, or every agent shown, for a bulk answer. See Many agents at once
fShow only what needs you, then each kind of item, then every agent
sGroup and sort: 1 groups by state, 2 by session, 3 by machine, 4 by project, and s again steps the order inside each group. Needs you stays on top in every grouping. A click on Group in the header opens the same choice
\ UnreleasedShow the agents as a column beside the focus, or as a strip of chips above it
<, > UnreleasedMake the list narrower or wider. A drag on its edge does the same
Z UnreleasedShow the region that has the keys alone, or the whole view again
w UnreleasedHide the side column, or show it again
/Search. A key:value term is a selector. Other words match the name, the session and the agent's last message
vReview the agent's changes
[, ]Switch the tab: Thread, Changes, Artifacts, Checkpoints and Pane
J, KScroll the thread. On the Artifacts tab, move between the artifacts
eShow every line of every card in the thread
{, } UnreleasedShow the thread's previous or next prompt at the top. The ruler at the right of the thread marks each prompt
. UnreleasedSelect the next child agent a card in the thread started. Enter opens its thread
Ctrl+B [, y in the focusCopy mode over the thread. See Copy from the thread
Ctrl+]Look at the agent's own screen. Ctrl+B i comes back
?All keys
Esc UnreleasedGo back one step: from the focus to the list on a narrow screen, then out of a region, then clear the search and the filter, then close the view. The key bar says what the next Esc does
qClose

The mouse works too. A click on a row selects it, and a double-click goes to its pane. A click on a group heading folds the group. The buttons on an approval card answer it, and + New agent opens the New agent sheet.

The layout follows the screen. From 120 columns the rows have two lines. From 80 columns they have one. Under 80 columns the list fills the screen, and Enter, → or a click opens the focus in its place. agents.list_width Unreleased sets the width of the list, as a number of cells such as 52 or a share such as 30%, and agents.view_list Unreleased picks a column, a strip of chips, or auto (a strip for two agents or fewer). <, > and \ change them, and the view keeps your choice.

The header counts the agents by state. A click on a count filters the list to that state. An agent on another machine has a chip with the machine's name on its row.

Regions Unreleased

The view has up to four regions: the list, the focus, the reply and the side column. One of them has the keys. Tab and Shift+Tab move the keys to the next or previous region, and a region the screen does not show is skipped. Z shows the region that has the keys alone. Esc steps back out, one step at a time, and the key bar at the foot shows the keys you can press there.

Upgrading from v0.10.1

The agents view replaces the Inbox panel. The Inbox items are its Needs you group. Some keys moved:

  • n opens the New agent sheet. Reject with a reason is now R.
  • x marks an agent for a bulk answer. Before, this key was Space, which now reads the prompt.
  • f steps through the items, then each kind, then every agent.
  • The tab Live is now Pane.

Every key is a binding in [keybindings.inbox].

F Added in v0.12.0 folds the group of the row under the cursor. A folded group shows its title, its count and the state mark of each row. F or Enter on the heading opens it again. A row that changes group leaves the folded group. The folds stay when you close the view. [agents] fold_working = true folds Working until you open it.

Settling an agent Added in v0.12.0

When you are done with an agent's work and want it out of view, settle it. D puts the agent under the cursor on the Settled shelf, or every marked agent. The Settle button in the focus header does the same. Its finished turn closes. The agent keeps running in its pane.

The agents view with the groups Needs you, Working, Idle and Settled. The agents web and cache are under Settled. The selected agent, api, shows its thread and a Settle button with the key D.

A settled agent comes back by itself in five cases: it asks a question or waits on an approval, reports an error, finishes a turn, sends you mail, or leaves the pane. It then goes to the group its state gives it. D on a settled agent takes it off the shelf, and u undoes a settle for 10 seconds. An agent that needs you now is not settled: answer it or dismiss its item first.

An agent at rest for more than an hour goes to Settled too. Every client draws the same shelf, a second terminal, tuios-web and the agents view of a linked machine too. The rail folds a settled agent into its +N at rest line. Only a person can settle an agent. The after-settle hook runs a command for each settle.

The task board Added in v0.12.0

b, or the word in the header, turns the list into the task board: the task cards of every session, grouped by stage, one column for each stage. B shows the stages as a list, as in the picture below.

The task board in the agents view. Cards are in the groups Todo, Doing, Verify, Review and Done. One card under Todo is blocked. The selected card, write the changelog, is free. Its Card tab shows its prompt and its history.
  • Inside a stage, the blocked cards come first, then the cards whose holder needs you, then the oldest.
  • A held card wears the mark of its holder. A free card says free. The Card tab shows the card's prompt and history.
  • Enter goes to the holder's pane. t takes the card for the pane behind the agents view, when the card is in that pane's session.
  • The board lists this machine's cards.

Task Boards has the rest: the columns and their keys, the stages and the moves tuios makes on its own, verify, Ready to merge, cards for a repository across machines, and dispatch.

Agents that stop reporting Added in v0.12.0

A harness with hooks reports at each prompt and each tool call. When the harness hangs, the reports stop. A pane that reported working through a hook, and then sends no report for silent_after, shows as unknown with the reason silent. The default is 10 minutes.

  • get-agent-state and list-agents report state: unknown and reason: silent.
  • The rail and the agents view draw the unknown mark. The row reads "No report for N min".
  • The state the agent reported stays working underneath. ask-agent, fan, the queue and mail do not type into the pane. The next report shows the agent's state again.

Set a longer time if your agents run long tool calls that send no hooks. See Agents that stop reporting.

The thread Added in v0.10.1

The thread shows what the agent said and did, read from its own transcript. It works for Claude Code, Codex, Gemini CLI, Qwen Code, Copilot CLI, Amp, opencode and Cursor Agent. For other agents, the thread shows the recap of their turns, their last message and their last mail.

  • Your prompts sit in a panel with an accent bar. The agent's answers are drawn as Markdown: headings, lists, tables, links and highlighted code.
  • Reads and searches fold to one line.
  • An edit shows its diff, with line numbers and the changed part of each line lit. e shows every line of every card.
  • A command that failed shows the end of its output and a failed mark.
  • A todo list is a plan: done rows struck through, the running row bold, and a rule that fills as rows are done. While the agent works, its newest todo list is pinned above the thread, whole.
  • Each turn starts with one line that says how long it worked and what it did, such as Worked for 45s · ran 1 command and read 1 file. A finished turn with nothing failed folds to that line, and a click opens it. The turn at work says Working for 3m.
  • An image is a card: one you pasted under your prompt, and one a tool gave back under its call. A click on the card opens the image view. The picture is drawn with kitty graphics where the terminal has them, and with block characters where it does not.
  • A code block in an answer shows 12 lines and a line such as 10 more lines. A click on it, or e, shows all of it.

The newest card is at the bottom. The wheel, or J and K, scrolls the thread. The thread grows while the agent works. A gutter mark is in front of all text that an agent wrote. Nothing in that text is a link or a key.

Ctrl+] closes the view, focuses the agent's pane and zooms it. The dock shows Press ctrl+b i to go back to the agents. The view then opens on the same agent, with every draft kept.

Move through the agents, look at one pane with Ctrl+], and come back with Ctrl+B i.

The view does not poll. The list changes when the state of an agent changes.

Copy from the thread Unreleased

Ctrl+B [ starts copy mode over the thread, and so does y when the focus has the keys. It has the keys of a pane's copy mode: the motions, / and ? to search, v, V and Ctrl+V to select, and y to copy. A copy is the text as the agent wrote it: a paragraph the thread wraps is one line, and the card edges and marks are left out. Y copies the selected entries as Markdown.

Artifacts Added in v0.11.0

The Artifacts tab lists what the agent showed you, newest first: each TML document its pane opened with tuios tml show, open or closed, and each screenshot it took. The selected one shows under the list.

The agents view on the Artifacts tab of the release agent. The list holds an open release note form, a screenshot named retry.png and a test run dashboard that the agent closed. Under the list, the form is live, and its Note field holds the text the person pasted.
  • An open document is live. It is the same document as its popup or pane, with the same state, so what you choose in one place shows in the other. o or a click gives it the keys. Esc gives them back to the view.
  • A text field takes typed and pasted text. Tab or a click goes into a field, and Enter submits the form. The agent gets your answer.
  • A closed document shows what it showed last, and your answer. Its row says answered, closed by the agent or dismissed.
  • A screenshot shows its path and its format.
  • A document from another session is read-only here. Attach to that session to use it.

A TML popup and the agents view do not show at the same time:

  • Open the view while an agent's popup floats, and the view selects that agent and shows the document, with the keys.
  • A document that opens while the view is open shows in the focus when it is from the selected agent. From another agent, its row gets a ● new artifact chip, and a popup moves the row to Needs you. A click on the chip opens it.
  • Close the view while the Artifacts tab shows an open document, and its window gets the focus and floats again.

The daemon keeps the last 20 artifacts of each pane in memory, so a client that attaches again sees the same list. A daemon restart clears it.

Fans, compare and judge Added in v0.11.0

The attempts of a fan sit under one row with the fan's task. A row that is ready for review shows its branch, its pull request and the checks of the pull request.

c on an attempt compares all the attempts side by side. Each column shows the attempt's agent, how long it took, its diff, its check from tuios fan verify, its cost, its first changed lines and its files.

KeyDoes
jStart a judge: an agent that reads the attempts and records which one to keep, and why
1 to 9, arrowsPick an attempt
k twiceKeep the picked attempt and remove the others
EnterGo to the attempt's pane
rRead the attempts again
EscBack to the list

The judge works in a session of its own, with the read grant only. Through tuios it can only read the attempts (their diffs, screens and scrollback) and record a verdict with tuios fan verdict. The verdict shows on top of the comparison, with its reasons. The judge's pick is marked recommended, and the fan's row names it.

A keep removes the other worktrees. Their changes go to git stash, and their branches stay. The first k lists every file that git ignores in the other worktrees, such as .env. A keep deletes these files, and git stash does not keep them. ↑ and ↓ scroll that list. The second k reads the attempts again, and keeps only when nothing changed. When the list grew, or tuios could not read it, it says so and keeps nothing.

Machines

With linked hosts, every agent on every machine has a row, and each row names its machine. The Machines block at the foot of the list shows each machine with its agent count, its load and the state of its link. A click on a machine shows only its agents. When the link to a machine is down, its rows are dim, say link down, and show the last state tuios knew.

Many agents at once Added in v0.10.1

x marks the selected agent. * marks every agent shown, or clears the marks when all are marked. The title shows how many agents have a mark. With marks:

KeyDoes
rWrite one reply. Enter queues it for each marked agent, at most 32. An agent that waits on a prompt, or that runs on another machine, does not get it. The dock names those agents
1List each approval that the marked agents wait on. Enter allows all of them
3Reject each approval that the marked agents wait on
dDismiss what the marked agents have in Needs you
zSnooze what the marked agents have in Needs you. Then select the time

A bulk key acts only on the marked agents the list shows. An agent in a folded group, or one the search hides, is left out. Closing the view clears the marks.

The list that 1 opens shows each approval whole. Enter does nothing until the list has been on the screen for a moment. A risky approval, a plan, and an approval that the screen cannot show whole are not in the list. The list says 2 need a second look. Allow them one by one. An approval that changed after the list showed it is not allowed. 2, always allow, does not work on many agents at once.

Esc and Ctrl+] close a reply to many agents and keep the draft. A key that send-keys typed does none of these actions.

After a restart, each agent to resume is a Resume row. * then y resumes them all. To resume some, mark each with x and press y. y alone resumes the row under the cursor. The view stays open, and each row says Resuming until the agent is back. A Resume row on another machine is left out.

Replying and the queue

A message for an agent in the middle of a turn has nowhere good to go: typed now, it lands in the middle of the turn. The queue holds it in the daemon and types it the moment the agent comes to rest.

r on a finished or errored item in the Inbox, on an agent in the agents view, or on a rail agent row opens the reply editor. Enter queues the reply. If the agent is at rest, TUIOS types the reply in a second or so. If not, the row says 1 queued until TUIOS types it. On the rail, x drops the newest queued message and u within 10 seconds queues it again.

On a pane that waits on a prompt, r opens nothing and says api is waiting on a prompt. Answer it first (space to peek).

The reply editor Added in v0.10.1

The reply editor keeps line breaks. It grows to 8 rows, then scrolls.

The reply editor under the thread of the api agent. The draft holds text, a block for a pasted 23-line test log, and an image block. A preview of the image, a latency graph, is above the draft.
KeyDoes
EnterQueue the reply
Ctrl+J, Shift+Enter, Alt+Enter, \ then EnterAdd a new line
Alt+← →, Ctrl+← →Move by word
Home, End, Ctrl+A, Ctrl+EGo to the start or end of the line
Ctrl+W, Alt+BackspaceDelete a word
Ctrl+U, Ctrl+KDelete to the start or end of the line
Ctrl+Z, Alt+ZUndo, redo
Ctrl+CClear the draft
Ctrl+VPaste from the clipboard: its text, or its image when it holds an image and no text
↑, ↓, Ctrl+RBring back an earlier reply. See History and your editor
Ctrl+GEdit the draft in $VISUAL or $EDITOR
EscClose the editor and keep the draft. r on the same pane opens it again

The reject reason, the answer to a prompt and the selector line use the same editing keys, on one line.

Paste blocks. A paste of more than 800 characters or 3 lines shows as one block, such as [Pasted text #1 · 42 lines]. The cursor steps over a block in one move, and Backspace deletes all of it. When the cursor is right after a block, the block is selected and the footer shows its keys:

KeyDoes
Ctrl+ORead the text of the block. The arrows and page keys scroll, Esc goes back
Ctrl+EPut the text of the block into the draft, to edit it
BackspaceRemove the block

Undo brings back a block that you removed or expanded.

Before it sends, the editor removes invisible characters, such as Unicode tags, bidi controls and zero-width spaces. When it removes any, it does not send and says Removed 3 invisible characters. Read the message and press enter to send. Text from a web page can hide instructions in these characters.

Naming a pane, an agent or a file Added in v0.10.1

Type @ at the start of the reply or after a space. A list opens under the editor: the agents and panes of every session on this machine, and the files in the folder of the pane that gets the reply. Type more to narrow the list.

› compare with @rev
  agent work/review  working
KeyDoes
↑, ↓Select an entry
TabPut the entry in place of the @ and the text after it
Esc, SpaceClose the list

An agent or a pane goes in as its address, such as work/review. A file goes in as its path from the folder of the pane, such as api/client.go. A folder goes in with a slash and keeps the list open, so you can go into it. TUIOS does not copy the file. The agent reads it with its own tools.

The list shows no files for a pane whose folder TUIOS does not know, or whose shell runs on another machine. A client in a browser or on the SSH server shows no files, because the files are on the server and not with you.

Images Added in v0.10.1

An image in the reply shows as one block, such as [Image #1 · 1280×720 png]. These three actions attach an image:

  • Ctrl+V when the clipboard holds an image and no text. TUIOS reads it with wl-paste, xclip, osascript or PowerShell.
  • An empty paste from your terminal. Some terminals send one when the clipboard holds only an image.
  • A paste of only the path of an image file. A terminal pastes a file that you drop on it in this way.

While the draft holds an image, a strip above the draft shows a preview of each image, 3 rows high. The strip shows at most 4 images, then +N more. TUIOS draws the previews with kitty graphics when your terminal has them, and with block characters if not. At 16 colours each image is a line of text, such as Image #1 · 1280×720 png · 412 KB.

Ctrl+O on a selected image shows it larger in place of the draft. There, o opens the image in the image viewer of your desktop, from a private copy. TUIOS removes the copy when you close the view. Esc goes back to the draft.

A reply takes 8 images, each at most 8 MB, and 8 MB in total. The editor refuses the same image twice: Image #1 is already in the message. A client that runs on another machine, such as tuios ssh or the browser, cannot read your clipboard image. There, Ctrl+V pastes the text.

When TUIOS types the reply, the daemon writes each image to a file on the machine of the pane. The harness manifest tells where the path goes. Claude Code, Codex, OpenCode, Kilo and Crush get the path in a paste of its own, where the image was, so the agent attaches the image. See How a reply is typed. An agent that takes no images refuses the reply: This agent cannot take images. Remove the image to send.

Large pastes Added in v0.10.1

The daemon on the machine of the pane decides how each block gets to the agent when it types the reply:

  • A reply of 12 KB or less, to a pane that takes a bracketed paste, goes in one paste, with the text of each block in its place.
  • In a larger reply, each block goes into a file, and a label in its place names the file.
make the backoff jitter configurable. The failing run:
[Pasted text #1: /run/user/1000/tuios/paste/tuios-paste-reply-20261016-101500-3fa2c1.txt, 2,048 lines]

The agent reads the file with its own tools. The file is yours only, in the paste folder next to the daemon's socket. The daemon writes the file when it types the reply, so a reply that waits in the queue never names a file that is gone. The daemon keeps the file for 24 hours, and removes it when the daemon stops.

The typed text must fit in 16 KB. This count includes a label for each block. The whole reply must fit in 8 MB. A larger reply stays open and says why: The typed text is larger than 16 KB. Make it shorter to send. or The message is larger than 8 MB. Remove a paste or an image to send.

A daemon from v0.10.0 or earlier takes a reply with blocks only when all of it fits in 16 KB. For a larger reply, the editor keeps the draft and tells you to restart the daemon.

History and your editor Added in v0.10.1

↑ on the first row of the draft brings back what you sent to this agent before, newest first. ↓ on the last row goes the other way, back to your draft. Ctrl+R searches what you sent: type to narrow the list, select with the arrows, and press Enter to load the message. A draft that Ctrl+C cleared is in the history too.

The daemon keeps the history in memory only, for each harness and folder. A pane that opens again in the same folder keeps its history. The history ends when the daemon stops. Only you can read it, from a client outside every pane. Each message keeps at most 256 KB of pastes and images. The daemon does not keep a larger block, and the editor tells you when the message comes back.

Ctrl+G opens the draft in $VISUAL or $EDITOR, with the text of each block in its place. When you save and quit, the file becomes the draft. An image is in the file as its label, such as [Image #1 · 640×480 png]. Keep the label to keep the image in its place. Remove the label to remove the image. TUIOS refuses a file that is too large for a draft, and the draft does not change. The file is yours only, and TUIOS removes it when the editor closes.

When the daemon refuses a reply, the draft stays. Drafts stay in the memory of the client and end with it.

Replying to an agent on another machine Added in v0.10.1

A reply to an agent on a linked machine goes to the daemon on this machine, which sends it over the link. The other machine queues it, writes the paste and image files there, and types the reply when the agent comes to rest. The [hosts] policy of that machine for this machine must allow write, and files for a paste block or an image. See Remote Hosts.

Your draft comes first

A message waits while you write to the agent. tuios does not type a queued message or a mail wake when you typed into the pane less than 3 seconds ago. For Claude Code and Codex, it also waits while the input box holds text. The row shows "Waits: your draft is in the prompt box", and get-agent-state reports draft_held. A draft that holds a message for 10 minutes opens a question in the Inbox. Nothing is dropped.

The queue

From a shell:

tuios queue -w build 'make the backoff jitter configurable'
tuios queue ls
tuios queue rm q3
ID  STATE    BY     AGE       PANE   MESSAGE
q1  waiting  shell  just now  build  make the backoff jitter configurable
  • A message is typed once the agent has been at rest for a second, one message per rest.
  • It is never typed over a prompt the agent waits on, so a queued message cannot answer an approval.
  • The daemon watches for the agent to take it. A message it does not take within 5 seconds is marked stalled, is never typed again, and opens a question in the Inbox asking you to look at the pane.
  • A stalled message holds the messages behind it until the agent next works, shows on its screen that it took the message, or you drop it. When the pane shows within ten minutes that it took the message, the question closes and the message leaves the queue.
  • A pane holds at most 8 messages ([agents.queue] max), each at most 16 KiB of typed text. A reply with paste blocks can carry up to 8 MiB of pasted text. The queues hold at most 32 MiB for each pane and 128 MiB in total.
  • The queue lives in memory: a daemon restart, the pane closing, or the agent leaving the pane drops it.

Reviewing an agent's changes

When an agent finishes, read what it changed, leave notes on the lines you want changed, and send the notes back as one message.

Ctrl+B v reviews the focused pane. v in the Inbox or on a rail agent row reviews that item's pane. The review opens over the whole screen: the changed files on the left, the file under the cursor on the right, and each note under its line. The code is coloured by file type in your theme's colours, and s puts the old and new sides next to each other on a wide screen.

│ Review  api-fan-demo-2  Terminal f40d4b17  2 files  +2 -0  vs main  1 note
├──────────────────┬────────────────────────────────────────────────────────
│  M a.txt   +1 -0 │ › @@ -1 +1,2 @@
│  U b.txt   +1 -0 │    1   1   hi
│                  │        2 + change
│                  │          ▌ note from a script: why this line

c adds a note on the line under the cursor and C one on the whole hunk. S sends every unsent note to the agent as one message, through the queue, so it is typed when the agent is at rest. Every key is on the Keybindings page.

The review runs git with no hooks. A filter, textconv or diff program that only the repository's own config names does not run, so the review shows such a file as it is on disk. A filter from your global git config, such as Git LFS, still runs.

To read or undo what one turn changed, see Checkpoints. When the work is good, ship it: commit, merge, push and open a pull request. A push that an agent asks for waits for your yes under Questions.

From a shell:

tuios review api-fan-retry-2 --stat
tuios review note -s api-fan-retry-2 api/retry.go:42 'log the attempt number here too'
tuios review notes -s api-fan-retry-2
tuios review send -s api-fan-retry-2
Review of api-fan-demo-2, pane f40d4b17, against main (20e3b85): 2 files, +2 -0
M  a.txt  +1 -0
U  b.txt  +1 -0

What is diffed. The pane's repository, from its base: the base the worktree was made from (by fan or worktree new), else the merge base with the branch's upstream, else HEAD. Committed and uncommitted work show together, untracked files included. --base names another base, --uncommitted shows only what is not committed, and --against diffs two attempts of a fan. To open every review on the uncommitted changes, set [review] scope to uncommitted. The diff is made through a temporary git index, so the repository, its index and its files are never changed. It stops at 400 files, 2 MiB of text or 5000 lines in one file.

Notes. A note keeps the text of its line, so it follows the line when the file changes. A note whose line is gone is marked outdated. The daemon holds the notes, so every client and the CLI see the same ones. A daemon restart keeps the notes of panes that come back. Closing the pane, or removing its worktree, drops them. The message the agent receives names who wrote each note: it says "from the person" only for notes written in your attached client.

Reviewing a session on another machine is not supported yet. Attach to that machine and review there, or bring the work here with tuios worktree pull.

Step through a review, from opening it to sending the notes and keeping one attempt of a fan:

review and compare1 of 8

Open the review (Ctrl+B v)

Ctrl+B v reviews the focused pane, and v on an Inbox row or a rail agent row reviews that pane. The diff is the worktree against the base it was made from, committed and uncommitted work together.

Review api-fan-retry-2 claude 3 files +38 -6 vs main 0 notes
────────────────────────────────────────────────────────────────────────────────
M client.go +24 -6 │ ›@@ -40,6 +40,14 @@ func (c *Client) Do
A backoff.go +12 -0 │ 40 40 req = req.Clone(ctx)
M client_test.go +2 -0 │ 41 - resp, err := c.http.Do(req)
│ 41 + resp, err := c.retry(ctx, req)
│ 42 + if err != nil {
│ 43 + return nil, err
│ 44 + }
│
────────────────────────────────────────────────────────────────────────────────
c note ] next hunk } next file s split w compare esc close

The same from a shell

tuios review api-fan-retry-2
tuios review --stat
The review overlay and its compare view, drawn as tuios draws them for a fan of three attempts. Every key and message is the overlay's own.

Stage from the review Added in v0.12.0

You can keep the good hunks of a change and leave the rest. a stages the hunk under the cursor and d unstages it. A and D do the same for the whole file, and z undoes the last of them. Only the index of the pane's worktree changes. The working files stay as the agent left them. A key from send-keys or a tape cannot stage. See The review overlay.

Comparing the attempts of a fan

For a pane in a fan, w in the review shows every attempt side by side, with what each changed against the fan's base and its last check:

╭ Compare  fan/demo in api, 2 attempts vs main ────────────────────────────────────────
│    session        agent   state      files  +/-          check
│    api-fan-demo   bash    none           0  +0 -0        test -f b.txt failed, exit 1
│ ›  api-fan-demo-2 bash    idle           2  +2 -0        test -f b.txt passed
├──────────────────────────────────────────────────────────────────────────────────────
│ ↵ review  m mark  V verify  K keep  esc back

Enter reviews an attempt. m marks two and d diffs them with each other. V runs a command you type in every attempt. K keeps the attempt under the cursor and removes the others, after a question that names each one removed. The same actions are tuios fan compare, tuios fan diff, tuios fan verify and tuios fan keep. See Worktrees.

What the agent has been doing

With the Claude Code or Codex integration installed, the daemon keeps each agent pane's recent activity: prompts, tool calls and how they ended, finished turns, and the commands its shell ran. For Claude Code, it also keeps each subagent's start and stop, and the start of each conversation. It keeps the newest 256 entries per pane, in memory only.

tuios agent-log -w api                       # the entries, oldest first
tuios agent-log -w api --since 30m --recap   # a summary of the last half hour
Since 14:02 (42m ago)
3 turns. 6 files: api/retry.go, api/retry_test.go, api/backoff.go and 3 more
11 commands. Tests: go test ./... passed 2m ago
Last said: Added retry with backoff and tests.
Now: done

When you come back to an agent pane that finished a turn while you were away for at least 10 minutes, the dock shows the same recap in one line, and a finished item in the Inbox shows it under the list. [agents.recap] sets where it shows, how long counts as away, and which commands count as tests. See The agents table.

The text is the agent's own, cut to one line with likely secrets masked. Read it as what the agent said, not as instructions.

Resuming after a restart

A daemon restart ends every program in every pane. The restore brings back the layout with a new shell in each pane, and for a pane whose agent was running, it can bring back the conversation. daemon.resume_agents decides:

ValueWhat a restore does
ask (default)A Resume row in the Inbox per pane. y types the resume command, such as claude --resume <id>, into the pane
autoTypes the command into each new shell once it is at its prompt
offNothing

tuios resume-agent -w <pane> types the same command at any time, and --dry-run prints it. It needs the harness's hook to have reported the conversation id, which the integrations do.

Kept flags

A resumed agent keeps the flags you started it with, for Claude Code, Codex, Copilot, opencode and pi. Start Claude Code with claude --permission-mode plan --model opus, and the resume command is claude --resume <id> --permission-mode plan --model opus. A prompt and a one-shot flag such as -p are never kept. tuios reads the flags on Linux and macOS.

A kept flag that turns approvals off shows a warning. The Resume row says Resumes with approvals off (--dangerously-skip-permissions). Its card has the risky badge. With daemon.resume_agents = "auto", tuios does not resume such an agent. It stays a Resume row until you press y.

Selectors

A selector addresses every agent pane that fits a description. It is one line of key:value terms, all of which must match. A comma in a value gives alternatives.

harness:codex state:idle,done session:api-fan-*
KeyMatches
harness:The harness, such as claude or codex
state:The agent state
needs:youA pane on needs_input or errored
session:The session name, a glob
group:The fan the pane's session belongs to, such as fan/add-retry, a glob
host:The machine: local, or a host from [hosts]
name:The window's name, a glob
cwd:The pane's directory, or any directory under it

The Inbox's /, list-agents --select, list-attention --select and wait-for agent-state --select read it. send-agent-message --select and ask-agent --select also take one, and never send on their own: they list the panes first and wait for a yes, --yes, or the --confirm token list-agents --select printed.

tuios lives only at tuios.dev and github.com/Gaurav-Gosain/tuios. tuios has no X or Twitter account. An account that offers a tuios token or presale is not this project.

On this page