@leg3ndy/otto-bridge
v1.1.8
Published
Local companion for Otto Bridge device pairing and WebSocket runtime.
Maintainers
Readme
Otto Bridge
Companion local do Otto para:
- reivindicar um codigo de pareamento gerado pela web
- armazenar o
device_tokendo dispositivo - manter um WebSocket persistente com o backend
- executar jobs locais com executor proprio do Otto no macOS,
mockouclawd-cursor
Guia de uso
Para um passo a passo de instalacao, pareamento, uso, desconexao e desinstalacao, veja USER_GUIDE.md.
Para o estado atual da arquitetura, capacidades entregues, limitacoes e roadmap do Otto Bridge, veja leg3ndy-ai-backend/docs/otto-bridge/OTTO_BRIDGE_ARCHITECTURE.md.
Para o corte de arquitetura do 0.9.0, veja leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_0_9_0_RELEASE.md.
Para o patch atual 1.1.8, veja leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_8_PATCH.md. Para o corte funcional da linha 1.1.0, veja leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_0_RELEASE.md.
Distribuicao
Fluxo recomendado agora:
- publicar como pacote npm privado/publico para time interno e beta testers
- validar pareamento, atualizacao e telemetria em ambiente real
- depois empacotar em
.dmg/.pkgno macOS e.msino Windows
O pacote ja esta estruturado para install via CLI:
npm install -g @leg3ndy/otto-bridge
otto-bridge
otto-bridge status
otto-bridge versionEnquanto o pacote nao estiver publicado, voce pode gerar um tarball local:
npm pack
npm install -g ./leg3ndy-otto-bridge-1.1.8.tgzNa linha 1.1.8, playwright segue como dependencia obrigatoria no otto-bridge. O primeiro npm install -g @leg3ndy/otto-bridge pode demorar mais porque instala o browser persistente usado pelo WhatsApp Web e pelos fluxos web em background do bridge.
No macOS, a linha 1.1.8 usa o provider macos-helper, um helper WKWebView sem Dock para o WhatsApp Web. O helper sobe com user-agent de Chrome moderno para evitar o bloqueio do WhatsApp ao detectar Safari/WebKit. O runtime antigo com Chromium/Playwright fica disponivel apenas como override explicito via OTTO_BRIDGE_WHATSAPP_RUNTIME_PROVIDER=embedded-playwright.
No nivel arquitetural, o 0.9.0 marcou a mudanca de papel do bridge: ele publica tools e resultados estruturados para o Otto, em vez de injetar resposta pronta como caminho principal do chat. O 1.0.0 oficializou isso como runtime agentico; o 1.1.8 mantem a camada workspace-first com rail de coding, trust/policy por workspace, source control first-class, working set persistido e grounding remoto por repositório, enquanto endurece o Otto Console, evita que otto-bridge update dispare setup interativo no meio da autoatualizacao e faz o scroll por wheel/trackpad funcionar no Terminal.app sem reativar click tracking.
Publicacao
Checklist de release:
npm whoami
npm install
npm run release:check
npm publish --access publicO publish exige permissao no scope @leg3ndy.
Se o seu npm local estiver com cache travado por permissao, rode com cache temporario:
npm_config_cache=/tmp/otto-npm-cache npm run release:check
npm_config_cache=/tmp/otto-npm-cache npm publish --access publicComandos
Listar ajuda
otto-bridge help
otto-bridge --helpAbrir o hub interativo e ligar o runtime
otto-bridgeEm TTY, o comando sem argumentos agora abre o hub interativo com banner, setup, status, extensoes e o Otto Console. Se ja existir pairing salvo, o próprio otto-bridge sobe o runtime local automaticamente e mostra o estado da conexão no hub.
Na web, o acesso ao Otto Bridge fica no botao com icone de estrela/brilho ao lado do botao de anexos.
Setup interativo
otto-bridge setupEsse fluxo pede API base URL, pairing code, nome do dispositivo e executor. Em install global interativo, o pacote tambem tenta abrir esse setup automaticamente quando ainda nao existe pairing salvo.
O pairing code e gerado no modal do Otto Bridge aberto pela interface web, no botao com icone de estrela ao lado de anexos.
Parear o dispositivo
otto-bridge pair --api http://localhost:8000 --code ABC123Opcoes suportadas:
--name: nome amigavel do dispositivo--timeout-seconds: limite de espera pela aprovacao web--poll-interval-ms: intervalo de polling do claim--executor:native-macos,mockouclawd-cursor--clawd-url: base URL da API local doclawd-cursor--clawd-poll-interval-ms: polling do status/logs doclawd-cursor
No macOS, o caminho recomendado agora e o executor nativo do Otto Bridge. Se nenhum --executor for informado, o pair usa native-macos por padrao no Mac.
Runtime principal do bridge
otto-bridgeEsse agora e o fluxo principal do produto: o hub abre, conecta o runtime local e deixa o Otto pronto para handoff e approvals sem depender de nenhum comando separado de runtime.
Se precisar do executor nativo no macOS sem reparar, atualize o pairing/config e reabra o hub:
otto-bridge setupO adapter clawd-cursor continua disponivel como override opcional no pairing legado:
otto-bridge pair --executor clawd-cursor --clawd-url http://127.0.0.1:3847Falar com o Otto no terminal
otto-bridge consoleO console usa a mesma sessão local já ligada pelo otto-bridge, envia prompts naturais ao backend usando device_token, respeita quota/plano do usuário e só vira handoff local quando o pedido realmente tiver cara de ação no computador. Quando houver device_job, ele acompanha polling e resolve confirm_required no terminal.
Dentro do console, use:
/model fastparaOttoAI Fast/model thinkingparaOttoAI Thinking/approval preview,/approval confirmou/approval trustedpara trocar o modo de aprovação do device/statuspara ver detalhes técnicos do bridge e do runtime/workspaceou/workspace statuspara ver o workspace ativo desta sessão/workspace listpara listar workspaces anexados ao device/workspace attach <path>para anexar uma pasta/repo novo pelo helper autenticado/workspace use <id|n>para fixar um workspace anexado na sessão atual/workspace clearpara limpar o binding atual do chat/sessão/newpara iniciar uma nova sessão e limpar o contexto local do console
No TTY, o console agora entra em alternate screen ao abrir o Otto Console, para esconder o scrollbar manual/nativo do terminal e deixar só a viewport interna do Otto. O header é impresso uma vez no topo da sessão, o transcript continua completo dentro da tela do console e o composer fica preso no rodapé com placeholder Peça algo ao Otto. Ao digitar /, o bridge abre uma palette navegável por setas, com Enter preenchendo comandos como /new para iniciar uma nova sessão local. Wheel/trackpad usam alternate scroll do terminal para navegar o transcript como setas; PageUp/PageDown continuam funcionando e cliques deixam de ser reportados como input do console.
No modo OttoAI Thinking, o terminal agora marca explicitamente o trecho de raciocínio com Pensando (OttoAI Thinking) e separa esse bloco da resposta final do Otto.
Quando o handoff local devolver resultado estruturado, o CLI agora mostra inline a listagem de arquivos e o conteúdo de read_file, em vez de só resumir que executou a tarefa.
Abrir um shell local pelo hub
otto-bridge terminalEsse comando abre um shell local interativo para instalar extensoes, rodar comandos externos e fazer operacao manual sem encerrar o bridge. No hub principal, a opcao Terminal faz a mesma coisa e volta ao menu quando voce sair com exit.
WhatsApp Web em background
Fluxo recomendado na linha 1.1.8:
otto-bridge extensions --install whatsappweb
otto-bridge extensions --setup whatsappweb
otto-bridge extensions --status whatsappwebO setup agora abre o login do WhatsApp Web no helper/background browser do proprio bridge. Depois do QR code, o Otto usa a sessao local em background, sem depender de aba visivel no Safari.
Contrato da linha 1.1.8:
otto-bridge extensions --setup whatsappweb: autentica a sessao uma vezotto-bridge: mantem o browser persistente do WhatsApp vivo em background enquanto o runtime do hub estiver ativo, sem depender de uma aba aberta no Safari- ao fechar o
otto-bridge: o browser em background e desligado, mas a sessao local fica lembrada para o proximo boot
Handoff rapido da linha 1.1.8
Ja fechado no codigo:
- provider
macos-helperdockless no macOS como runtime padrao do WhatsApp - user-agent do helper ajustado para evitar bloqueio do WhatsApp por detecao de Safari/WebKit
- resultado final dos
device_jobagora e persistido como contexto mais forte para o proximo turno do Otto - prompt bridge-aware no chat normal para ajudar o Otto a responder com base no que realmente aconteceu no device
- runtime local agora publica
local_toolspara o Otto/backend saberem exatamente o que o device consegue fazer - o runtime agentico agora executa
execution_graphgranular por acao, em vez de colapsar a corrida local inteira num unicotool_call - o protocolo do runtime agora publica
graph_id/step_idnos eventos de job e aceita controles por step para confirmacao/cancelamento - o executor
native-macosagora reporta o step atual por acao e publica inline artifacts estruturados para resultados locais nao-uploadados - o
runtime_contractagora pode declararworkspace_contextcom roots/targets e descriptors deinstruction_bundle,repo_manifest,workspace_index,workspace_memoryeworkspace_policypara jobs de arquivo e shell - o bridge agora resolve
workspace_contextem paths absolutos, detectarepo_root, carregaAGENTS.mdpor precedencia e publicainstruction_bundle,repo_manifest,workspace_index,workspace_memoryeworkspace_policyno resultado - workspaces anexados pelo modal web agora tambem viram parte do metadata do helper: o
otto-bridgeconsulta/v1/devices/runtime/workspacescomdevice_token, sonda localmenterepo_root,branche a cadeia deAGENTS.mdantes dodevice.hello, e reage adevice.metadata.refreshpara republicar esse snapshot quando o usuario anexa/remove um workspace com o bridge online - filesystem e shell locais agora respeitam os roots declarados do workspace, em vez de operar como superficie global quando o job vier escopado
workspace_policyagora aplica perfisobserve_only,dev_assist,workspace_codingerelease_operatorantes da execucao local de actions escopadas- cada workspace anexado agora tambem persiste o proprio
policy_profile_id; o modal do Otto Bridge permite trocar esse perfil, o banner do chat mostra o trust atual e o runtime trata esse valor como teto real da sessao antes de shell, patch, delete ou release write_json_file,mkdir,move_fileedelete_fileagora fazem parte da familia inicial de file ops tipadas do workspaceworkspace.patch,git.clone,git.fetch,git.checkout,git.rebase,git.merge,git.tag,git.status,git.diff,git.stage,git.commit,git.pusheworkspace.testsagora fazem parte da primeira familia tipada de coding agent do catalogo localapply_patch,git_status,git_diff,run_tests,git_clone,git_fetch,git_checkout,git_rebase,git_merge,git_tag,git_add,git_commitegit_pushagora executam dentro do workspace escopado e devolvem snapshots estruturados em vez de shell cruapply_patchentende o formato*** Begin Patch ... *** End Patch, devolvepatch_setestruturado e continua bloqueando paths fora do workspace permitidorun_testsagora aceitacommandexplicito ouprofiletipado (pytest,npm_test,pnpm_test,yarn_test,bun_test,lint,build) e devolveresolved_commandno snapshot finalgit_clone,git_fetch,git_checkout,git_rebase,git_merge,git_tag,git_add,git_commitegit_pushsobem comrequires_confirmation, devolvem receipts estruturados (git_clone_receipt,git_fetch_receipt,git_checkout_receipt,git_rebase_receipt,git_merge_receipt,git_tag_receipt,git_stage_receipt,git_commit_receipt,git_push_receipt) e tratamnothing_to_commit/Everything up-to-datecomo resultado observavel do jobrepo_manifesteworkspace_indexagora saem comscoped_root_path, manifests/lockfiles, key files e extensoes dominantes para grounding leve de repoworkspace_memoryagora reaproveita o historico recente do mesmoworkspace_ide volta atualizada no resultado do job para grounding curto entre execucoesworkspace_memoryagora tambem respeita governanca persistida no backend, comretention_days,retention_job_limit,last_cleared_atelast_cleared_reason, que o modal do Otto Bridge pode ajustar sem sair do runtime- automacoes locais do canal
bridgeagora disparam/v1/devices/automations/local/bridge/triggerem cada tick, reaproveitando o mesmo runtime agentico do chat comdevice_job, approvals e replay auditaveis - o
runtime_contractagora tambem pode declararworker_profiles, e o executor ecoa esse bundle emworker_profiles/artifact para deixar explicito quais perfis de leitura, mudanca, validacao e release foram ativados no job - o
execution_graphagora pode marcarworker_idpor step, e oruntime_contracttambem pode declararworker_executioncombudget_seconds,timeout_seconds,retry_limitemax_parallel_taskspor worker para preparar fan-out controlado - o backend agora deriva
runtime_workerseruntime_handoffspersistidos do mesmo graph, incluindoworker_run_id,fanout_level/wave/groupe retry por worker a partir deretry_of_worker_run_id/retry_attempt git_diffagora carregastatediff_excerpt, e o backend usa isso para grounding mais estrito de respostas sobre diff longo- o
runtime_contractagora tambem declaracommand_packsformais (plan-fast,plan-deep,instruction-updater), e o bridge ecoa esses modos como artifact estruturado para deixar claro qual intensidade de planejamento/manutencao foi aplicada no job - o
instruction_updateragora e um descriptor explicito do runtime, comsource_entrypoints,target_pathserecommended_validation_stage_idsquando o plano tocaAGENTS.md,README.mdoudocs/ workspace.testsagora consegue resolverprofile=autoviavalidation_ladder, executando stages comotypecheck,build,node_test,lintepytestpor stack, com snapshot agregado por etapa- o executor
native-macosagora publicaruntime_hook_tracesomando hooks de lifecycle e tool-use (session_start,pre_tool_use,post_tool_use,validation_ladder_started/completed,session_end), preparando enforcement, replay fino e metricas futuras - o frontend agora consome
runtime_hook_trace,runtime_replaye o progresso corrente como feed inline persistente no chat, para o usuario ver o Otto lendo, procurando, editando, validando e concluindo em tempo real - o chat web agora mostra esse plano/checklist acima do input enquanto o job local roda, e deixa o bloco detalhado de runtime apenas para o resultado final quando houver detalhe real de arquivo/diff/source control/validacao/erro
- o catalogo local agora inclui
filesystem.open_path, usado para abrir um arquivo/pasta local no app padrao do macOS ou revelar no Finder a partir dos links clicaveis do timeline - o modal do Otto Bridge agora mostra
Jobs locaisem resumo textual,Snapshot do workspacecom source control/validacao/working set e links de path que disparamopen_pathlocal, sem repetir a timeline detalhada do chat - o bridge agora possui um CLI interativo proprio com setup inicial, hub terminal e
Otto Consolepara conversar com o Otto pelo proprio terminal - o backend agora expoe caminhos
device-authpara o console do bridge usar chat com quota/plano (/v1/devices/cli/chat/completions) e acompanhar approval/job usando apenasdevice_token - o caminho principal do bridge usa
summary/narration_contextno lugar de resposta automatica pronta read_fileagora entrega conteudo completo segmentado emcontent_chunkspara o Ottolist_filessemlimitagora lista o diretorio inteiro, sem fallback silencioso para 40 itens- o planner do bridge prioriza o modelo para escolher a tool certa pelo contexto; regex fica como fallback
Testes locais do runtime
npm run test:runtimeAinda precisa reteste em campo:
- fluxo completo do WhatsApp no helper
macos-helper - confirmacao de que o helper realmente passa do gate de compatibilidade do WhatsApp
- perguntas de follow-up como
o que voce mandou?depois de uma acao local de mensagem
Ver estado local
otto-bridge statusVer versao instalada
otto-bridge version
otto-bridge --versionAtualizar o pacote
Atualizacao automatica via npm:
otto-bridge updatePara apenas ver qual comando sera executado:
otto-bridge update --dry-runPara instalar manualmente:
npm install -g @leg3ndy/otto-bridge@latestRemover pareamento local
otto-bridge unpairVariaveis de ambiente
OTTO_API_BASE_URLOTTO_BRIDGE_HOMEOTTO_BRIDGE_NAMEOTTO_BRIDGE_EXECUTOROTTO_CLAWD_BASE_URLOTTO_CLAWD_POLL_INTERVAL_MS
Payload esperado para jobs desktop
Os executores locais do Otto Bridge procuram a tarefa em uma destas chaves, nessa ordem:
taskpromptinstructioninstructionsmessage
O executor nativo do macOS tambem aceita payload estruturado em actions[], por exemplo:
{
"job_type": "desktop_actions",
"payload": {
"actions": [
{ "type": "open_app", "app": "Safari" },
{ "type": "open_url", "url": "https://www.youtube.com", "app": "Safari" }
]
}
}Exemplo:
{
"job_type": "desktop_task",
"payload": {
"task": "Abra o Safari e pesquise Otto AI"
}
}