agenterm 0.5.0
Terminal-native agent runtime with persistent sessions, branching, and MCP
Requires Python: >=3.12
Keywords: agents, ai, cli, llm, mcp, openai, terminal

# agenterm

**Terminal-native agent runtime** built on the OpenAI Agents SDK and MCP.

Persistent sessions. Branching conversations. Multi-provider. Local-first.

## Installation

```bash
# Recommended: isolated install (like pipx, but faster)
uv tool install agenterm

# Or try without installing
uvx agenterm --help

# Or traditional pip
pip install agenterm
```

After installation, run:

```bash
agenterm --version    # verify installation
agenterm repl         # start interactive session
```

## Required CLI tools (local)

agenterm’s local toolset wraps external CLI binaries. If any are missing, the CLI
fails fast with an install hint.

```bash
brew install ripgrep fd bat tree
```

`stat` is provided by the OS (BSD/GNU); ensure it is available on `PATH`.

On non‑macOS platforms, install the same binaries via your system package
manager and ensure they are on `PATH`.

## Overview

agenterm runs inside any project directory and provides:

- `agenterm repl` — start an interactive REPL session (prompts to save config if missing).
- `agenterm run` — execute a one‑shot run (prompt args, `--file`, or piped stdin).
- `agenterm inspect` — inspect background responses (`response`), local runs (`run`), run event ledgers (`run-events`), SDK turns (`turn`), or agent_run reports (`agent-run`).
- `agenterm config` — create and view effective configuration (`save`, `show`, `path`).
- `agenterm agents` — view/manage agents (instruction files) (`list`, `show`, `path`, `save`).
- `agenterm mcp` — diagnostics, inspection, and MCP server exposure.
- `agenterm artifacts` — browse durable artifacts produced by the agent.
- `agenterm session` — introspection and management of local Agents sessions.
- `agenterm branch` — manage session branches (list/use/new/fork/delete/runs).

The engine is a single‑path pipeline:

> CLI / REPL → AppConfig + SessionState → Agents engine (Responses + tools + MCP) → output

For product vision and target architecture, see `VISION.md` and `ARCH.md`.
This README focuses on how to **use** the CLI.

## Development Setup

For contributing or running from source:

1. Install dependencies:

   ```bash
   uv sync
   ```

2. Initialize configuration (first-time setup):

   Option A (recommended): start the REPL and save a config when prompted.

   ```bash
   uv run agenterm repl
   ```

   Option B (non-interactive): write a baseline config explicitly.

   ```bash
   uv run agenterm config save --scope global
   ```

   Use `--force` to overwrite an existing `~/.agenterm/config.yaml`.

   Optional: create a per-project override:

   ```bash
   uv run agenterm config save --scope local
   ```

   Optional: write baseline agent files:

   ```bash
   uv run agenterm agents save --scope global
   ```

3. Run the CLI:

   ```bash
   uv run agenterm --help
   ```

4. Ensure credentials are available:

   - For `openai/...` models: set `OPENAI_API_KEY` in your shell environment, or
     run `agenterm repl` and use `/config key <KEY>` to save it to `~/.agenterm/.env`.
   - For `gateway/...` models: set the env vars referenced by
     `providers.gateway.routes.*.api_key_env` (local backends like built-in
     `gateway/ollama/*` may omit keys).

The runtime dependencies (Agents SDK, OpenAI client, MCP types) live in `.venv` and are treated as the runtime source of truth for types and behavior.

## Core commands

### Flags and output format

agenterm uses **command-scoped flags**. Put flags after the subcommand name:

```bash
uv run agenterm run --model openai/gpt-5.2-pro --config path/to/config.yaml "..."
```

Common flags:

- `--config PATH` (`-c`) — select a config file (commands that load config).
- `--format human|json` (`-o`) — select output format per command (`--format json` emits a single JSON envelope).
- Human output uses Rich panels/tables; use JSON output for machine parsing.
- `--model ID` (`-m`) — override the configured model (`openai/<model>` or `gateway/<route>/<model>`).
- `--agent NAME` — override the configured agent name (commands that resolve agent files, like `run`, `repl`, and `agents show/path`).
- `--quiet` (`-q`) — suppress informational notices.
- `--verbose` (`-v`) — show verbose error details.
- `--version` (`-V`) — show the CLI version and exit.

### One‑shot runs (`agenterm run "..."`)

Basic usage:

```bash
uv run agenterm run "describe this repo"
```

#### Streaming behavior

Foreground runs always stream internally. By default (quiet), the CLI prints only the final answer and footer. With `--live`, the CLI prints tool calls/outputs and reasoning labels as they arrive. Background runs are the only non‑streaming mode.

#### Non‑interactive by design

`agenterm run` never prompts. Approvals are auto‑resolved and short config/agent source notes are emitted to stderr. Use the REPL for interactive approvals or config/agent save prompts.

#### Input sources

Input can come from:

- Positional prompt arguments,
- `--file FILE` (`-f`),
- `stdin` — used only when no other source is provided.

#### Rendering and output modes

Foreground runs support two orthogonal toggles:

- **Quiet (default)** — do not pass `--live`:
  - Suppresses mid‑stream labels; shows only the final answer and a run summary panel
    (attachments count, tools, usage, response/session IDs).
- **Live (`--live`)**:
  - Streams `[reasoning]`, `[tool call]`, `[tool output]` as they arrive and renders the final answer with Markdown.
- **JSON output (`--format json`)**:
  - Use `agenterm <command> --format json …` to force machine‑readable JSON output for that command.
  - Emits a single JSON envelope to stdout and suppresses human formatting. The envelope is shared across CLI surfaces and has the shape `{schema_version, trace_id, ts, result:{resource, payload}}` (see `ARCH.md`).
  - Suppresses streaming accessories even when `--live` is set (JSON mode emits exactly one document).

Defaults for `--live` / JSON output come from `run.live` and `run.json_output` in `config.yaml` (`--format` overrides per invocation).

#### Cancelled runs (automatic resume)

When a run is cancelled mid‑turn, agenterm records in‑flight turn items and
automatically prepends them to the next run input.

Properties:

- Durable: cancelled-attempt items are replayed until a later run completes a turn
  (so repeated cancellations/timeouts do not drop them).
- No tool replay: tool calls are not re‑executed; recorded tool outputs (including
  rejections/denials) are reused as‑is.
- Tool-args stall recovery: if streamed tool-call arguments stall (e.g., endless
  whitespace deltas), agenterm cancels the stuck stream, records a synthetic tool
  output describing the stall (tool not executed), and resumes from that coherent
  state on the next run.

REPL shortcut:

- `/continue` starts a new run with **no new user message** and relies on the automatic
  resume mechanism (use `/again` to re-send the full previous prompt).

#### Attaching files and URLs

Attach local files or URLs to a `run` invocation:

```bash
uv run agenterm run \
  --attach path/to/file.py \
  --attach https://example.com/spec.pdf \
  "summarize these"
```

#### OpenRouter + Gemini 3 (Responses API proof)

agenterm supports OpenRouter via an **OpenAI-compatible Responses API** gateway route.
This proof run demonstrates:

- Gemini 3 model execution on OpenRouter,
- a **required tool call** (forced via model tool choice + selecting a single tool), and
- an **image attachment** passed as structured Responses input (`input_image`) via an inline data URL.

1) Configure credentials:

```bash
export OPENROUTER_API_KEY="..."   # required
```

2) Run the proof config (ships with this repo):

```bash
uv run agenterm run \
  --config examples/config/openrouter_gemini3_proof.yaml \
  --tool fn:info \
  --attach examples/assets/expression.jpeg \
  "Describe the image, then call the info tool."
```

Notes:

- `--tool fn:info` restricts the tool surface to a single safe local tool.
  Combined with `model.tool_choice: required` in the example config, the model must
  emit at least one tool call.
- The example config enables inline data URLs (`attachments.allow_inline_data_url: true`),
  so local images are sent to the provider as `data:<mime>;base64,...` in `input_image.image_url`.
  Disable this policy if you only want to attach public URLs (no local file ingestion).

#### Ollama local route (OpenAI-compatible Responses)

agenterm ships a built-in `ollama` gateway route:

- Route id: `gateway/ollama/<model>`
- Base URL: `http://localhost:11434/v1`
- Key env: none by default (`api_key_env: null`)
- Model validation: `allow_any_model: true` (local model ids vary by machine)

Quick start:

```bash
# Start Ollama and ensure a model is available.
ollama serve
ollama pull gpt-oss:20b

# Run through the built-in route.
uv run agenterm run --model gateway/ollama/gpt-oss:20b "summarize this repository"
```

Notes:

- `OPENAI_API_KEY` is not required for `gateway/ollama/*` runs.
- Background mode is disabled on the built-in Ollama route because provider-side
  response retrieval is not available on that route.

#### Tools and bundles

Enable tools (file search, web_search (`web.run`), local tools `parallel`/`info`/`rg`/`fd`/`bat`/`tree`/`stat`,
`agent_run`, `agent_run_report`, `apply_patch`, `plan`, `image_generation`, and `shell` on macOS)
as follows:

- Configure tool families, bundles, and policies in `config.yaml` (see “Configuration”).
- Use `tools.bundles` and `tools.default_bundles` in `config.yaml` to control which tools and MCP servers are active.
- For one‑shot runs, override selection per invocation with:
  - `--tools-bundle NAME` (repeatable) to select bundle names.
  - `--tool KEY` (repeatable) to select individual tool keys.
  - Passing either flag overrides default bundles; selection becomes **only** the
    specified bundles/keys (tools are still disabled by `--no-tools`).
- Cap or extend agent loops via `agent.max_turns` (SDK turns per run, 1–500) in `config.yaml`.
  - When the limit is exceeded, the run stops with `MaxTurnsExceeded`; completed SDK turns remain in session history.
    Start a new run or raise `agent.max_turns` to continue.

#### Dangerous tools

Dangerous is a **tool label** used for gating (not a tool family). Defaults are
policy-driven but can be overridden in config.

Default dangerous refs:

- `fn:shell`, `fn:apply_patch`, `fn:user:*`, `mcp:*`
- Hosted MCP connectors: `hosted:mcp:*`
- `plan`, `agent_run_report`, safe read tools (`parallel`, `info`, `rg`, `fd`, `bat`, `tree`, `stat`),
  and `agent_run` are **safe by default** (no side effects).

Overrides (config):

- `tools.dangerous.add`: force‑mark tool refs as dangerous.
- `tools.dangerous.remove`: force‑mark tool refs as safe.
  - Example: mark `web_search` (`web.run`) dangerous or mark `apply_patch` safe.

Tool ref syntax:

- explicit tool keys (e.g., `hosted:openai:web_search` for `web_search`/`web.run`, `fn:shell`, `mcp:files`)
- built-in names (`file_search`, `web_search` (`web.run`), `image_generation`, `parallel`, `shell`, `apply_patch`,
  `plan`, `agent_run_report`, `steward`, `rg`, `fd`, `bat`, `tree`, `stat`, `agent_run`)
- `fn:user:<name>` or `fn:user:*`
- `hosted:mcp:<name>` or `hosted:mcp:*`
- `mcp:<server_key>` or `mcp:*`

Behavior:

- One-shot run:
  - Without `--allow-dangerous`, dangerous tools are dropped from selection.
  - Approvals are always auto‑resolved; `agenterm run` never prompts. Use the REPL for interactive approvals.
- REPL:
  - Allows dangerous tools; approvals default to `prompt` mode (manual) and are handled via a modal approvals overlay.
  - Passing `--approvals auto` starts the session in `auto` mode.

agenterm does **not** attempt to classify arbitrary shell strings as “read-only”.

Platform notes:

- `fn:shell` is **macOS-only** (Seatbelt via `sandbox-exec`).
- `fn:apply_patch` is **cross-platform**, but is confined to the workspace root and always goes through approvals.

#### Structured outputs

You can drive structured JSON outputs via a JSON/YAML schema configured in `config.yaml`:

```bash
uv run agenterm config save --scope local
${EDITOR:-vi} .agenterm/config.yaml
uv run agenterm run "answer using this schema"
```

Set `model.text_format_file` in your config to point at a schema file (for example `examples/structured/answer_schema.yaml`). This loads a JSON/YAML schema into `model.text_format` and installs a structured output schema so the model emits responses that follow your JSON schema.

Structured output schemas are enforced in strict mode: object schemas are normalized to include
`additionalProperties: false`, and invalid schemas fail fast before any request is sent.

#### Tracing

Consolidated trace flag:

- `--trace on|off` — enable/disable tracing for this invocation
- `--trace ID:GROUP:key=val,...` — all-in-one trace configuration (implicitly enables tracing)

These map into the following fields in `AppConfig.run`:

- `run.trace_enabled`
- `run.trace_id`
- `run.group_id`
- `run.trace_metadata`

They are forwarded to the Agents `RunConfig` so your observability backend can correlate CLI runs and REPL sessions. The REPL `/status` command surfaces the active tracing configuration.

Quick lookup (non-REPL):

- `agenterm trace show` — display effective trace configuration (`--format json` for scripts).

## Background runs & inspection

### Background runs

Use `--background` to submit a server‑side (non‑streaming) run:

```bash
uv run agenterm run --no-tools --background "run this in the background"
```

Behavior:

- The `run` command prints only a `response_id` for background submissions:

  ```text
  response_id: resp_...
  ```

- Background mode is accepted only for:
  - `openai/<model>`, and
  - `gateway/<route>/<model>` where the route is configured with
    `protocol: openai_responses` and `supports_background: true`.
- Built-in route defaults:
  - `gateway/openrouter/*`: background enabled (`supports_background: true`)
  - `gateway/ollama/*`: background disabled (`supports_background: false`)

- Background runs only attach **hosted-plane** tools (`hosted:*`).
  - Gateway routes do not expose hosted tools, so gateway background runs execute
    without tool attachments.

- All client-plane tools (`fn:*`, `mcp:*`, `fn:user:*`) are stripped automatically in background mode (background runs cannot reach your local machine), including local MCP servers.

- Hosted MCP connectors can be used in background mode by selecting:
  - `hosted:mcp:<name>` (from `mcp.connectors[*].name`),
  - and passing `--allow-dangerous` when the connector is marked dangerous
    (default: hosted MCP connectors are dangerous; overrideable via `tools.dangerous.remove`).

### Inspecting background results

Use `agenterm inspect response` to inspect a previously submitted background response:

```bash
uv run agenterm inspect response RESPONSE_ID
```

Scope:

- `inspect response` is OpenAI-credentialed (`OPENAI_API_KEY`) and does not
  retrieve gateway route response IDs.

This fetches a single Responses object by id and prints:

- `response_id`
- Model id (including concrete version)
- `background: true` when the run was submitted with `--background`
- Status (for example, `completed`, `failed`)
- Usage summary (`in=… out=… total=… tokens`)
- A best‑effort `output:` block with aggregated text output

This path is strictly **read‑only**:

- It does not mutate Agents sessions or local session history (SDK turns).
- It exists solely to make `--background` runs easy to inspect without leaving the CLI.

### Inspecting local runs, run events, and SDK turns

Local inspection reads the SQLite store and does not require provider access:

```bash
uv run agenterm inspect run SESSION_ID 3
uv run agenterm inspect run-events SESSION_ID 3
uv run agenterm inspect turn SESSION_ID 7
```

To inspect delegated `agent_run` reports (stored as artifacts):

```bash
uv run agenterm inspect agent-run REPORT_ID
```

## Sessions for one-shot runs

Every one-shot `agenterm run` invocation uses a local SQLite-backed session (`AgentermSQLiteSession`, an agenterm-owned wrapper around Agents `AdvancedSQLiteSession`) so transcripts and usage are persisted in a shared SQLite store.

- By default, each run creates a fresh session with a UUID `session_id`.

- To reuse a session across multiple runs and continue from local session history (SDK turns), pass:

  ```bash
  uv run agenterm run --session <UUID> "continue this agent in the same session"
  ```

- `--session <UUID>` is **resume-or-fail**: if the session does not exist locally, `agenterm` exits with an error. Use `agenterm session list` to discover valid ids.

- To target a specific branch within a session, use `--branch <BRANCH_ID>` (defaults to the session head branch):

  ```bash
  uv run agenterm run --session <UUID> --branch main "continue on a branch"
  ```

  To override the server-side store per run (without editing config), use
  `--store/--no-store`:

  ```bash
  uv run agenterm run --store "enable server-side store for this run"
  ```

  Default is `model.store: false` (provider store off). Set `model.store: true` to
  enable server-side persistence by default.

### Inspecting stored sessions

Use the session subcommands to inspect stored transcripts and usage:

- `agenterm session list` — list sessions in the local store (compact table with single-line last-message previews).
- `agenterm session show <ID>` — print metadata; includes `usage_total` when the per-request ledger is present.
- `agenterm session runs <ID> [--branch <BRANCH_ID>]` — show run history for a branch; tokens include cached/reasoning totals when available.
- `agenterm branch list <SESSION_ID>` — list branches for a session.

## Interactive REPL (`agenterm repl`)

Start the REPL:

```bash
uv run agenterm repl
```

Input defaults:
- Enter sends the prompt.
- Ctrl+J inserts a newline (Shift+Enter is not distinct in macOS iTerm2 without remapping).
- Ctrl+C clears the current input line.
- Pasting multi-line text does not auto-send; press Enter to submit.

### Key slash commands

**Core commands:**
- `/help [topic]` — tiered help; shows overview or per-command details.
- `/status` — session snapshot (model, tools, config, IDs).
- `/errors` — show captured stderr/logging lines from the REPL error buffer.
- `/last diff [preview|full]` — show the most recent apply_patch diff (preview is line‑bounded; `full` is unbounded).
- `/last tools [preview|full]` — show the most recent tool call/output (bounded preview by default; `full` is explicit).
- `/last approvals [preview|full]` — show the most recent approvals (pending + resolved; includes rejection reasons).
- `/trace [show|clear|on|off]` — tracing controls for this session.
- `/quit` — exit REPL (also Ctrl+D).
  - On exit, agenterm prints a resume command with the current session id.

**Model and tools:**
- `/model` — route-first model picker (modal).
  - Step 1: pick route (`openai`, `openrouter`, `ollama`).
  - Step 2: pick model from route recommendations (`model_suggestions`) plus discovered route catalog entries.
  - `/model <route>` — open the picker directly for one route (`openai|openrouter|ollama`).
  - `/model <ID>` — set model directly (`openai/<model>` or `gateway/<route>/<model>`).
  - Model IDs validate against provider registries implied by the prefix (OpenAI catalog or gateway route policy).
  - Convenience: `/model gpt-5.2` is treated as `openai/gpt-5.2` in the REPL.
- `/tools [sub]` — view and adjust tool bundles and individual tools.
- `/approvals [sub]` — manage tool approvals (mode: `prompt|auto`; supports `list|show|approve|reject`).

**Settings (consolidated under `/config`):**
- `/config key <KEY>` — set API key for this session.
- `/config verbosity [low|medium|high|unset]` — adjust output detail.
- `/config reasoning [effort|summary] <VALUE>` — adjust reasoning effort/summary.

**REPL UI controls (`/repl`):**
- `/repl theme dark|light` — select the REPL prompt theme.
  - Dark/light themes use warm amber CRT‑inspired theme tokens for prompt UI and CLI accents.
- `/repl color-depth auto|mono|ansi|default|truecolor` — set prompt-toolkit color depth (default `auto`, which picks the highest supported depth; truecolor on macOS Terminal/iTerm2).
- `/repl mouse on|off` — enable/disable mouse support in the prompt UI (default on).
- `/repl completion off|commands|full` — toggle completion (slash commands only, or slash + history suggestions).
- `/repl edit-mode emacs|vi` — set editing mode (vi default, emacs optional).

**UX toggles (`/ux`):**
- `/ux markdown on|off` — toggle styled Markdown rendering for agent output.
- `/ux reasoning off|summary` — show/hide reasoning summaries (summary-only; no chain-of-thought dumps).
- `/ux diffs off|summary` — show/hide apply_patch diff artifacts in the transcript.
- `/ux stream final|live` — choose final-only vs live text streaming (Markdown renders only in final mode).
- `/ux verbosity quiet|normal|debug` — control detail level (labels-only → bounded details → raw event types).

**Session management (consolidated under `/session`):**
- `/session new` — start a fresh REPL conversation.
- `/session list` — list known sessions in the local SQLite store (compact table with single-line last-message previews).
- `/session use <ID>` — attach to an existing stored session.
- `/session runs [N]` — show recent runs for the current session.
  - Attaching to a session replaces the in-memory transcript with the stored branch history.

**Branch management (consolidated under `/branch`):**
- `/branch list` — list branches for the current session.
- `/branch use <BRANCH_ID>` — switch to a branch.
- `/branch new [BRANCH_ID]` — create a new branch from head and switch to it.
- `/branch fork <RUN_NUMBER> [BRANCH_ID]` — create a branch from a run (exclusive) and switch to it.
- `/branch delete <BRANCH_ID> [--force|-f|force]` — delete a branch (never `main`; deleting current branch requires force).
- `/branch runs [N]` — show recent runs for the active branch.
  - Switching branches replaces the in-memory transcript with the selected branch history.

**Context and control:**
- `/attach <PATH|URL>` — stage files/URLs for the next run (e.g., `/attach README.md`).
- `/attach list` — show staged and last-used attachments.
- `/attach remove <PATH|URL>|all` — unstage attachments for the next run (does not reset conversation).
- `/attach clear` — clear staged attachments and cancel any pending “use last attachments” state.
- `/agent` — show the current agent.
- `/agent list` — list available agents.
- `/agent <NAME>` — switch agent and branch from head (e.g., `/agent default`).
- `/compress` — run compression and switch to the compression continuation (snapshot/compaction, provider‑dependent); tracked as a run in the session ledger.
- `/compress show` — print the latest compression continuation (snapshot/compaction), grouped by content/citation type; UI-only output with binary payloads redacted.
- `/mcp refresh|status` — refresh MCP servers or show status/tool counts.
- `/again` — re-run the last prompt; forks from the last run when it has turns, otherwise retries in place (requires a stored session).
- `/continue` — continue after cancellation/timeout without resending the full previous prompt (uses automatic resume).
- `/edit` — edit the last prompt; forks from the last run when it has turns, otherwise edits in place (requires a stored session).
- ESC/Ctrl+C — cancel the current run or compression immediately (in‑flight items are captured and automatically reused).
  - If cancellation stalls, the REPL escalates to a hard cancel and persists the cancelled run; the next run resumes with the captured items.

### REPL UX and state

- The REPL is full‑screen and scrollable:
  - Transcript output renders in a dedicated scrollable window with internal scrollback.
  - Slash‑command outputs render as transcript blocks with consistent spacing.
- The layout is stable:
  - Transcript (scrollable) → adaptive completion panel → spacer → composer → spacer → status bar.
- The transcript uses mouse-wheel scrolling without a visible scrollbar.
- Stream mode is explicit: `/ux stream final|live`. Live mode streams plain text deltas (no panels); final mode renders the completed answer (Markdown when enabled).
- The REPL uses the same `AppConfig` / Agents engine as `run`.
- If a run fails before a response id is recorded, the REPL discards staged items and continues with local session history replay on the next prompt.
- If you cancel a run, agenterm records the cancelled attempt; the next run resumes with the captured items on top of local session history.
  - It adds interactive state and approvals on top.
- Approvals appear as a modal overlay with approve/reject actions; decisions still emit transcript blocks.
- The status bar highlights `AUTO` in bold danger red when approvals mode is automatic.
- The prompt chevron is `>`. Approval posture is shown in the HUD/placeholder notice.
- The HUD/placeholder surfaces short notices (approval pending, run running).
- The bottom toolbar is a minimal status line:
  - `agent: <name>[model] | effort: <value> | tools: <bundle> | context: <percent>%` where `<percent>` uses provider-reported
    input tokens for the **last provider request** of the last completed run, normalized by `model.context_window` when configured;
    when `model.context_window` is null, the toolbar shows the raw token count (packing uses a 128k token fallback internally).
  - `AUTO` appears when approvals mode is auto (right-aligned when width permits, otherwise appended).
  - For per-run and cumulative totals, use `agenterm session runs --branch …` / `agenterm session show <SESSION_ID>` (token ledger).
  This is informational and does not change model behavior.

### Tool approvals in the REPL

Tool approvals in the REPL are non‑blocking:

- When a `shell` or `apply_patch` tool call requires approval, the model run runs as a background task while the UI stays responsive.
- When an approval is requested, the REPL opens a modal approval overlay and emits a bounded `[approval requested]` transcript block.
  - `[approved]` / `[rejected]` blocks appear when the decision resolves.
- While a run is running:
  - Press `y`/`n` in the modal to approve/reject the next pending tool call.
  - Press `n` and supply a reason to reject with a user-provided reason (forwarded to the model).
  - Use `/approvals list` and `/approvals show <ID>` to inspect details on demand.
  - Use `/last approvals` to inspect the most recent approval requests and decisions (bounded; includes rejection reasons).
  - Use `/approvals auto` to approve everything pending and continue without prompts.
  - Use `/approvals prompt` to return to manual approvals.
  - Normal prompts and most commands are rejected with a short message instead of hanging.
- Auto‑approval is supported and shared with `run`:
  - `/approvals auto` enables auto‑approval for the session.
  - `repl.approvals.mode: auto` in config starts REPL sessions in auto‑approval mode.

## Attachments

- Attach local files or URLs with `--attach PATH|URL` (repeatable).
- Prompts can come from:
  - Positional args,
  - `--file FILE`,
  - `stdin` (when no other source is provided).

Under the hood, agenterm maps prompts and attachments into Responses input items
based on provider capabilities (file_id, image_url, file_url).

Attachment mapping:

- Text files map to `input_text` (inline text).
- Image files are uploaded when file IDs are supported; otherwise they require an explicit `http(s)` URL
  (or inline data URLs when explicitly allowed).
- PDF files are uploaded when file IDs are supported; otherwise they require an explicit `http(s)` URL
  (or inline data URLs when explicitly allowed).
- `http(s)` URLs map to `input_image.image_url` for images or `input_file.file_url` for other files.
- Gateway (LiteLLM) lanes convert Responses inputs to Chat Completions, so they only accept
  `input_image.image_url` and `input_file.file_data` (file IDs/URLs are rejected).
- Inline data URLs are disabled by default and must be explicitly enabled via `attachments.*`.

Example assets in `examples/assets/`:

- `examples/assets/agents_guide.pdf` — long-form document for testing file search/attachments.
- `examples/assets/expression.jpeg` — math expression image for vision tests
  (prompt: "simplify this expression").

## Examples

Examples are runnable demos and test assets. Canonical behavior and contracts live
in `README.md` and `ARCH.md`. Reference-only material lives in `docs/ref/`.
See `docs/ref/README.md` for the reference index.

See `examples/README.md` for the full examples index.
Reference input-item example: `docs/ref/response-input-example.yaml`.

## Configuration (AppConfig)

agenterm reads a single `config.yaml` into an `AppConfig` (see `ARCH.md`). Discovery order:

   1. `--config PATH` (explicit).
   2. `.agenterm/config.yaml` (project-local override; when present).
   3. `~/.agenterm/config.yaml` (global baseline; Linux and macOS only).

   Use `agenterm config save --scope global` to create the global baseline config,
   `agenterm config save --scope local` to create a per-project override, or
   `agenterm config path` to see the active config location.

   If no config file exists yet, agenterm runs with a fully-typed built-in default
   `AppConfig`. The REPL offers a one-time prompt to save a config, while
   `agenterm run` stays non-interactive and prints a short config-source note on stderr.
   In greenfield mode, any config/agent file validation error is fatal; the CLI
   instructs you to delete the local/global `.agenterm/` directories and retry.

### Agents (instruction files)

The **agent name** is the filename (without extension) for the instruction
file. There is no separate display name — the agent name is used everywhere.

agenterm resolves the active agent from the highest‑priority source available.
Local agent files override global ones, and REPL `/agent` overrides everything
for the active session.

On `agenterm agents save`, bundled agents are copied to:
```
~/.agenterm/agents/        # global defaults
./.agenterm/agents/        # project-local overrides
```

Local saves prefer copying global agents when they exist.

`agenterm agents show` prints the full effective agent file:
- Human output renders Markdown by default.
- Use `--plain` for raw text.
- Use `--format json` for a single JSON envelope.

Use `agenterm agents path` to report the effective source + path.

Starter instruction templates live in `docs/ref/agent-instruction-templates.md`
(reference-only); adapt them to your repo constraints.

**Resolution order:**
1. `--agent NAME` (CLI explicit override)
2. `./.agenterm/agents/<name>.md` project-local override (when present)
3. `~/.agenterm/agents/<name>.md` user default (if it exists and is readable)
4. Bundled `src/agenterm/data/agents/<name>.md` shipped with the package

In the REPL, `/agent <NAME>` switches agents and creates a new branch from
head (unless there is no session history yet, in which case the current branch metadata
is updated in place); this live override is the highest priority within that
session.

The default `default` agent is a generalist companion tuned for local,
tool-using work. The bundled `coding_agent` agent establishes:
- Quality-first principles
- Tool discipline (when to use shell vs apply_patch)
- File editing conventions
- Error handling and escalation patterns

Edit `~/.agenterm/agents/<name>.md` to customize agent behavior globally, or
`./.agenterm/agents/<name>.md` to customize it per-project.

### Additional notes

- The canonical, complete, commented starter template is generated from the live `AppConfig` schema (see `agenterm config save`), so it always stays in sync with the code.
- Runtime configuration lives in `config.yaml`, while agent files live in `.agenterm/agents/` (local/global overrides):
  - Agent/model defaults
  - Tools
  - MCP servers
  - Retries (provider/MCP/store retry policies)
  - Guardrails
  - Tool bundles
  - Shell policy
- CLI flags are per‑run overrides layered on top of this config.

### Retries (provider/MCP/store)

Retries are configured centrally in `retries` within `config.yaml`. SDK‑internal retries are
disabled; agenterm’s own retry policy is the single source of truth. Use:

- `retries.provider` for model calls (streamed/background/agent_run).
- `retries.mcp` for MCP `list_tools` / `call_tool` retries.
- `retries.store` for SQLite `SQLITE_BUSY` backoff.

### Local continuity (always)

- Agenterm CLI always replays local session history (SDK turns) for each run (bounded by packing).
- Provider-managed conversation state is never used for continuity.
- Store (`model.store`) controls **provider persistence only**:
  - Default is off (`model.store: false`).
  - Override per invocation with `--store` or `--no-store`.
  - Enables background inspection and response retrieval where the provider
    route supports it.
- `last_response_id` is stored per branch only when provider storage is enabled
  (for inspection identifiers, not for continuity).

Session history (SDK turns) and usage are persisted locally via the Agents session store:

- Agenterm CLI creates an `AgentermSQLiteSession` (an agenterm-owned wrapper around Agents `AdvancedSQLiteSession`) backed by the history DB at `~/.agenterm/<version>/history.sqlite3`.
- Both `run` and `repl` keep full transcripts without requiring additional configuration files.
- agenterm records per‑branch per‑run status in the meta DB at `~/.agenterm/<version>/store.sqlite3` to support post‑mortem debugging.

### Artifacts vault (generated images)

Some model/tool outputs are too large to store directly in session history (SDK turns) (base64 image payloads). agenterm treats these as **durable artifacts**:

- Location (single per-user root):
  - History DB: `~/.agenterm/<version>/history.sqlite3`
  - Meta store DB: `~/.agenterm/<version>/store.sqlite3`
  - Artifacts root: `~/.agenterm/artifacts/`
  - Images: `~/.agenterm/artifacts/images/<artifact_id>.<ext>`
- Storage model:
  - Artifact bytes live on disk.
  - The DB stores stable references (artifact id + path + metadata).
  - No deduplication/content hashing is performed (artifact ids are UUIDs).
  - Session history stores `image_generation_call.result: null`; rehydration is UI‑only and never re‑injects base64 into model input.
  - UX surfacing:
  - REPL: iTerm2 inline previews bounded by the configured max width/height, plus durable paths in the transcript.
    - Commands: `/artifacts list [N]`, `/artifacts show <ID>`, `/artifacts open <ID>`, `/artifacts agent-run <ID>`,
      `/inspect agent-run <ID> [--json]`
    - Inline previews are only shown in iTerm2; other terminals show the path only.
    - Previews preserve aspect ratio and fit within the configured bounds.
  - CLI: `agenterm artifacts list|show|open|agent-run`
    - `agenterm artifacts list` supports `--session-id` and `--trace-id` filters.
  - One-shot runs: when stdout is a TTY, `agenterm run ...` prints image artifact cards even in quiet mode.
  - JSON mode: `agenterm run --format json ...` includes `result.payload.artifacts` so scripts can capture paths deterministically.
- Retention:
  - agenterm does not delete artifacts automatically (no retention caps). Delete files manually if desired.

### Compression (compression.*)

Compression runs **before** a run and may also run **mid-run** (between model turns)
when the packed input grows too large. This is most common in multi-turn agent loops
or when tool output expands the prompt.

Compression creates a compression continuation branch (snapshot/compaction) and
switches head; subsequent model calls replay from the continuation and stay local.

- Strategy:
  - `snapshot`: run `steward.snapshot` (continuation snapshot).
  - `compaction_if_supported`: use `/responses/compact` when the provider declares support; fall back to snapshot otherwise.
  - `both_if_supported`: run both snapshot + compaction and select the active continuation branch via `primary_branch`.
- Trigger:
  - `ask`: prompt in the REPL only; non‑REPL runs skip compression unless `trigger: auto`.
  - `auto`: run compression without prompting.
- Threshold:
  - Percent‑only: `compression.threshold_percent` (0 < x ≤ 1).
  - Uses `model.context_window` (default 400000) as the reference budget; the threshold is capped
    by the input token budget (`context_window - max_output_tokens`).
- Drop policy:
  - `deny`: refuse to drop turns after compression (default).
  - `ask`: prompt before dropping turns.
  - `allow`: drop oldest turns without prompting when still over budget.

Example:

```yaml
compression:
  # snapshot | compaction_if_supported | both_if_supported
  strategy: compaction_if_supported
  # ask | auto
  trigger: ask
  # Compress when history reaches 50% of the context window.
  threshold_percent: 0.5
  # When running both snapshot + compaction, which continuation branch becomes active.
  primary_branch: snapshot
  # deny | ask | allow
  drop_policy: deny
```

Example config file: `examples/config/compression_percent.yaml`
Gateway route example: `examples/config/gateway_routes.yaml`
Ollama route example: `examples/config/ollama_local.yaml`

### Canonical defaults (mirrors `AppConfig` in code)

```yaml
agent:
  # Model identifier (Responses/Agents models only).
  # Model IDs are prefixed: openai/<model> or gateway/<route>/<model>.
  # Validation uses provider registries
  # (OpenAI /models cache or gateway route policy: allowlist/allow_any_model).
  model: openai/gpt-5.2
  # Agent name (instruction file name; bundled agents live in src/agenterm/data/agents).
  # Use /agent <NAME> in the REPL to switch and branch from head.
  name: default
  # SDK turn limit per run (1–500).
  max_turns: 250

model:
  # Sampling
  temperature: 1.0
  #top_p: 0.9
  #frequency_penalty: 0.0
  #presence_penalty: 0.0

  # Output length (visible + reasoning tokens where applicable)
  max_output_tokens: 128000

  # Reasoning configuration for gpt-5 / o-series models.
  # Set to null for non-GPT-5 models.
  reasoning:
    effort: xhigh
    summary: auto

  # Model verbosity (maps to Responses text.verbosity)
  # low|medium|high
  verbosity: medium

  # Include usage so the CLI can surface token summaries.
  include_usage: true

  # Advanced knobs (map directly to ModelSettings / Responses):
  tool_choice: auto
  # agenterm always disables provider-level tool parallelism (parallel_tool_calls=false).
  truncation: disabled
  store: false
  context_window: 400000           # default tokens; set null for 128k fallback; manual; for packing + UI %
  prompt_cache_retention: 24h           # or "in_memory"
  # Optional per-request metadata forwarded to the model API.
  #metadata:
  #  run_id: demo-123
  # Structured output (JSON schema). When set, this populates model.text_format and installs
  # a structured output schema so the model emits responses that follow your JSON schema.
  #text_format:
  #  type: json_schema
  #  name: example_answer
  #  schema:
  #    type: object
  #    properties:
  #      summary:
  #        type: string
  #        description: Short natural-language summary of the result.
  #    required: ["summary"]
  #    additionalProperties: false
  #  strict: true
  #  description: Example structured answer format
  #
  # Alternatively, you can point at a JSON/YAML schema file. Exactly one of
  # text_format/text_format_file may be set.
  #text_format_file: examples/structured/answer_schema.yaml
  #top_logprobs: 0
  #extra_headers:
  #  X-Experiment: B
  #extra_query:
  #  service_tier: priority
  #extra_body:
  #  metadata:
  #    run_id: demo-123

providers:
  openai:
    # Optional OpenAI-compatible endpo