> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Web UI

> A browser app on the same engine as the terminal: chat, coder and agent with your tools, skills, memory, sessions and channels, streamed live, with the permission dialogs the loops raise answered from the page. Opened with /web next to the terminal or served with chatcli web.

`/web` opens ChatCLI in your browser, next to the terminal, **on the same session**. What you type in the browser continues in the terminal, in MCP, in ACP and in your channels, and the other way round, because the browser drives the very same engine and the same saved sessions the other surfaces drive. `chatcli web` serves it without a terminal.

It is local by construction: the server binds the loopback interface on a free port, every run mints its own token, the token travels in a header the page reads from the address once, and nothing is sent anywhere but your own machine.

***

## Opening it

| Command                                          | What it does                                                                                       |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `/web`                                           | Start the web UI bound to this terminal's session and open it in the browser                       |
| `/web url`                                       | Start it and only print the address                                                                |
| `/web status`                                    | Show whether it runs, its address, the child process and the bound session                         |
| `/web off`                                       | Stop it                                                                                            |
| `chatcli web`                                    | Serve the web UI from a terminal of its own, until `Ctrl+C`, bound to a fresh `web-<date>` session |
| `chatcli web --session name`                     | Serve it bound to a saved session                                                                  |
| `chatcli web --addr 127.0.0.1:8765 --no-browser` | Fixed port, print the address only                                                                 |

`/web` works mid-run, like `/dash`. A terminal that is not bound to a saved session gets bound to a fresh one first (`web-<date>`), so the conversation has a name both surfaces can follow; a bound terminal shares its session as is. The browser opens with exactly what that session holds: run `/web` mid-conversation and the page starts with those turns and syncs from there; run it on a terminal that has not typed yet and the page starts empty. It never refills from the rolling `mcp-web` mirror of a previous run. Closing the terminal stops the web UI: the address carried a token only that process handed out.

`chatcli web` on its own does the same: without `--session` it binds the browser to a fresh `web-<date>` session, created on the first completed turn, so each standalone run keeps its own conversation instead of overwriting the rolling `mcp-web` mirror. Nothing is saved "at the end": every completed turn is written through as it finishes, so `Ctrl+C` or closing the tab loses at most a turn that was still streaming. A terminal bound to a named session, including the `web-<date>` one `/web` creates, is flushed once more on exit and is **not** duplicated as an `autosave-` file.

<Info>The browser only opens from an interactive terminal. `chatcli web --no-browser`, or a pipe, prints the address instead.</Info>

## Continuity across surfaces

The web UI is not a second engine. It runs on the shared RPC backend that the [MCP server](/features/mcp-server), the [ACP server](/features/acp) and the [chat gateway](/features/chat-gateway) run on, and it keeps a session the way they do:

* the browser's live history is **bound** to a saved session and written through after every turn;
* before each turn the bound session is re-read when another surface changed it (the terminal, an IDE over ACP, a WhatsApp or Telegram conversation through the gateway), so a reply given elsewhere is in the transcript before you continue;
* the [Conversation Hub](/features/conversation-hub) thread of the principal is resumed, exactly as `chatcli mcp-server` does.

The sidebar lists every saved session with its title. Attach one to continue it, fork it, or start a fresh one. **+ New** clears the page and binds it to a fresh `web-<date>` session of its own (the file appears on the first turn), so the new conversation is saved and listed like any other; the terminal keeps the session it had, and the header names the session the page is bound to. Deleting is the same `/session delete` the terminal runs.

## What you see

| Area           | What it holds                                                                                                                                                                         |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Header**     | Mode (Chat, Coder, Agent), provider and model selectors filled from the catalog and the live model lists, the session cost, theme and language toggles, the panel toggle              |
| **Sessions**   | Saved sessions with titles and age, search, new, fork, delete                                                                                                                         |
| **Transcript** | Streamed replies rendered as Markdown (headings, lists, tables, fenced code with copy), thinking blocks, tool cards with input and output, the agent's plan, cancel and error notices |
| **Composer**   | Enter sends, Shift+Enter breaks the line, `/` opens the command palette, `@` the tool palette; images by file or paste; voice input and image generation when configured              |
| **Panel**      | Status (route, policy, max tokens, cost, daily budget), Tools, Skills, MCP servers, Memory resources, Commands                                                                        |

### Modes and permissions

Chat turns stream token by token through the provider's streaming path. Coder and agent turns stream the loop's structured events: thoughts, messages, every tool call as it starts and ends, and the plan. When a loop reaches a policy-gated action (an `ask` rule, a dangerous command), the page shows the same permission dialog the IDE gets over ACP: **allow once**, **allow always**, **deny**, **deny always**. No answer within the timeout (`CHATCLI_MCP_PERMISSION_TIMEOUT`, default 10 minutes) denies the action once, so a walked-away browser never leaves a loop hanging.

One turn at a time, as in the terminal: while a turn runs, sending another is refused with a clear notice instead of queueing silently. Closing the tab cancels the run.

### Provider and model

The selectors show what the engine can reach: providers with credentials, and per provider the models the catalog knows plus what the provider's API lists live. Picking one sets the route for the turns that follow, without touching the terminal's own selection. Skills that pin a model still win for the turns they fire on.

### Media

| Feature          | Needs                                            | What it does                                                                     |
| ---------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
| Image input      | a vision-capable model, or the describe fallback | Attach or paste images; they reach the turn like `@file` does                    |
| Voice input      | an STT backend (`CHATCLI_STT_*`)                 | Record in the browser, transcribe on your machine, drop the text in the composer |
| Read aloud       | a TTS backend (`CHATCLI_TTS_*`)                  | A speak button on every reply                                                    |
| Image generation | an image provider (`CHATCLI_IMAGE_*`)            | The image button turns the composer text into an image                           |

Features that are not configured are hidden, not broken.

## The API behind the page

The page talks to a small JSON API on the same origin. It is documented here because a script can drive it as well as the page does, with the token from the address:

| Endpoint                                                                              | Purpose                                                                                                                                                            |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET /api/boot`                                                                       | Everything the page needs at load: language, theme, features, providers, tools, skills, commands, resources, sessions, status and the live history                 |
| `POST /api/turn`                                                                      | Run a turn; the response is a stream of server-sent events (`run`, `chunk`, `thought`, `message`, `tool_start`, `tool_end`, `plan`, `permission`, `done`, `error`) |
| `POST /api/runs/{id}/permission`                                                      | Answer a permission dialog: `allow_once`, `allow_always`, `deny_once`, `deny_always`                                                                               |
| `POST /api/runs/{id}/cancel`                                                          | Cancel the running turn                                                                                                                                            |
| `GET /api/sessions`, `GET /api/sessions/{name}/messages`, `POST /api/session`         | The session catalog, a saved session's messages, and the attach/save/fork/clear actions                                                                            |
| `GET /api/tools`, `POST /api/tools/{name}`                                            | The tool catalog and a direct tool call                                                                                                                            |
| `GET /api/skills`, `GET /api/skills/{name}`, `GET /api/commands`, `POST /api/command` | Skills, their content, the slash commands the surface may run, and running one                                                                                     |
| `GET /api/resources`, `GET /api/resource?uri=`                                        | Memory and context resources (`chatcli://memory/...`)                                                                                                              |
| `GET /api/status`, `POST /api/defaults`                                               | Route, cost, budget and MCP status; changing the default provider and model                                                                                        |
| `POST /api/tts`, `POST /api/stt`, `POST /api/image`                                   | Media, when configured                                                                                                                                             |

Every call carries `X-Web-Token: <token>`; the token is never accepted from the query, the Host must match the bound address exactly (a DNS-rebinding guard), and the page ships with a strict Content-Security-Policy that allows no external resource.

## Privacy and safety

* Loopback only. A request to bind another interface is refused.
* One token per run, 128 bits, in memory. Stop the process and the address is dead.
* The web UI runs the engine **unattended** like MCP and ACP: dangerous commands follow `CHATCLI_MCP_DANGER` (`block` turns them into in-band refusals) and the permission dialog covers the `ask` rules. `/policy` in the terminal changes the rules for both.
* The page is one embedded file. No CDN, no fonts, no analytics, works offline.

## Configuration

| Setting                          | Default       | Meaning                                                |
| -------------------------------- | ------------- | ------------------------------------------------------ |
| `chatcli web --addr`             | `127.0.0.1:0` | Listen address; loopback addresses only                |
| `chatcli web --session`          | none          | Saved session to bind at start                         |
| `chatcli web --no-browser`       | off           | Print the address instead of opening the browser       |
| `CHATCLI_MCP_PERMISSION_TIMEOUT` | `600s`        | How long a permission dialog waits before denying once |
| `CHATCLI_MCP_DANGER`             | ask           | `block` refuses dangerous commands in-band             |
| `CHATCLI_MCP_HUB`                | on            | `off` skips the Conversation Hub resume                |

`/config web` shows whether the web UI runs, its address, the child process, the bound session and the log file (`~/.chatcli/web.log`).

## Relationship to the other surfaces

| Surface    | Talks to                    | Session continuity  | Streams           | Permissions                  |
| ---------- | --------------------------- | ------------------- | ----------------- | ---------------------------- |
| Terminal   | the engine directly         | its bound session   | yes               | inline prompts               |
| Web UI     | shared RPC backend          | bound session + hub | SSE               | browser dialog               |
| MCP server | shared RPC backend          | bound session + hub | line emit         | elicitation                  |
| ACP        | shared RPC backend          | bound session + hub | structured events | `session/request_permission` |
| Gateway    | its own ChatCLI, unattended | hub                 | reply per message | auto                         |

<CardGroup cols={2}>
  <Card title="Live Dashboard" icon="chart-network" href="/features/live-dashboard">
    What every process is doing, as a live graph. Open it from the web UI's terminal with `/dash`.
  </Card>

  <Card title="Session Continuity" icon="arrows-rotate" href="/features/session-management">
    How a saved session follows you across the terminal, IDEs and channels.
  </Card>
</CardGroup>
