> ## 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

> Uma app no navegador sobre o mesmo motor do terminal: chat, coder e agent com suas tools, skills, memória, sessões e canais, transmitidos ao vivo, com os diálogos de permissão dos loops respondidos na página. Aberta com /web ao lado do terminal ou servida com chatcli web.

`/web` abre o ChatCLI no seu navegador, ao lado do terminal, **na mesma sessão**. O que você escreve no navegador continua no terminal, no MCP, no ACP e nos seus canais, e vice-versa, porque o navegador aciona exatamente o mesmo motor e as mesmas sessões salvas que as outras superfícies acionam. `chatcli web` a serve sem terminal.

É local por construção: o servidor escuta na interface de loopback numa porta livre, cada execução cria o próprio token, o token viaja num header que a página lê do endereço uma vez, e nada sai da sua máquina.

<Frame caption="Um passeio pela página: o painel com status, o catálogo de tools com filtro, skills e comandos; `/` e `@` abrem paletas no compositor; as abas de modo; o tema claro. (Dados sintéticos.)">
  <img src="https://mintcdn.com/encom/i9tdhZCxh_2JvFDP/images/web-ui.gif?s=06cd950b0470a8b9dd40fff9500fbbe4" alt="Passeio animado pela web UI do ChatCLI: abrindo o painel, filtrando tools, navegando skills e comandos, as paletas de barra e arroba no compositor, trocando modo e tema" width="1440" height="820" data-path="images/web-ui.gif" />
</Frame>

***

## Abrindo

| Comando | O que faz |
| - | - |
| `/web` | Sobe a web UI vinculada à sessão deste terminal e abre no navegador |
| `/web url` | Sobe e só imprime o endereço |
| `/web status` | Mostra se está rodando, o endereço, o processo filho e a sessão vinculada |
| `/web off` | Para |
| `chatcli web` | Serve a web UI de um terminal próprio, até `Ctrl+C`, vinculada a uma sessão `web-<data>` nova |
| `chatcli web --session nome` | Serve vinculada a uma sessão salva |
| `chatcli web --addr 127.0.0.1:8765 --no-browser` | Porta fixa, só imprime o endereço |

`/web` funciona no meio de um turno, como o `/dash`. Um terminal que não está vinculado a uma sessão salva é vinculado a uma nova antes (`web-<data>`), para a conversa ter um nome que as duas superfícies acompanhem; um terminal já vinculado compartilha a sessão como está. O navegador abre exatamente com o que essa sessão tem: rode `/web` no meio de uma conversa e a página começa com esses turnos e sincroniza dali; rode num terminal que ainda não digitou nada e a página começa vazia. Ela nunca é preenchida com o espelho rolling `mcp-web` de uma execução anterior. Fechar o terminal encerra a web UI: o endereço carregava um token que só aquele processo entregou.

`chatcli web` sozinho faz o mesmo: sem `--session` ele vincula o navegador a uma sessão `web-<data>` nova, criada no primeiro turno concluído, então cada execução avulsa guarda a própria conversa em vez de sobrescrever o espelho rolling `mcp-web`. Nada é salvo "no fim": cada turno concluído é gravado assim que termina, então `Ctrl+C` ou fechar a aba perde no máximo um turno que ainda estava em streaming. Um terminal vinculado a uma sessão nomeada, inclusive a `web-<data>` que o `/web` cria, é gravado uma última vez na saída e **não** é duplicado como arquivo `autosave-`.

<Info>O navegador só abre a partir de um terminal interativo. `chatcli web --no-browser`, ou um pipe, imprime o endereço.</Info>

## Continuidade entre superfícies

A web UI não é um segundo motor. Ela roda sobre o backend RPC compartilhado em que o [servidor MCP](/pt/server/mcp-server), o [servidor ACP](/pt/server/acp) e o [chat gateway](/pt/gateway/chat-gateway) rodam, e mantém a sessão do mesmo jeito:

* o histórico ao vivo do navegador é **vinculado** a uma sessão salva e gravado após cada turno;
* antes de cada turno a sessão vinculada é relida quando outra superfície a mudou (o terminal, uma IDE por ACP, uma conversa de WhatsApp ou Telegram pelo gateway), então uma resposta dada em outro lugar já está na transcrição antes de você continuar;
* a thread do [Conversation Hub](/pt/gateway/conversation-hub) do principal é retomada, exatamente como o `chatcli mcp-server` faz.

A barra lateral lista todas as sessões salvas com título. Vincule uma para continuá-la, bifurque, ou comece uma nova. **+ Nova** limpa a página e a vincula a uma sessão `web-<data>` própria (o arquivo aparece no primeiro turno), então a conversa nova é salva e listada como qualquer outra; o terminal segue na sessão que tinha, e o cabeçalho mostra a sessão à qual a página está vinculada. Apagar é o mesmo `/session delete` que o terminal executa.

## O que você vê

| Área | O que contém |
| - | - |
| **Cabeçalho** | Modo (Chat, Coder, Agent), seletores de provider e modelo preenchidos pelo catálogo e pelas listas ao vivo, o custo da sessão, alternadores de tema e idioma, o botão do painel |
| **Sessões** | Sessões salvas com título e idade, busca, nova, bifurcar, apagar |
| **Transcrição** | Respostas transmitidas renderizadas como Markdown (títulos, listas, tabelas, blocos de código com copiar), blocos de raciocínio, cartões de tools com entrada e saída, o plano do agent, avisos de cancelamento e erro |
| **Compositor** | Enter envia, Shift+Enter quebra a linha, `/` abre a paleta de comandos, `@` a de tools; imagens pelo seletor de arquivos ou colagem; botões de microfone, Falar e geração de imagem |
| **Painel** | Status (rota, política, max tokens, custo, orçamento diário), Tools, Skills com filtro e um interruptor de fixar por skill, servidores MCP com um interruptor liga/desliga cada, recursos de memória, comandos |

### Ligando e desligando servidores MCP e skills

**Painel → MCP** tem um interruptor por servidor configurado. Ligar ou desligar faz exatamente o que `/mcp start <nome>` e `/mcp stop <nome>` fazem: o servidor mostra *iniciando…* enquanto conecta, e a lista de tools é atualizada quando ele sobe. **Painel → Skills** tem um interruptor de fixar por skill, o mesmo que `/skill pin <nome>` e `/skill unpin <nome>`: uma skill fixada entra em todos os turnos da sessão, e as fixadas aparecem primeiro, com a contagem. Skills marcadas como só manuais (`disable-model-invocation`) não podem ser fixadas; o interruptor delas fica desabilitado e elas continuam rodando quando você as chama com `/<nome>`.

Como os comandos do terminal, os interruptores valem enquanto o processo web estiver rodando: os servidores MCP voltam como configurados no próximo início, e as skills fixadas pertencem à sessão. O `/web` serve a página a partir do próprio processo `chatcli web`, então um interruptor muda os servidores e as skills fixadas dos turnos do navegador, não os do terminal.

### Modos e permissões

Turnos de chat transmitem token a token pelo caminho de streaming do provider. Turnos de coder e agent transmitem os eventos estruturados do loop: raciocínios, mensagens, cada chamada de tool ao começar e terminar, e o plano. Quando um loop chega a uma ação sob política (uma regra `ask`, um comando perigoso), a página mostra o mesmo diálogo de permissão que a IDE recebe por ACP: **permitir uma vez**, **permitir sempre**, **negar**, **negar sempre**. Sem resposta dentro do timeout (`CHATCLI_MCP_PERMISSION_TIMEOUT`, padrão 10 minutos) a ação é negada uma vez, então um navegador abandonado nunca deixa um loop pendurado.

Um turno de cada vez, como no terminal: enquanto um turno roda, enviar outro é recusado com um aviso claro em vez de enfileirar em silêncio. Fechar a aba cancela a execução.

### Provider e modelo

Os seletores mostram o que o motor alcança: providers com credenciais e, por provider, os modelos que o catálogo conhece mais o que a API do provider lista ao vivo. Escolher um define a rota dos turnos seguintes, sem mexer na seleção do terminal. Skills que fixam um modelo continuam vencendo nos turnos em que disparam.

### Slash commands e tools no compositor

Uma linha que começa com `/` ou `@` é roteada como o terminal a roteia, antes de chegar ao modelo. Os comandos funcionam digitados no compositor, escolhidos no autocompletar do `/` ou executados em **Painel → Comandos**. Depois de um comando e um espaço, o autocompletar oferece subcomandos, flags e valores vindos do completer do próprio terminal: `/mcp ` lista `status`, `start`, `stop` e os demais com descrição, e `/skill pin ` lista as skills. Setas navegam, Tab ou Enter aceitam, Esc fecha:

* `/chat`, `/agent`, `/run` e `/coder` trocam o modo da página; `/coder conserte o teste` troca e executa o resto da linha nesse modo.
* Tudo o que a [superfície ACP](/pt/server/acp) roda headless roda aqui também, listado por `GET /api/commands`: `/help`, `/session`, `/memory`, `/model`, `/switch`, `/cost`, `/policy`, `/config`, `/storage`, `/mcp`, `/skill`, `/dash` e os demais. Eles respondem na transcrição. `/session load`, `attach`, `detach` e `fork` também redesenham a página com a sessão à qual ela fica vinculada.
* [Templates de comando customizados](/pt/extensions/slash-commands) (`~/.chatcli/commands`, o `.chatcli/commands` do projeto, `.claude/commands`, `~/.codex/prompts` e as outras fontes) e [skills](/pt/extensions/skill-authoring) invocáveis pelo usuário (`/<skill> args`) rodam como um turno no modo atual da página, do jeito que o ACP os roda.
* No modo chat, um `@tool` no início roda a tool diretamente, como o `chatcli tool` faz, e mostra a saída num bloco de tool; `@file`, `@git`, `@env` e `@history` continuam injetores de contexto para o modelo.
* Qualquer outro `/texto` que não seja um comando conhecido vai para o modelo como texto do usuário, então um caminho ou um erro de digitação nunca é sequestrado.

A página também atende os comandos que agem sobre a própria conversa, com a semântica do navegador:

| Comando | O que faz na página |
| - | - |
| `/clear` (também `/newsession`, `/session new`) | O mesmo que **+ Nova**: uma conversa nova vinculada a uma sessão `web-<data>` nova. A conversa anterior continua salva em **Sessões**. |
| `/retry` | Pergunta de novo o último turno exatamente como foi registrado (texto, imagens, modo e rota) e substitui a resposta dele. Se a nova tentativa falha, a resposta anterior é restaurada. Não é o `/retry` do terminal, que reenvia um pedaço do fluxo de arquivos grandes. |
| `/rewind [n]` | Remove os últimos `n` turnos (padrão 1) da conversa e da sessão salva vinculada; um terminal que compartilha essa sessão adota a conversa mais curta no próximo turno dele. Só a conversa volta: arquivos que um turno do coder mudou ficam como estão. `/rewind compact` (desfazer uma compactação) é só do terminal. |
| `/plan` | Arma o plan-first como o terminal faz e mostra o último plano da sessão no painel de plano. `/plan <tarefa>` ou `/plan agent <tarefa>` roda a tarefa com plan-first no modo agent, `/plan coder <tarefa>` no modo coder, e `/plan preview <tarefa>` mostra o plano sem executá-lo. |
| `/jobs` | Só leitura: `list` (o padrão), `show`, `tree`, `logs`, `history` e `help`. Cancelar, pausar, podar e as outras mudanças rodam no terminal. |
| `/schedule` | `/schedule list` é o `/jobs list`. `/schedule <spec>` cria o job. A menos que o [daemon do scheduler](/pt/tools/scheduler) esteja rodando (`chatcli daemon start`), o job roda no scheduler do processo web e para junto com ele. |
| `/hooks` | Lista os [hooks](/pt/extensions/hooks-system) configurados. |
| `/lsp <arquivo>` | Mostra os [diagnósticos LSP](/pt/coder/lsp-diagnostics) do arquivo. |

`/wait` não está disponível, porque segura a conversa até uma condição valer e a página roda um turno de cada vez: agende a espera com `/schedule <nome> --wait <condição>` e acompanhe com `/jobs`. Os comandos de arquivos grandes do terminal, `/retryall`, `/nextchunk` e `/skipchunk`, são recusados e apontam para o `/retry`.

Comandos que só fazem sentido num terminal respondem com o motivo e o que fazer no lugar:

| Comando | Por que fica no terminal |
| - | - |
| `/exit`, `/quit` | Feche a aba, ou pare o `chatcli web` (Ctrl+C onde ele roda, ou `/web stop` no terminal que o abriu). |
| `/menu` | Abre o menu do terminal; na página, digite `/` ou abra **Painel → Comandos**. |
| `/update` | Substitui o binário em execução; reinicie a web UI depois. |
| `/auth` | Roda um login interativo; faça o login no terminal e reinicie a web UI. |
| `/gateway`, `/watch`, `/connect` | Iniciam ou controlam um processo de longa duração ligado ao terminal. |
| `/worktree` | Troca a working tree da sessão do terminal. |
| `/reload` | Recarrega a configuração do terminal; reinicie a web UI (`/web stop`, depois `/web`) para pegar as mudanças. |
| `/reset`, `/redraw` | Redesenham a tela do terminal (no REPL, `/reset` redesenha o terminal); na página, use `/clear` para começar uma conversa nova. |

Qualquer outro comando conhecido do REPL fora dessas listas responde que não está disponível no app web.

### Imagens

Anexe imagens pelo seletor de arquivos ou cole no compositor. A legenda é opcional: uma imagem enviada sozinha pede ao modelo que a analise e descreva o que ela mostra.

* As imagens anexadas viajam com o turno e **ficam na conversa** para os turnos seguintes. Uma cópia privada de cada uma também é salva em `~/.chatcli/attachments/` (diretório `0700`, arquivos `0600`, selados em repouso quando `CHATCLI_ENCRYPTION_KEY` está definida), e o turno nomeia o caminho salvo, então uma execução de coder ou agent pode olhá-la de novo com `@view <caminho>` e a referência sobrevive à compactação e ao terminal continuando a sessão. As cópias expiram com a TTL de sessão (`CHATCLI_SESSION_TTL`, 90 dias); o `/storage` as lista e poda como o store `attachments`, e o `/config retention` mostra a política.
* Uma linha enviada com anexos **sempre vai para o modelo**, mesmo quando começa com um `@tool`. No chat, `@view captura.png o que está errado?` anexa aquela imagem local como o `@file` faz; o `@view` nunca roda sozinho no chat, porque ali o próprio turno carrega a imagem.
* A visão é julgada pelo modelo para o qual a página roteia o turno: um modelo com visão recebe a própria imagem; um modelo sem visão recebe o fallback de descrição (a imagem é descrita antes por um modelo com visão).
* Limites: até **32 MB por requisição**; uma maior é recusada com um `413` claro que nomeia o limite, em vez de um erro de decodificação. As cópias salvas têm teto de 20 MB por imagem.

### Voz

A entrada de voz funciona sem configurar nada. A página prefere os **motores offline embutidos** — Whisper para a fala que entra, Kokoro para a fala que sai, sem API key e sem conta — em toda direção que `CHATCLI_TRANSCRIPTION_*` e `CHATCLI_TTS_*` deixam sem configurar; uma API key de nuvem sozinha não é uma escolha de motor de fala (ela está ali para os modelos de chat). `CHATCLI_TRANSCRIPTION_PROVIDER`, `_CMD` ou `_URL`, e os equivalentes `CHATCLI_TTS_*`, fixam outro motor e vencem.

* O primeiro clique no microfone ou no botão de ouvir **pergunta antes de baixar** o motor embutido (cerca de 233 MB para o Whisper base, cerca de 158 MB para o Kokoro; menos quando partes já estão em cache), com barra de progresso e botão de cancelar, ou deixa você manter o motor que serve agora (`Usar <motor> por enquanto`) ou adiar. O download roda em segundo plano, sobrevive ao fechamento do diálogo, e o motor assume assim que fica pronto.
* As gravações são convertidas **no navegador** para WAV mono de 16 kHz, então não é preciso ffmpeg na máquina; um navegador que não consegue decodificar a própria gravação a envia como gravou, e o servidor diz o motivo quando não consegue decodificá-la.
* O microfone mostra o estado — gravando, transcrevendo — e os erros com o motivo (permissão negada, nenhuma fala detectada, navegador sem suporte). Clique para falar, clique de novo para parar; **Esc descarta** uma gravação, ou interrompe uma resposta sendo lida.
* **Falar** inicia uma conversa por voz: o que você diz é transcrito e enviado sozinho, a resposta é lida em voz alta sem código nem símbolos de Markdown, e a página volta a escutar quando a resposta termina. Uma pausa de cerca de 1,3 s encerra a sua vez; uma escuta que não ouve nada encerra o ciclo em silêncio; começar a gravar enquanto uma resposta está sendo lida a interrompe.
* O **botão de ouvir** em cada resposta usa a mesma escolha de motor. O fallback `say` do macOS é convertido para WAV na saída, então toca em qualquer navegador.
* O painel de status mostra o motor que serve cada direção (`Voz de entrada`, `Voz de saída`) e oferece o download quando o motor offline ainda não está instalado; o `/config web` imprime as mesmas linhas no terminal.

<Note>Só a página web prefere os motores embutidos e pergunta antes de baixá-los. O [gateway](/pt/gateway/chat-gateway) e o `@speak` mantêm os padrões do processo: motores locais e sem chave primeiro, o motor embutido a partir do cache ou como último recurso.</Note>

### Geração de imagem

Com um provider de imagem configurado (`CHATCLI_IMAGE_*`), o botão de imagem transforma o texto do compositor numa imagem. Recursos não configurados ficam escondidos, não quebrados.

## A API por trás da página

A página fala com uma pequena API JSON na mesma origem. Está documentada aqui porque um script pode acioná-la tão bem quanto a página, com o token do endereço:

| Endpoint | Propósito |
| - | - |
| `GET /api/boot` | Tudo o que a página precisa ao carregar: idioma, tema, recursos, providers, tools, skills, comandos, recursos de memória, sessões, status e o histórico ao vivo |
| `POST /api/turn` | Executa um turno; a resposta é um stream de server-sent events (`run`, `chunk`, `thought`, `message`, `tool_start`, `tool_end`, `plan`, `permission`, `done`, `error`) |
| `POST /api/runs/{id}/permission` | Responde a um diálogo de permissão: `allow_once`, `allow_always`, `deny_once`, `deny_always` |
| `POST /api/runs/{id}/cancel` | Cancela o turno em execução |
| `GET /api/sessions`, `GET /api/sessions/{name}/messages`, `POST /api/session` | O catálogo de sessões, as mensagens de uma sessão salva e as ações de vincular/salvar/bifurcar/limpar |
| `GET /api/tools`, `POST /api/tools/{name}` | O catálogo de tools e uma chamada direta |
| `GET /api/skills`, `GET /api/skills/{name}`, `GET /api/commands`, `POST /api/command` | Skills (com `pinned` e `manual_only`), o conteúdo delas, os slash commands que a superfície pode executar, e executar um |
| `POST /api/mcp/{name}`, `POST /api/skills/{name}` | Liga ou desliga um servidor MCP (`{"on": true}`), fixa ou desafixa uma skill (`{"pinned": true}`); `501 unsupported` num backend sem os interruptores |
| `GET /api/complete?line=` | Completions da última palavra de uma linha de slash command: `{"items": [{"text", "description"}]}` |
| `GET /api/resources`, `GET /api/resource?uri=` | Recursos de memória e contexto (`chatcli://memory/...`) |
| `GET /api/status`, `POST /api/defaults` | Rota, custo, orçamento e status MCP; troca do provider e modelo padrão |
| `POST /api/tts`, `POST /api/stt`, `POST /api/image` | Falar um texto (`{text}`; Markdown e código são removidos antes, AIFF é convertido para WAV), transcrever um corpo de áudio (qualquer container que o motor decodifique; a página envia WAV mono de 16 kHz, `?lang=` sugere o idioma), gerar uma imagem. `409 voice_install` significa que o motor offline está em oferta e ainda não instalado |
| `GET /api/voice/status`, `POST /api/voice/install`, `POST /api/voice/cancel` | O motor que serve cada direção (`stt`, `tts`), se a instalação embutida está em oferta e o tamanho do download, e o progresso da instalação em andamento; iniciar a instalação (`{targets: ["stt","tts"]}`) ou cancelá-la |

Toda chamada carrega `X-Web-Token: <token>`; o token nunca é aceito pela query, o Host precisa bater exatamente com o endereço vinculado (guarda contra DNS rebinding), e a página traz uma Content-Security-Policy estrita que não permite recurso externo algum.

## Privacidade e segurança

* Só loopback. Um pedido para escutar em outra interface é recusado.
* Um token por execução, 128 bits, em memória. Pare o processo e o endereço morre.
* A web UI roda o motor **desassistido** como MCP e ACP: comandos perigosos seguem `CHATCLI_MCP_DANGER` (`block` os transforma em recusas em linha) e o diálogo de permissão cobre as regras `ask`. `/policy` no terminal muda as regras para os dois.
* A página é um único arquivo embutido. Sem CDN, sem fontes, sem analytics, funciona offline.

## Configuração

| Configuração | Padrão | Significado |
| - | - | - |
| `chatcli web --addr` | `127.0.0.1:0` | Endereço de escuta; só endereços de loopback |
| `chatcli web --session` | nenhum | Sessão salva para vincular no início |
| `chatcli web --no-browser` | desligado | Imprime o endereço em vez de abrir o navegador |
| `CHATCLI_MCP_PERMISSION_TIMEOUT` | `600s` | Quanto tempo um diálogo de permissão espera antes de negar uma vez |
| `CHATCLI_MCP_DANGER` | ask | `block` recusa comandos perigosos em linha |
| `CHATCLI_MCP_HUB` | ligado | `off` pula a retomada do Conversation Hub |
| `CHATCLI_TRANSCRIPTION_PROVIDER` / `_CMD` / `_URL`, `CHATCLI_TRANSCRIPTION_MODEL`, `CHATCLI_TRANSCRIPTION_LANG` | vazio | Fixa um motor de fala para texto (vazio: a página prefere o Whisper embutido); o tamanho do modelo Whisper (`base`); a sugestão de idioma padrão |
| `CHATCLI_TTS_PROVIDER` / `_CMD` / `_URL`, `CHATCLI_TTS_VOICE`, `CHATCLI_TTS_VOICE_PT` | vazio | Fixa um motor de texto para fala (vazio: a página prefere o Kokoro embutido); as vozes |
| `CHATCLI_SESSION_TTL` | `90` | Dias que as cópias salvas das imagens anexadas ficam guardadas |

`/config web` mostra se a web UI está rodando, o endereço, o processo filho, a sessão vinculada e o arquivo de log (`~/.chatcli/web.log`), mais as linhas de voz: o motor que a página usa em cada direção e o estado do motor offline que ela prefere (instalado, ou o tamanho do download).

## Relação com as outras superfícies

| Superfície | Fala com | Continuidade de sessão | Transmite | Permissões |
| - | - | - | - | - |
| Terminal | o motor diretamente | sua sessão vinculada | sim | prompts em linha |
| Web UI | backend RPC compartilhado | sessão vinculada + hub | SSE | diálogo no navegador |
| Servidor MCP | backend RPC compartilhado | sessão vinculada + hub | emit de linhas | elicitation |
| ACP | backend RPC compartilhado | sessão vinculada + hub | eventos estruturados | `session/request_permission` |
| Gateway | ChatCLI próprio, desassistido | hub | resposta por mensagem | automático |

<CardGroup cols={2}>
  <Card title="Dashboard ao vivo" icon="chart-network" href="/pt/usage/live-dashboard">
    O que cada processo está fazendo, como um grafo ao vivo. Abra do terminal da web UI com `/dash`: a web UI aparece como janela própria `web`, com seus turnos, chamadas de modelo, tools e skills.
  </Card>

  <Card title="Continuidade de sessão" icon="arrows-rotate" href="/pt/context/session-management">
    Como uma sessão salva acompanha você pelo terminal, IDEs e canais.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.