Terminal interface
When to read this: You want to use Chatty from a terminal — interactively, as a one-shot command, or in a pipeline — with the same providers and models as the desktop app.
Install
| Method | How |
|---|---|
| From the desktop app | macOS: Chatty menu → Install CLI…. Linux and Windows: Settings → General → Install CLI…. The same spot offers Reinstall CLI later |
| From the release | The desktop package already contains chatty-tui |
| From source | Build it yourself: Build and run |
Where it lands: macOS puts a link in /usr/local/bin (you may be asked for an administrator password); Linux copies the binary to ~/.local/bin — add that folder to your PATH if chatty-tui is not found; Windows adds the app’s install folder to your user PATH, so open a new terminal afterwards.
Note
After a desktop update on Linux, the copy in
~/.local/binis refreshed the next time the desktop app launches./updateinsidechatty-tuidoes the same on demand.
Modes
| Mode | Command | Use |
|---|---|---|
| Interactive | chatty-tui | Full-screen chat with a model picker, tool picker and approval prompts |
| Headless | chatty-tui --headless -m "question" | One message in, the answer on stdout — for scripts and sub-agents |
| Pipe | cat notes.md | chatty-tui --pipe | stdin is the message; the answer goes to stdout |
| ACP | chatty-tui acp | Serves the Agent Client Protocol on stdin/stdout, so an editor such as Zed or VS Code can run chatty as its agent (below) |
Useful flags: --model <id or name> picks a model (exact id, then name, then substring); --enable / --disable switch tool groups for this run (shell, fs-read, fs-write, fetch, git, code-exec, docker-exec, ask-user, terminal; an unknown name is an error), and --only runs with exactly the groups named; --auto-approve skips every approval prompt (Security & sandboxing); --usage-file <path> writes what a headless or pipe run spent (tokens, model and tool calls, how it ended) to a JSON file (below). Full list: CLI flags.
Usage file
chatty-tui --headless --usage-file <PATH> -m "…" (or --pipe) writes what the
run spent to PATH as one JSON object; stdout, stderr and the exit code are unchanged. It is
written when the run ends however it ends (including SIGINT/SIGTERM/SIGHUP), and
rewritten after every model call while it runs, so a run killed from outside
leaves its latest totals with "exit": "running". Each write goes through a
temporary file and a rename, so a reader never sees half an object.
{"schema":1,"input_tokens":550,"output_tokens":25,"cache_read_tokens":350,"cache_write_tokens":null,"reasoning_tokens":4,"model_calls":4,"tool_calls":2,"tool_calls_failed":1,"turns":3,"follow_up_passes":2,"duration_ms":18,"exit":"completed","model":"llama3.2"}
| Field | Meaning |
|---|---|
schema | 1; bumped only when a field changes meaning or goes away |
input_tokens | Prompt tokens over every model call, cached ones included |
output_tokens | Generated tokens over every model call, reasoning included |
cache_read_tokens | Prompt tokens served from the provider’s cache (part of input_tokens); null when no call reported any |
cache_write_tokens | Prompt tokens written to the provider’s cache (part of input_tokens); null when no call reported any |
reasoning_tokens | Output tokens spent reasoning (part of output_tokens); null when no call reported any |
model_calls | Model requests that completed and reported usage |
tool_calls | Tool calls the model started |
tool_calls_failed | Those that ended in an error |
turns | Passes: the task, then every prompt the run sent itself |
follow_up_passes | The passes after the task’s (stall resumes, retries, nudges, finalizations) |
duration_ms | Wall-clock time since the run started |
exit | running, completed, deadline (the --max-duration budget was spent), error (non-zero exit) or cancelled (a signal) |
model | The model identifier the run used |
delegated_by_agent | Agent name → input_tokens, output_tokens and model_calls its delegations reported (already part of the totals); absent when the run delegated nothing |
Totals are summed per model call across every pass, plus what delegated agents
reported spending; tool_calls counts this agent’s own calls. A request cut off
mid-stream reports no usage and is not counted.
Export a conversation
Export a conversation as ATIF, the trajectory format the desktop app also writes, to debug a run.
chatty-tui --headless --export-atif <PATH> -m "…"writes the finished conversation when the run ends, also when it fails or is stopped.-writes to stdout./export [path]in the interactive TUI exports the current conversation. Without a path it writes<config dir>/chatty/exports/<conversation-id>.atif.jsonand prints where.chatty-tui --export <conversation-id> [--out <PATH>]exports a saved conversation without running anything.
A run that delegated exports as one tree. Each agent’s turns, reasoning, tool calls with their results, and token usage come right after the step that delegated to it. Each step names its agent by path, for example root/coder-1, and the delegation step that started it. The agents, their models, spend and final status (completed, failed or stopped) are listed together. best_of attempts and the judge sit under the best_of step, which records the attempt kept and the judge’s reason. If a worker’s conversation was over the capture size limit, or a stopped worker left none, the export says so. It does the same when the step token counts do not add up to the run’s total.
API keys and your configured secrets are replaced with [REDACTED] in every export. Text a tool returned is exported as the tool returned it, so check it before sharing a trajectory. --save-conversation is a different file: the restore format, not an analysis export.
Zero-config quick start
Talk to a running model server without opening the desktop app or storing a key:
# Ollama (discovers models at localhost:11434; pass a URL for another host)
chatty-tui --ollama
chatty-tui --ollama --model llama3.2
# vLLM, llama.cpp, LM Studio or any OpenAI-compatible server
chatty-tui --openai-compat-url http://localhost:8000
chatty-tui --openai-compat-url http://localhost:8000 --model my-model --api-key sk-...
Add --think true / --think false to force a reasoning model’s extended-thinking mode on or off for the session — useful here since a zero-config session has no saved model settings to toggle it in otherwise. Works with Ollama and OpenAI-compatible servers that support a reasoning parser (for example vLLM’s --reasoning-parser).
Welcome screen and status bar
An empty interactive session shows what is active: model and context window, workspace and git branch, enabled tool groups, internet capabilities (fetch, search, browser, cloud sandbox, MCP) and runtime features (memory, modules, remote agents). MCP, memory and embeddings load in the background — badges show ⟳ (for example [MCP ⟳]) and the status bar reads loading services… until they are ready.
The status bar always shows the app version, the working directory and the git branch when you are inside a repository, plus the branch’s pull request (#591 open ✓) when git integration is on. Footer hints switch to Enter queues · /now <text> interrupts · Ctrl+C stop · Ctrl+Q quit while a reply streams, and the status line adds · N queued once a message is waiting. Once a provider round-trip has completed, or a second has passed, streaming also gets a · turn 3 · 1:15 suffix — the running turn count and elapsed time — so a long unattended reply still shows it’s making progress. A scrollbar appears when the transcript overflows; scrolling up unpins auto-scroll, End re-pins it. While the agent works through a multi-step plan, the status bar also shows its position (●▸○ Plan 1 of 3 · <step title>), cleared when you send the next message. Once the agent has edited files, a change tray segment (4 files +58 −4) tallies every edit made so far in the conversation.
Tool calls in the transcript are folded by default — a single call shows the tool and its main argument on one line, the result trimmed to a few lines with a … +N lines marker, and a run of several calls that all succeed collapses further into one counted line (for example explored 3 files, ran 1 command). A settled call is one line with a ▸ marker; click it to open its result (▾), and click again to close it. The counted line is clickable too and lists the calls it covers. The call still running shows its whole command, wrapped over up to four rows. A command that needed your approval renders inline with its verdict (Approve [host] <command> — allowed), and a file edit gets its own stat line (± path +a −r). Errors are always shown in full and never folded. Press Ctrl+R or run /verbose to switch to the full, untrimmed input/output for every tool call; the footer hint shows which mode is active.
A multi-step plan renders as a single card instead — a goal, a progress count and one line per step (pending, in progress, done, blocked, with its reason) — redrawn in place as the plan advances rather than logging each update as its own row. /verbose still shows the raw plan tool calls.
Keys
| Key | Action |
|---|---|
Enter | Send |
/ | Command picker (↑/↓, Tab or Enter) |
@ | File picker (type to filter) |
PageUp / PageDown, Shift+↑/↓, mouse wheel | Scroll |
End | Jump to the bottom and resume auto-scroll |
y / n | Approve or deny a tool prompt |
1-9 | Pick an option when the agent asks a clarifying question (ask_user) |
t | Type a custom answer instead of picking an option |
Ctrl+C | Stop streaming, or quit when idle |
Ctrl+Q | Quit immediately |
Ctrl+R / /verbose | Toggle full tool-call payloads on or off |
A pending clarifying question replaces the input row and takes over the
keyboard until answered — Ctrl+C/Ctrl+Q still work. Multiple questions are
answered one at a time; press Esc while typing a custom answer to go back
to the options.
The terminal app has a few commands of its own — /model, /tools, /modules, /update, /paste, /now, /unqueue, /export, /swarm, /msg, /stop, /quit — alongside the shared ones. All of them: slash commands.
/swarm prints the agent tree for the conversation’s latest delegation as an indented list, one row per agent: name, model, status (running, done or failed) and spend. With no delegation yet, it says so.
/msg <agent> <text> sends a message to a running agent, by the name /swarm shows. The agent reads it at its next tool call rather than waiting for its run to end.
/stop <agent> stops one agent of the running swarm, by the name /swarm shows, and every agent it started. The rest keeps running, and the agent that called it carries on without it.
/agents running lists only the agents still running, one per line: name, conversation, the agents above it, whether it is working or waiting on you (for an approval or an answer), how long it has run, and what it has spent so far. The desktop shows the same list across all conversations (see sub-agents).
Sending a message while a reply is still streaming doesn’t get refused — press Enter as usual and it queues, showing up in the transcript as Queued #1: <text>, Queued #2: <text> and so on, and runs as its own turn once the current one ends. /now <text> instead cancels the running turn right away and sends <text> next. /unqueue takes back the message queued last. Up to 5 messages can wait; a sixth is refused. Ctrl+C cancels the current turn but leaves the queue as it is — nothing runs until you send (or /now) again, which then runs the queue’s front first.
/online is an unfinished feature, off by default: it only does anything once Settings → Execution → Developer → Hosted Conversations is on (a moved conversation carries its transcript and nothing else yet). With it on, /online shows where the current conversation runs and, before anything moves, a table of what a move would and would not carry. /online <server-url> uploads the conversation’s history to that chatty-server and continues it there; /online off brings it back to this machine. Workspace files, attachments, MCP servers, memory, skills and provider API keys never leave this machine. The server needs a Hive sign-in: /online reuses the one saved by the desktop app (Settings → Extensions → Hive) without refreshing it, so sign in there first.
Pasting more than 6 lines or 800 characters replaces the pasted text in the input box with a short reference, [Pasted text #1 +45 lines], so a stack trace or log dump doesn’t fill the screen — shorter pastes (a URL, a path, a one-line error) are inserted as-is. The model still receives the full text when you send the message. Run /paste 1 to print a reference’s full text back to the transcript. The reference acts as a single character: the cursor steps over it, and backspace at its edge removes the whole thing.
Use chatty as an agent in Zed or VS Code
chatty-tui acp runs chatty as an Agent Client Protocol (ACP) agent, so an editor can use it as its coding agent. Each editor thread is its own chatty conversation, rooted at the folder you have open. It uses your chatty providers, models, tools and MCP servers. Tool calls, the files they touch and the agent’s todo plan show up in the editor, and when a tool needs approval the editor asks you with Allow / Deny.
The command. The editor starts chatty-tui itself, so give it the full path:
- macOS app:
/Applications/chatty.app/Contents/MacOS/chatty-tui - Linux: the
chatty-tuibinary inside the AppImage, or one you built - From source:
cargo build --release -p chatty-tui, thentarget/release/chatty-tui
Put other flags before acp, e.g. "args": ["--model", "claude-sonnet", "acp"] or "args": ["--ollama", "acp"].
Zed
Zed supports ACP agents natively. Open Agent Settings → External Agents → Add Custom Agent, or add this to your settings file:
{
"agent_servers": {
"Chatty": {
"type": "custom",
"command": "/path/to/chatty-tui",
"args": ["acp"],
"env": {}
}
}
}
Then pick Chatty in the Agent Panel. dev: open acp logs shows the protocol messages; chatty’s own log goes to stderr, which Zed writes to its log.
VS Code
VS Code has no built-in ACP support, and chatty does not appear in Copilot Chat. Install an ACP extension instead, such as ACP Client (also on Open VSX for Cursor and Windsurf), and add chatty to your settings.json:
{
"acp.agents": {
"Chatty": {
"command": "/path/to/chatty-tui",
"args": ["acp"],
"env": {}
}
}
}
Open the ACP panel in the Activity Bar and click Chatty to connect. Keep acp.autoApprovePermissions at ask so chatty’s approval prompts reach you; allowAll approves everything. ACP: Show Protocol Traffic shows the protocol messages.
Not supported yet
- The model asking you a clarifying question (
ask-useris off over ACP). - MCP servers configured in the editor (chatty uses its own).
- Images in the prompt.
- Reopening an earlier thread or session.
--team.
Other ACP editors should work the same way — JetBrains IDEs and Neovim (CodeCompanion, avante.nvim) among them — but only Zed and VS Code are described here.
Install a team
chatty-tui --install-team NAME[@VERSION] installs a published team from the Hive marketplace, with every spec and locked plugin signature-checked, then exits. See Install a team from the marketplace.
Shared configuration
chatty-tui reads the same settings as the desktop app — providers, models, tools, secrets and memory — so run the desktop app once to set things up, or skip that entirely with --ollama / --openai-compat-url. Where the files live: Advanced.