A chat has three bands from top to bottom: the status strip, the transcript, and the composer. The transcript stays pinned to the newest line while the agent works. Scroll up to read something earlier and it stops following; scroll back to the bottom and it follows again. The wheel scrolls it from anywhere in the pane, the gutters included.
What the rows are
Your prompts
Your messages are the bubbles on the right, with any attached images shown small above the text. A steer is a bubble too, inset and labelled Steer, because it went into the turn above it rather than starting a new one.
Hover a past prompt to see Rewind to here on agents that can rewind. See Rewind and fork.
The agent’s replies
Replies render as Markdown: headings, lists, tables, quotes and code.
- Code blocks are highlighted in their language, and have a Copy code button.
- Mermaid blocks are drawn as diagrams.
- Links to a web page open in your browser. A link to a file in the
project, like
src/sign.tsorsrc/sign.ts:42, opens the file in the editor, at that line when there is one. A link to a file outside the project only says where it is, rather than opening something unexpected. Atori://link, which the Autopilot writes, opens that folder or session in Tori. - Raw HTML in a reply is shown as text, and a remote image is turned into a link, so nothing in a reply can load or run anything.
Thinking
When the agent thinks before it answers, a Thinking row appears and shimmers while it is live. Afterwards it reads Thought for 12s. Click it to read the thinking, and Hide thinking to fold it again.
Tool calls
Each tool the agent runs is a row: the tool’s name, the argument that tells this call apart (a file, a command, a search pattern), how long it took if over a second, and its state:
| State | Meaning |
|---|---|
| Running | The call is in progress |
| Waiting for approval | It needs your permission; the prompt is on the row |
| Done | It finished |
| Failed | It returned an error. The name is drawn in the failure colour |
| Denied | You or a rule refused it |
A failed or denied call stays folded, like any other, so a turn that makes a dozen calls does not rearrange itself under you. The row already says what happened.
Click a row to open it. Inside you see the full input, the output, and for a tool that edits a file, the diff of exactly what this call changed.
- Every path is clickable. Click a file name, or a line in a diff or in search output, to open the file in the editor at that line.
- Long output folds. Output past 20 lines folds, with Show full output to read the rest. Set the number in Settings > Chat > Tool output lines; 0 shows everything. Very old output is not kept forever: The rest of this output is no longer held.
- Several writes to one file in a row fold onto the first card, which then shows each write’s diff in turn.
Undo one hunk from the transcript
An edit card can show what is on disk now, and undo part of it.
- Open an edit call’s card.
- Click Compare with the file on disk. Tori compares the file with how it was just before this call, using the copy it kept at the time.
- Each hunk of the difference has a Revert button, Undo this hunk in the working tree. Click it to put that part of the file back.
Tori checks the hunk is still exactly what you see before writing anything, so a revert never lands on lines that have moved. If no copy was kept, for example in a chat reopened from history, the card says there is nothing to compare against.
Hooks
Claude’s hooks run around tool calls. A hook only shows in the transcript when it fails, with its exit code and what it printed. Turn on Show every hook event in Settings > Chat to see every run. Tori’s own hook, which keeps the copy of a file before an edit, is labelled Tori’s before-state hook.
Notices
One line notices tell you about the session: a model switch that will apply from the next turn, a compaction in progress (with how long it has been running), a spending ceiling coming close, an error and what the agent’s process printed when it died. Some have a Summary you can open for the detail.
Rows from Tori
When Tori itself writes into a chat, the row is centred and wears the Tori mark, so it never reads as something you said:
- Tori: news on pull request #482, from a watched pull request.
- Tori continued after the usage limit reset, from Resume at reset.
- Tori told this chat about its Topic, and its Topic changed, in a Topic chat.
- From Retry worker, a steer sent by another session.
- The Autopilot’s brief, resumes and wake ups, in the Cockpit.
Click the info button on the row to read exactly what Tori sent.
Command output
What the agent prints for a slash command, like /usage, /context or
/cost, is shown as a block in the transcript, and stays there when the chat
is reopened.
Fold the agent’s work away
Turn on Collapse agent work to read a chat as prompts and replies only. Between two replies, the thinking, tool calls, hooks and answered questions fold into one line, for example 4 tool calls, 1 hook, or Thought for 20s when there was only thinking. A count of failures follows in red. While the agent is working, the line names what it is doing right now. Click a line to open it.
A permission prompt or a question still waiting on you is never folded.
Switch it from the session menu or in Settings > Chat. It applies to every chat.
Read a reply aloud
Hover a reply and a speaker button, Read aloud, appears in the gutter to its left. Click it and Tori reads the reply to you in the voice and at the speed set in Settings > Chat > Read aloud. The voice is a model that runs on your Mac, so nothing you read leaves the machine. It needs macOS 13.4 or later on an Apple Silicon Mac. On an Intel Mac the button, Read on a selection and the Read Aloud commands are not there, and Settings > Chat > Read aloud says Needs an Apple Silicon Mac.
Downloading a voice
The first Read opens Download a voice, since the model is not part of Tori. Pick one of three:
| Choice | Download | What you get |
|---|---|---|
| Smaller | 107 MB | The natural voice. Sounds nearly the same as Larger, and 28 voices to pick from |
| Larger | 340 MB | The natural voice at full quality. The same 28 voices |
| Fastest | 60 MB | Starts quickest. Eight voices, and a little less natural |
Download fetches it, with the progress shown as Downloading, 40 of 107 MB, and the reply is read once it lands. Not now closes the dialog: a download already started carries on, but the reply waiting on it is not read. Reading something else while the dialog is open replaces the waiting reply. If the download fails, the dialog says Couldn’t download the voice: and why, with Retry. One model is installed at a time; you change or delete it in Settings.
The model loads on the first Read, about half a second, and Tori starts loading it as soon as a chat with a reply is in front so the wait is usually gone by the time you click. After five idle minutes it is dropped to free the memory.
What gets read
What gets read is the reply as it is drawn, not its Markdown source:
- Paragraphs, list items, headings and quotes are read one after another, with a short pause after a heading and after each list item.
- A table is read row by row, the header row first, with its cells read as a list.
- A task list item is read with its state first, to do, or done,.
- A code block is not read out. Tori says Code block skipped. in its place, so a sentence like “run this:” does not run into the next one.
- Inline code is read as plain words, and a link is read as its text, without the address.
- A check, cross or warning emoji is said as check, cross or warning. Other emoji are skipped.
A reply still being written is read as far as it has got, and the reading stops there rather than following it.
How code is said
A reply about code is rewritten into what a developer would say before it is spoken, so a path or a flag is not spelled out letter by letter:
| Written | Said |
|---|---|
src/utils/speech.ts |
speech dot T S, in src utils |
Omnibox.tsx:703 |
Omnibox dot T S X, line 703 |
config/corne.keymap, .gitignore, desktop/ |
corne dot keymap, in config; dot gitignore; desktop folder |
https://github.com/gettori/tori/issues/103 |
github dot com |
3c492711, a commit hash |
a hash |
3.4.2, v0.3 |
3 point 4 point 2; version 0 point 3 |
--no-verify, -q |
dash dash no verify; dash q |
a != b && c == d, ->, std::env::var |
a not equal b and c equals d; to; std env var |
speech_speak, speakableBlocks, read-a-reply-aloud |
speech speak; speakable Blocks; read a reply aloud |
Cmd+Shift+P, LCTRL, BSPC, KP_SLASH |
Command Shift P; Left Control; Backspace; Keypad Slash |
107 MB, 450ms, 15%, ~2 GB, 3x6, #101 |
107 megabytes; 450 milliseconds; 15 percent; about 2 gigabytes; 3 by 6; number 101 |
e.g., i.e., vs, w/o, LCTRL / TAB |
for example; that is; versus; without; Left Control or Tab |
localhost:3000 |
localhost, port 3000 |
A colon or a parenthesis is read as a pause. Words developers say their own
way are said that way: JSON is “Jason”, src is “source”, SQL is “sequel”,
config, plugin, enum, yaml, toml, github, sudo and nginx are
words, and npm, CLI, API, URL, HTML, CSS, SSH, CPU, GPU,
DNS, TCP, JWT, DOM, UUID, ID and the like are spelled, as is any
word of up to five capital letters.
A word Tori does not know is spelled out letter by letter, unless espeak-ng is installed, in which case it sounds the word out instead.
While it reads
The paragraph being read is highlighted, and a chip at the top of the window says Reading aloud. On the chip:
- The speed button, 1x to start with, steps through 0.75x, 1x, 1.25x, 1.5x and 2x, then back to 0.75x. The new speed starts from the paragraph being read, and it is the same setting as Speed in Settings.
- Stop reading stops it.
The reading carries on when you switch to another tab, and the chip stays so you can stop it from anywhere. Reading something else replaces what is being read. Closing the window or quitting Tori stops it. There is no pause.
A selection, and the palette
To read only part of a reply, select it and click Read on the toolbar that appears beside the selection, next to Quote. A selection is read paragraph by paragraph too, without the highlight. The same toolbar appears on a selection in a PDF.
From the command palette (Cmd+K):
| Command | What it does |
|---|---|
| Read Selection Aloud | Reads what was selected when you opened the palette. Listed only when something outside a text box was selected |
| Read Last Reply Aloud | Reads the latest reply in the chat in front. Greyed out with No chat in front when no chat is, and says There is no reply on screen to read. when the chat has none yet |
| Stop Reading Aloud | Stops it. Greyed out with Nothing is being read otherwise |
If the voice cannot play, a notice says Couldn’t read aloud: and why, for example when no audio output can be opened.
Long chats
A long chat opens on its most recent turns, so it is quick to open. Click Load earlier at the top of the transcript to read further back; each click brings in more, from disk if needed. The figures on the status strip always count the whole conversation, not just what is loaded.
The status strip
The strip above the transcript says what the session is doing:
| Shows | Meaning |
|---|---|
| Working 1m 12s | A turn is running, with how long it has been going |
| Waiting for approval | It is stopped on a prompt or question for you |
| Compacting | The agent is summarising the conversation to free context. This can take half a minute with nothing else on screen |
| Waiting: 2 agents, 1 task and similar | The turn is over but subagents or background tasks it started are still running |
| Idle | Nothing is running |
| Connecting | The agent’s process is starting |
| Disconnected | The process went away. Click Reconnect to resume the session in a new process |
After it come the number of files the session has touched, and the session’s figures. Hover any figure for its name:
- Model: the model the session is running.
- Prompts you sent.
- Agent turns.
- Tool calls.
- Compactions, when there have been any, and roughly how many tokens they freed.
- Context: how much of the model’s context window the conversation uses, as a number over the window, a percentage and a small pie that fills. Shown only when the window is known.
The figures are read from the conversation on disk, so a session you reopened counts its earlier turns too.
The session menu
The … button at the end of the status strip opens the session menu.
Show changes as a diff
Swaps the transcript for one diff per file across the whole session: every file this chat changed, from how it was before the chat touched it to how it is now. A line rewritten four times shows once, at its final value. Click Show transcript to go back.
- Each file shows how many edits made its diff, and new file if the chat created it.
- A hunk the agent explained has a why button that shows the reasoning the agent wrote before making that change.
- shared marks a file another chat in the same worktree also wrote. The diff shows only this chat’s edits; the file on disk carries both.
- Changed by something else while this session ran lists files that changed in the worktree but not through this chat, with which chat claims them or unattributed.
- Side by side and Inline switch the layout, the same choice as the Changes panel.
This view needs the session to be running, because Tori keeps the before-copies only while it runs. For an ended session, use the transcript or the Checkpoints tab.
Collapse agent work
The same switch as above.
Send to a new chat
Opens a new chat on the same agent and account, and sends what is in the composer there. Use it to ask a side question without adding it to this conversation. With an empty composer it asks you to type something first.
Fork this chat
Starts a new chat that carries this conversation up to now, so you can try a different direction and keep the original. Only offered once the chat has some history, and only on agents that can fork (Claude today).
Side chats
New side chat opens a read-only copy of this session in a drawer beside it. Once a chat has side chats, they are listed here to bring to the front, reopen or remove. See Side chats.
Usage
Two lines: Last turn with that turn’s tokens and cost, and This chat with the session’s cost and turn count. Hover them for the detail: the session’s tokens, over how many turns, and its cost. For a chat you reopened, it says when the total only counts turns this window watched finish.
Session details
The last row of the menu. Under its name it already tells you how many MCP servers need you to sign in or are not connected, how many servers there are, and how many skills the session loaded. Click it to open the details in a panel beside the menu.
- The account at the top: the plan the agent reports, which of your accounts the chat runs on, and the organisation.
- MCP servers, with how many are connected. Each server has a dot (green
when connected) and, on the right, how many tools it offers, Needs
sign-in, or the agent’s own word for what went wrong. A server that failed
shows its error under it. Servers configured for this project that the chat
did not load are listed too: one in the project’s
.mcp.jsonthat Claude has not approved yet says pending approval (runclaudeto approve). - Skills, grouped by the plugin that brought them, with your project’s and your own under Project & user. Click a group to show or hide its skills.
- Plugins, with their versions.
- Agents and Chat capabilities, folded until you click them. Chat capabilities is what this agent can do in a Tori chat, such as rewind, steering, approvals, diffs, spending ceilings, subagents and attachments.
A server that needs signing in is signed into from the agent’s own interface; Tori shows the state but has no sign-in of its own.
Add an MCP server to the project
- Open the session menu and click Session details.
- Under MCP servers, click Add server.
- Type a name and the command that starts it, for example
npx -y @scope/server. - Click Save.
The server is written to the project’s .mcp.json, the same file
claude mcp add --scope project writes. Hover a project server and click
Remove to take it out of that file again. Servers configured at user level
are listed but not editable here.