/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.

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.)
Abrindo
/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-.
O navegador só abre a partir de um terminal interativo.
chatcli web --no-browser, ou um pipe, imprime o endereço.Continuidade entre superfícies
A web UI não é um segundo motor. Ela roda sobre o backend RPC compartilhado em que o servidor MCP, o servidor ACP e o 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 do principal é retomada, exatamente como o
chatcli mcp-serverfaz.
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ê
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 regraask, 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,/rune/codertrocam o modo da página;/coder conserte o testetroca e executa o resto da linha nesse modo.- Tudo o que a superfície ACP roda headless roda aqui também, listado por
GET /api/commands:/help,/session,/memory,/model,/switch,/cost,/policy,/config,/storage,/mcp,/skill,/dashe os demais. Eles respondem na transcrição./session load,attach,detacheforktambém redesenham a página com a sessão à qual ela fica vinculada. - Templates de comando customizados (
~/.chatcli/commands, o.chatcli/commandsdo projeto,.claude/commands,~/.codex/promptse as outras fontes) e skills 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
@toolno início roda a tool diretamente, como ochatcli toolfaz, e mostra a saída num bloco de tool;@file,@git,@enve@historycontinuam injetores de contexto para o modelo. - Qualquer outro
/textoque 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.
/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:
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ório0700, arquivos0600, selados em repouso quandoCHATCLI_ENCRYPTION_KEYestá 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/storageas lista e poda como o storeattachments, e o/config retentionmostra 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@filefaz; o@viewnunca 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
413claro 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 queCHATCLI_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
saydo 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 webimprime as mesmas linhas no terminal.
Só a página web prefere os motores embutidos e pergunta antes de baixá-los. O 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.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:
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(blockos transforma em recusas em linha) e o diálogo de permissão cobre as regrasask./policyno terminal muda as regras para os dois. - A página é um único arquivo embutido. Sem CDN, sem fontes, sem analytics, funciona offline.
Configuração
/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
Dashboard ao vivo
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.Continuidade de sessão
Como uma sessão salva acompanha você pelo terminal, IDEs e canais.