The TUI
Amber's terminal UI is a BitchX/IRC-inspired multi-window interface for interacting with the agent directly from the terminal. It runs on Linux and macOS.
Status Bar
The status bar sits at the bottom of the screen, always visible:
───── amber 0.5.8 ───── Apache 2.0 ───── C++17 ───── utf-8 ───── ncurses ─────
Connection state indicator, version number, and current section. Static but present.
Slash Commands
Type / to open the command drawer. Commands are JSON-driven, no hardcoded completions. The tree structure supports unlimited nesting:
flowchart TB
json["completions.json<br/>the single source of truth"]
schema["node = { help, man, action, children }<br/>the last leaf of a branch carries the action"]
json --> schema
schema --> index["SettingRegistry indexes every node<br/>help · man · children · choices · ranges"]
index --> keyed["namespaces keyed by full display path<br/>get.model is not set.model"]
keyed --> resolve["resolve_key<br/>exact → get.key → set.key"]
resolve --> unknown["unresolved → empty<br/>the caller reports an unknown command"]flowchart TD
line["Enter: /set policy read"] --> strip["strip the leading slash, trim, tokenize"]
strip --> walk["walk the commands tree, consuming every token<br/>that names a documented child"]
walk --> deepest{"any node matched?"}
deepest -->|no| unknown["unknown command (try /help)"]
deepest -->|yes| node["node = deepest documented match<br/>remaining tokens joined as the argument"]
node --> has{"node carries an action?"}
has -->|no| man["print the node man page<br/>documented, not executable"]
has -->|yes| reg{"action registered?"}
reg -->|no| man
reg -->|yes| dispatch["dispatch(action, arg)"]
dispatch --> safe["exceptions caught<br/>command error: ... to the status line"]/set model # switch models /set provider # switch providers /get model list # list available models /get plugin # list plugins and their state /set plugin <id> on # enable a plugin /set policy rule # manage permission rules /get job status # check running jobs
Command Drawer
The drawer shows available commands with short help text. It's not a modal dialog - it's a terminal drawer that slides up from the bottom, like BitchX's command list.
───────────────────────────────────────────────────────────── /set model Switch LLM model /set provider Switch LLM provider /get model list List available models /get plugin List plugins and their state /get job status Check running jobs /set policy rule Manage permission rules ─────────────────────────────────────────────────────────────
Every row above comes from the tree. Runtime values, models, providers, policy rules, jobs, plugins, MCP servers, are merged in as feed leaves, so nothing a user can type is hardcoded in C++:
flowchart TB
tree["completions.json<br/>documented namespaces"]
feeds["feed leaves generated at runtime<br/>model list · policy rules · providers · jobs<br/>plugins · MCP servers · plugin commands"]
tree --> merge
feeds --> merge["merge_completions_json<br/>deep merge: static fields preserved,<br/>children unioned, feeds never clobber docs"]
merge --> actions["each leaf carries a generated action<br/>and the feed registers its closure"]
actions --> surface["drawer · completions · dispatch<br/>one tree, three readers"]Sessions & Jobs
Multiple sessions can run concurrently, each with its own context and provider. Background jobs are tracked and can be inspected or killed from the command tree.
/get job status # check running jobs /get job <id> read # read a job's output /get job <id> kill # kill a job
Plugin Controls
Plugins can be enabled and disabled at runtime. The command tree reflects the current plugin state:
/get plugin # list all plugins and their state /set plugin anthropic on # enable the Anthropic provider /set plugin anthropic off # disable (unwinds cleanly)
Tool Call Visibility
You don't just see what the agent says, you see what it's doing. Tool calls are displayed as they execute, with output capping and timeout enforcement.
[tool] read_file: /home/jack/projects/readme.md → 42 lines read, 1.2KB [tool] search_files: pattern="TODO" in /home/jack/projects/ → 12 matches found [tool] bash: grep -rnI "fixme" /home/jack/projects/ → 3 matches in 2 files
Compression Status
When the compression pipeline runs, you see live progress, not a spinner, actual status updates as the pipeline classifies, extracts, and prunes:
[compress] Classify: 248 messages → core: 12, context: 18, prune: 218 [compress] Extract: 3 memory ops, 2 skill ops [compress] Prune: replaced 218 bulky outputs with placeholders [compress] Headroom: 25% enforced (186/736 tokens) [compress] Done: 248 → 30 messages (87.9% reduction)
Approval Dialogs
The agent asks before running shell commands. Approval dialogs appear as modal prompts with the command text, workspace path, and a yes/no choice:
───────────────────────────────────────────────────────────── Approval required: bash tool Command: rm -rf /home/jack/projects/build Workspace: /home/jack/projects Timeout: 60s [Y]es [N]o [A]lways allow [E]xit ─────────────────────────────────────────────────────────────
Multi-Window Chat
Like BitchX, amber supports multiple chat windows. Each window can connect to a different LLM or run a different agent task. Window switching isAlt+1 through Alt+9, the same muscle memory as the good old days of IRC.
Runtime Telemetry
The status bar is composed from a plugin registry, surfacing runtime state, connection, model, provider, job count, and metrics from the bundled metrics plugin, without hardcoding UI segments.