# TUI Guide

Single bubbletea textarea (`internal/runtime/tui`); slash commands open transient popups that close cleanly back to the prompt.

Since v1.2.0 the TUI no longer runs agents itself: the daemon runs every request and the TUI is a client over the Unix socket `~/.config/agenvoy/daemon.sock` (mode `0600`, newline-delimited JSON frames). A run is bound to the connection that started it, so closing the TUI stops the run while its pending snapshot is kept. Confirmations and `ask_user` questions from that run go only to the TUI window that started it; a confirmation for a path outside `$HOME`, a `sudo` argv or `sandbox: false` asks for the system password in a TUI password field (a sensitive path inside `$HOME` only needs a plain confirmation) and the daemon verifies it (`sudo -S -v`). When the socket is down the status line shows `Connecting` and the TUI retries every 5 seconds; plain input, skills, `/pending` resume and scheduler dispatch wait until it reconnects, while local `/` commands keep working. The work directory is the TUI's own: set it with `Shift+P`. Removed in v1.3.0: the daemon no longer pushes a directory the agent switched to with `cd`, because the agent can no longer change it.

Since v1.3.8, while the session has background legs running, the line above the input reads `N background task(s) running`, followed by `(esc to cancel)` when no run is in progress; it refreshes every second. The v1.3.0 `Waiting for background tasks (the reply continues here)` line, and the follow-up mode behind it, were Removed in v1.3.8 because a run no longer stays pending for its background work (see [Pending Tasks and Cancellation](/docs/execution-engine-pending)).

## Shortcuts

| Key | Action |
|---|---|
| `Enter` | Send the current input. While a run is in flight only plain text is sent, as a **steer** message delivered to the running loop; `/` commands are neither listed nor sent until the run ends |
| `Alt+Enter` | Insert a newline |
| `!` prefix | Since v1.3.0, `!<command>` runs the rest of the line with `$SHELL -c` (`/bin/sh` when unset) in the TUI's work directory, from the TUI process itself rather than the sandbox, for at most 30 minutes; the input box turns red with a `$ ` prompt while the line starts with `!`. The exit code and output (up to 32 KiB) print in the transcript, then go to the agent as a `[Shell command]` message asking it to report the result; that message is hidden from the chat history. Like any other message it needs a registered model and a connected daemon, and `Esc` / `Ctrl+C` stop the command. Since v1.3.2 a command containing the word `sudo` first checks for a valid sudo ticket; without one a `System password:` popup opens, the password is verified with `sudo -S -v`, and the command then runs reusing that ticket. A wrong password ends with `[Denied] password: incorrect password`; `Esc` closes the popup without running the command |
| `/` | Begin slash-command filter (popup picker — Up / Down to navigate, Tab / Enter to autocomplete into the textarea, Esc to dismiss) |
| `Up` / `Down` | Walk input history when the cursor is on the first / last line (per-session `.cmd_history` file) |
| `Esc` | Outside a popup, in this order (v1.2.0): dismiss the command picker, else close the notice box, else open the cancel popup while running — **No**, **Yes (cancel)**, or **Pause (keep pending)**. Cancel discards the pending task (since v1.3.9 it stays in chat history with a `[Canceled]` reply), pause stops the run and leaves it resumable through `/pending`; both also stop the task's background jobs. A run that has emitted nothing yet is cancelled straight away with no popup. Otherwise clear a non-empty input; with the input empty and no run, open the background-task menu (v1.3.8): **No**, each running leg and **All** (two or more), then a confirmation before the pick is cancelled |
| `Ctrl+C` | While running, cancel the task outright (the user-cancel path — the pending task is discarded and, since v1.3.9, kept in chat history as `[Canceled]`); otherwise print `ctrl+c again to quit`. A second `Ctrl+C` within 3 seconds quits the TUI |

Single-key toggles fire only when the input is empty, the command picker is closed and no run is active (`Shift+Tab` only checks the last two):

| Key | Action |
|---|---|
| `Shift+Tab` | Toggle auto mode (`safe` ↔ `auto`) |
| `Shift+F` | Toggle fast mode — the mode line shows `[fast]` while enabled |
| `Shift+G` | Toggle `CLAUDE.md` / `AGENTS.md` injection (v1.2.0; off at start). When on and the work directory has one of those files, the mode line shows `[CLAUDE.md]` or `[AGENTS.md]` and the file is added to each turn's context |
| `Shift+U` | Live provider usage / balance for every registered provider that reports one: `codex`, `grok-oauth`, `copilot`, `deepseek`, `openrouter`, `claude-code` (Ollama Cloud: Removed in v1.2.0); the result lands in the notice box. Since v1.1.3 a provider with several quota windows shows each one as `5h/week/total` percentages, colored by its own level |
| `Shift+P` | Open the **Work directory** popup (v1.3.0): an absolute path, `~/...` or a path relative to the current directory; a path that does not exist is refused with `[Not found] work directory`, and the letter case of each segment is corrected to the one on disk |
| `Shift+W` / `Shift+S` | Cycle the session model backward / forward through `auto` and the registered models (not the same as `w` / `s` inside `/model`, which reorder the fallback list) |
| `Shift+A` / `Shift+D` | Cycle the session reasoning level down / up through `auto`, `none`, `low`, `medium`, `high`, `xhigh`, `max` — `auto` included since v1.1.0 |

Shell command mode (`Shift+T`) was removed; since v1.3.0 the `!` prefix runs a command directly instead. The `Shift+M` model list was removed; use `/model`, which lists the registered models.

In list popups, `Enter` confirms the highlighted entry, `d` deletes it and `t` sets its tier where the popup offers those actions. Text-input popups use `Ctrl+S` to confirm, `Enter` for a newline, and `Esc` to cancel.

Since v1.3.3 confirmation, password and `ask_user` popups ignore `Esc`: pick an option instead. A confirmation offers **Yes**, **Yes don't ask again**, **Yes allow this turn**, **No skip this** (with an optional reason for the agent), **Abort keep for resume** and **Cancel delete task**; password prompts (a path outside `$HOME`, `sudo`, `sandbox: false`) drop the two remember options while plain confirmations, including a sensitive path inside `$HOME`, keep them, and a wrong system password keeps the popup open until verification succeeds. A `run_command` / `background_command` confirmation shows the dispatcher model's explanation above a divider and the command. Open popups re-render when the terminal is resized, `ask_user` clips its question and detail to the window height so every option stays visible, and a task that ends while a popup is open no longer leaves the status stuck on running.

The TUI auto-tails the active session's `action.log` (foreign-process writes prefixed with `▌ ` in warn-purple). Single-session view only.

Since v1.1.0 status messages (command results, errors, `Shift+U` output) collect in a framed notice box above the input instead of scrolling into the transcript. Since v1.1.3 plain success confirmations — a saved role, a deleted key, a new session and the like — go to the debug log instead, so the box only holds what needs attention; since v1.3.0 empty-state and progress messages (`no active session`, `nothing scheduled`, `compacting history...` and the like) go there too, and since v1.3.2 so does the `⚠ restricted path approved` notice. It keeps the last 32 lines and shows 4 at a time; `Tab` pages up when there are more, and `Esc` closes it.
