UI de Controle (navegador)¶
A UI de Controle é um pequeno app de página única Vite + Lit servido pelo Gateway:
- padrão:
http://<host>:18789/ - prefixo opcional: defina
gateway.controlUi.basePath(ex.:/openclaw)
Ela se comunica diretamente com o WebSocket do Gateway na mesma porta.
Abertura rápida (local)¶
Se o Gateway estiver em execução no mesmo computador, abra:
Se a página não carregar, inicie o Gateway primeiro: openclaw gateway.
A autenticação é fornecida durante o handshake do WebSocket via:
connect.params.auth.tokenconnect.params.auth.passwordO painel de configurações do dashboard permite armazenar um token; senhas não são persistidas. O assistente de onboarding gera um token do gateway por padrão, então cole-o aqui na primeira conexão.
Pareamento de dispositivo (primeira conexão)¶
Quando você se conecta à UI de Controle a partir de um novo navegador ou dispositivo, o Gateway
exige uma aprovação de pareamento única — mesmo se você estiver na mesma Tailnet
com gateway.auth.allowTailscale: true. Isso é uma medida de segurança para evitar
acesso não autorizado.
O que você verá: "disconnected (1008): pairing required"
Para aprovar o dispositivo:
# List pending requests
openclaw devices list
# Approve by request ID
openclaw devices approve <requestId>
Após a aprovação, o dispositivo é lembrado e não exigirá nova aprovação, a menos
que você o revogue com openclaw devices revoke --device <id> --role <role>. Veja
Devices CLI para rotação e revogação de tokens.
Notas:
- Conexões locais (
127.0.0.1) são aprovadas automaticamente. - Conexões remotas (LAN, Tailnet, etc.) exigem aprovação explícita.
- Cada perfil de navegador gera um ID de dispositivo único; portanto, trocar de navegador ou limpar os dados do navegador exigirá novo pareamento.
O que ela pode fazer (hoje)¶
- Conversar com o modelo via Gateway WS (
chat.history,chat.send,chat.abort,chat.inject) - Fazer streaming de chamadas de ferramentas + cartões de saída de ferramentas ao vivo no Chat (eventos do agente)
- Canais: status do WhatsApp/Telegram/Discord/Slack + canais de plugin (Mattermost, etc.) + login por QR + configuração por canal (
channels.status,web.login.*,config.patch) - Instâncias: lista de presença + atualização (
system-presence) - Sessões: lista + substituições de thinking/verbose por sessão (
sessions.list,sessions.patch) - Cron jobs: listar/adicionar/executar/habilitar/desabilitar + histórico de execuções (
cron.*) - Skills: status, habilitar/desabilitar, instalar, atualizações de chave de API (
skills.*) - Nós: lista + capacidades (
node.list) - Aprovações de exec: editar allowlists do gateway ou do nó + política de solicitação para
exec host=gateway/node(exec.approvals.*) - Configuração: visualizar/editar
~/.openclaw/openclaw.json(config.get,config.set) - Configuração: aplicar + reiniciar com validação (
config.apply) e acordar a última sessão ativa - Gravações de configuração incluem um guard de hash base para evitar sobrescrever edições concorrentes
- Esquema de configuração + renderização de formulários (
config.schema, incluindo esquemas de plugin + canal); o editor Raw JSON permanece disponível - Debug: snapshots de status/saúde/modelos + log de eventos + chamadas RPC manuais (
status,health,models.list) - Logs: tail ao vivo dos logs de arquivo do gateway com filtro/exportação (
logs.tail) - Atualização: executar uma atualização de pacote/git + reiniciar (
update.run) com um relatório de reinicialização
Notas do painel de Cron jobs:
- Para jobs isolados, a entrega padrão é anunciar um resumo. Você pode alternar para nenhum se quiser execuções apenas internas.
- Os campos de canal/alvo aparecem quando anunciar é selecionado.
Comportamento do chat¶
chat.sendé não bloqueante: confirma imediatamente com{ runId, status: "started" }e a resposta é transmitida via eventoschat.- Reenviar com o mesmo
idempotencyKeyretorna{ status: "in_flight" }enquanto estiver em execução, e{ status: "ok" }após a conclusão. chat.injectadiciona uma nota do assistente ao transcript da sessão e transmite um eventochatapenas para atualizações de UI (sem execução do agente, sem entrega em canal).- Parar:
- Clique em Stop (chama
chat.abort) - Digite
/stop(oustop|esc|abort|wait|exit|interrupt) para abortar fora de banda chat.abortoferece suporte a{ sessionKey }(semrunId) para abortar todas as execuções ativas daquela sessão
Acesso via Tailnet (recomendado)¶
Tailscale Serve integrado (preferido)¶
Mantenha o Gateway em loopback e deixe o Tailscale Serve fazer o proxy com HTTPS:
openclaw gateway --tailscale serve
Abra:
https://<magicdns>/(ou seugateway.controlUi.basePathconfigurado)
Por padrão, as requisições do Serve podem se autenticar via cabeçalhos de identidade do Tailscale
(tailscale-user-login) quando gateway.auth.allowTailscale está true. O OpenClaw
verifica a identidade resolvendo o endereço x-forwarded-for com
tailscale whois e comparando com o cabeçalho, e só aceita isso quando a
requisição atinge o loopback com os cabeçalhos x-forwarded-* do Tailscale. Defina
gateway.auth.allowTailscale: false (ou force gateway.auth.mode: "password")
se você quiser exigir token/senha mesmo para tráfego do Serve.
Vincular à tailnet + token¶
openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
Depois abra:
http://<tailscale-ip>:18789/(ou seugateway.controlUi.basePathconfigurado)
Cole o token nas configurações da UI (enviado como connect.params.auth.token).
HTTP inseguro¶
Se você abrir o dashboard via HTTP simples (http://<lan-ip> ou http://<tailscale-ip>),
o navegador roda em um contexto não seguro e bloqueia o WebCrypto. Por padrão,
o OpenClaw bloqueia conexões da UI de Controle sem identidade do dispositivo.
Correção recomendada: use HTTPS (Tailscale Serve) ou abra a UI localmente:
https://<magicdns>/(Serve)http://127.0.0.1:18789/(no host do gateway)
Exemplo de downgrade (apenas token via HTTP):
{
gateway: {
controlUi: { allowInsecureAuth: true },
bind: "tailnet",
auth: { mode: "token", token: "replace-me" },
},
}
Isso desativa identidade do dispositivo + pareamento para a UI de Controle (mesmo em HTTPS). Use apenas se você confiar na rede.
Veja Tailscale para orientações de configuração de HTTPS.
Construindo a UI¶
O Gateway serve arquivos estáticos a partir de dist/control-ui. Compile-os com:
pnpm ui:build # auto-installs UI deps on first run
Base absoluta opcional (quando você quer URLs de assets fixas):
OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build
Para desenvolvimento local (servidor de dev separado):
pnpm ui:dev # auto-installs UI deps on first run
Depois, aponte a UI para a URL do WS do seu Gateway (ex.: ws://127.0.0.1:18789).
Depuração/testes: servidor de dev + Gateway remoto¶
A UI de Controle é composta por arquivos estáticos; o destino do WebSocket é configurável e pode ser diferente da origem HTTP. Isso é útil quando você quer o servidor de dev do Vite localmente, mas o Gateway roda em outro lugar.
- Inicie o servidor de dev da UI:
pnpm ui:dev - Abra uma URL como:
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
Autenticação opcional única (se necessário):
http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789&token=<gateway-token>
Notas:
gatewayUrlé armazenado no localStorage após o carregamento e removido da URL.tokené armazenado no localStorage;passwordé mantido apenas na memória.- Quando
gatewayUrlestá definido, a UI não faz fallback para credenciais de configuração ou de ambiente. Forneçatoken(oupassword) explicitamente. A ausência de credenciais explícitas é um erro. - Use
wss://quando o Gateway estiver atrás de TLS (Tailscale Serve, proxy HTTPS, etc.). gatewayUrlsó é aceito em uma janela de nível superior (não incorporada) para evitar clickjacking.- Para configurações de dev com cross-origin (ex.:
pnpm ui:devpara um Gateway remoto), adicione a origem da UI agateway.controlUi.allowedOrigins.
Exemplo:
{
gateway: {
controlUi: {
allowedOrigins: ["http://localhost:5173"],
},
},
}
Detalhes de configuração de acesso remoto: Acesso remoto.