# CLI

An agentic terminal REPL --- like Claude Code, but connected to **your own API**. Read files, write code, run commands, search your codebase, all from the terminal.

```bash
$ aroom chat
```

```
Anteroom CLI - /path/to/your/project
  Model: gpt-4 | Tools: 6 | Instructions: loaded | Branch: main
  Type /help for commands, Ctrl+D to exit
```

Type a bare `/` at the prompt to open the in-terminal command palette. It ranks the most common slash commands first, labels each suggestion by intent (`Conversation`, `Workspace`, `Inspect`, `Workflow`, `Session`), and inserts an editable command scaffold into the buffer instead of executing immediately.

## Modes

=== "Interactive REPL"

    ```bash
    $ aroom chat                       # Start fresh
    $ aroom chat -c                    # Continue last conversation
    $ aroom chat -r <id>               # Resume specific conversation
    $ aroom chat -p /path/to/project   # Set project root
    $ aroom chat --no-tools            # Disable built-in tools
    ```

=== "One-Shot"

    ```bash
    $ aroom chat "explain main.py"
    $ aroom chat -c "now add rate limiting"
    $ aroom chat -r a1b2c3d4 "fix the failing test"
    ```

    One-shot mode creates a conversation in the database, generates a title, and exits after the response. The AI still has access to all tools and can run multiple agentic iterations.

=== "Exec (Non-Interactive)"

    ```bash
    $ aroom exec "summarize test results"
    $ aroom exec "refactor code" --json
    $ aroom exec "run tests" --timeout 300 --quiet
    $ aroom exec "generate report" --no-tools --no-conversation
    ```

    Exec mode is non-interactive --- no approval prompts, no REPL. Perfect for scripting, CI/CD, and automation. Returns JSON output (`--json`), respects timeout (`--timeout`), and can suppress tool use (`--no-tools`) or conversation persistence (`--no-conversation`). Exit codes: 0 (success), 1 (error), 124 (timeout).

## How It Works

1. You type a prompt at the input prompt
2. A context-aware phase indicator tracks progress: **Connecting...** while establishing the API connection, **Thinking...** while waiting for the first token, **Writing...** while tokens stream in. An elapsed timer appears after 2 seconds, and a cancel hint (`esc to cancel`) appears after 5 seconds
3. When the AI calls tools, the indicator shows what is happening: a humanized summary for single tools (e.g. "Reading src/foo.py...") or a count for parallel execution ("Running 3 tools...")
4. The full response renders as Rich Markdown --- syntax-highlighted code, tables, headers, lists
5. A context footer shows token usage, response size, elapsed time, and remaining headroom

### Streaming rendering

When your terminal is a TTY and `NO_COLOR` is unset, markdown formats **as tokens arrive**, not only at the end of the turn (#1365):

- Bold, italic, and inline code format the moment their closing delimiter streams in
- Headers render with styling as soon as the newline after `##` arrives
- Fenced code blocks show their container (language label) as soon as the opening ``` arrives; code fills in line-by-line
- Lists and tables lay out incrementally and then lock in once the structure closes

The underlying mechanism is `rich.live.Live` re-rendering `Markdown(buffered_text)` into a single live region on a throttled cadence (default 50 ms / `refresh_hz: 20`). When a tool call interrupts mid-stream, the live region is flushed to a static print first so tool output renders cleanly beneath settled prose.

**Fallback paths** — the streaming renderer auto-disables (and the CLI falls back to the legacy "buffer and render at end" path) in these contexts:

- Non-TTY output (piping `aroom` into a file or another command)
- `NO_COLOR` environment variable is set
- `aroom exec` mode (unless you opt in with `cli.streaming.live_in_exec_mode: true` / `AI_CHAT_CLI_STREAMING_LIVE_IN_EXEC_MODE=true`)
- `cli.streaming.enabled: false` explicitly in config

Tuning knobs are documented in [`cli.streaming`](../configuration/config-file.md#clistreaming). Environment variables: see the four `AI_CHAT_CLI_STREAMING_*` rows in the [Environment Variables reference](../configuration/environment-variables.md#reference).

### Live turn status

Every turn flows through one ambient status line. The label evolves through staged phases rather than spawning competing indicators:

1. **Working...** --- immediate acknowledgment the prompt was received (before the API connection opens)
2. **Connecting...** --- establishing the API connection
3. **Thinking... Ns** --- waiting for the first token, elapsed time after 2s
4. **Writing... Ns · 1,247 chars** --- tokens streaming in
5. **Reading src/foo.py... 3s** --- tool execution (single tool) or **Running 3 tools... 5s** (parallel)
6. **Thinking... 7s  retry 2/3** --- retry countdown if a call fails
7. **Thinking... Ns  cancelled** --- on cancel (Esc)

The status line occupies a single slot in the bottom toolbar in footer mode; when prompt_toolkit's toolbar is unavailable it writes an in-place line above the prompt. Either way, one surface --- never two.

### Turn summary

When a turn completes, a single compact line closes the loop:

```
✓ done · 3.2s · 1 tool
```

- Success: `✓ done · 3.2s · 1 tool` (singular for one, plural for many; zero-tool turns omit the count)
- Cancelled: `cancelled · 1.1s`
- Failed: `failed: connection refused · 2.0s`

Switching verbosity to `detailed` appends up to three distinct tool verbs, e.g. `✓ done · 5.0s · 4 tools · read write bash`.

### Tool Call Lifecycle

Each tool call renders as a two-phase surface (#1364):

1. **Running phase** — the ambient thinking/footer ticker carries the active tool label (`Reading src/foo.py...`, `Running 3 tools...` for parallel execution). No separate breadcrumb is printed to scrollback.
2. **Completion phase** — a single compact, theme-aware line in the tool lane:

    ```
    │ ✓ Read src/foo.py  ·  42 lines  0.5s
    │ ✓ Ran pytest -q  ·  exit 0  3.2s
    │ ✗ Ran ls /nope  1.2s
        No such file or directory
    ```

    Components: gutter glyph (tool lane), status icon (`✓`/`✗`, success/error color), past-tense verb + target, optional metric suffix (muted, between target and elapsed), elapsed time (muted, suppressed under 100 ms). Failures append a one-line muted error summary beneath the completion line.

VERBOSE verbosity adds a dim `args: {...}` footline under each completion line so the exact tool arguments are still visible. Set `cli.live_tools.show_args_in_verbose: false` to suppress. File-modifying tools (`edit_file`, `write_file`) still emit the inline diff surface instead of the compact completion line.

Tuning knobs are documented in [`cli.live_tools`](../configuration/config-file.md#clilive_tools).

## Agentic Loop

The AI runs in an agentic loop: it can call tools, inspect results, call more tools, and continue reasoning --- up to 50 iterations per turn. Multiple tool calls in a single response execute in parallel.

## Prompt Queuing

Type and submit messages while the AI is working. They queue (up to 10) and process in FIFO order. The prompt stays active at the bottom of the terminal while output streams above it.

### Queue Feedback

When you submit a message while the AI is busy, the CLI shows:

```
Message queued [1/1]: your message preview here...
```

The format is `[position/total]` followed by the first 80 characters of the message. When a queued message starts processing, a gold separator line shows the message content (up to 200 characters with ellipsis if truncated).

If the queue is full, you see: `Queue full --- wait for current work to finish`.

## Shell Escapes

Use `!` at the start of a REPL entry to run a local shell command without sending it to the AI:

```bash
!git status
! ls -la
```

Bang commands are CLI-only, skip the normal approval gate because the user invoked them explicitly, still respect bash hard-block and `safety.bash` sandbox restrictions, and print command output directly in the terminal instead of adding it to conversation context.

## Cross-Platform

Works on macOS, Linux, and Windows:

- Signal handling uses `asyncio.add_signal_handler` on Unix and falls back gracefully on Windows
- Path resolution uses `os.path.realpath` for consistent behavior
- The prompt toolkit input handles platform-specific terminal differences

## Features

| Feature | Page |
|---|---|
| Built-in tools | [Tools](tools.md) |
| Reusable prompt templates | [Skills](skills.md) |
| Inline file contents | [File References](file-references.md) |
| Token tracking & compact | [Context Management](context-management.md) |
| All /commands (chat mode) | [Commands](commands.md) |
| Project instructions (ANTEROOM.md / CLAUDE.md / AGENTS.md) | [Project Instructions](project-instructions.md) |
| Color themes | Config: `cli.theme` (midnight/dawn/high-contrast/accessible) |
| Config history & restore | `aroom config history` / `diff` / `restore` — see [Config History](../configuration/config-file.md#config-history) |

## Exec Mode

For non-interactive automation and scripting, use `aroom exec` instead of `aroom chat`:

```bash
aroom exec "task description"       # Execute a one-off task
aroom exec "task" --json            # JSON output for parsing
aroom exec "task" --timeout 60      # Set wall-clock timeout
aroom exec "task" --quiet           # Suppress stderr progress
aroom exec "task" --verbose         # Show full tool details
aroom exec "task" --no-tools        # Disable tool use
aroom exec "task" --no-conversation # Skip database persistence
```

See [Commands](commands.md) for CLI flags that work in both modes (`--approval-mode`, `--allowed-tools`, `--model`).

## Startup Behavior

Anteroom defers heavy initialization to minimize time-to-prompt:

- **Connection validation** is deferred until the first AI message. If the provider is unreachable, the error appears when you send your first message. To validate eagerly, use `aroom --test`.
- **Vector search index** initializes in a background task after the prompt appears. It completes in 10--50ms and is ready before you can type a command. In the unlikely case a command arrives before initialization finishes, there is a small one-time wait.
- **MCP server connections** are established in the background after the prompt appears. Tools become available within 1--2 seconds.
- **Update checks** run fully in the background and display results when available (never blocks the prompt).

## Server Management

Run the web UI in the background without keeping a terminal open:

```bash
aroom start          # start in background, opens browser
aroom status         # check if the server is running
aroom stop           # stop the background server
```

Works on macOS, Linux, and Windows. PID files support multiple instances on different ports (`aroom start --port 9090`). See [Commands](commands.md#server-management) for details.
