Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Este projeto é implementação própria. Não copie nem adapte código, testes,
```
crates/botloft-core tipos de domínio, IDs, envelope, tipos do protocolo (exportados via ts-rs)
crates/botloft-store SQLite, migrations em migrations/NNNN_nome.sql
crates/botloftd daemon: rpc, supervisor, runtime, terminal, courier, tools, hooks, platform
app/ Tauri v2 + React 19 + TS strict + Tailwind v4 + Zustand + xterm.js
docs/ spec e ADRs
crates/botloftd daemon: rpc, supervisor, runtime, chat, courier, tools, platform
app/ Tauri v2 + React 19 + TS strict + Tailwind v4 + Zustand
docs/ spec e ADRs (docs/adr/0001: bots headless com chat)
```

## Comandos
Expand Down Expand Up @@ -50,31 +50,29 @@ Em dev, use `$env:BOTLOFT_HOME = "$PWD\.dev\home"` (caminho absoluto) no daemon
- Código, identificadores, comentários, commits e README em **inglês**. Docs em `docs/` podem ser em português.
- Arquivos com no máximo **~300 linhas**. Passou disso, divida por responsabilidade.
- Erros: `thiserror` nos crates de biblioteca, `anyhow` só no binário.
- IDs são ULID com prefixo (`crw_`, `bot_`, `msg_`, `dlv_`, `tsk_`). Tempo em ms Unix.
- IDs são ULID com prefixo (`crw_`, `bot_`, `msg_`, `dlv_`, `tsk_`, `cht_`, `apr_`, `att_`). Tempo em ms Unix.
- Tudo que é específico de Windows fica em `crates/botloftd/src/platform/`. O resto do daemon não chama Win32 direto.
- A UI depende só da interface `BotloftApi` (`app/src/lib/api.ts`). Testes de componente usam `FakeBotloft`.
- Nunca edite `app/src/lib/protocol.gen.ts` à mão.
- Commits pequenos, no formato Conventional Commits (`feat(courier): ...`).

## Windows: armadilhas conhecidas

- O inbox do Claude Code no Windows é um **named pipe** criado pelo próprio Claude Code. O daemon é cliente. A primeira linha tem que ser o auth com `CLAUDE_CODE_MESSAGING_TOKEN`, senão a conexão é descartada. Abra o pipe só com a mensagem pronta.
- Hooks usam **exec form** (`"args": [...]`) chamando `botloftd.exe hook <evento>`. Nada de hook em bash ou PowerShell. O subcomando sai sempre com 0 e nunca escreve no stdout.
- Só o `claude.exe` nativo roda. O `claude.cmd` do npm é recusado: passar por `cmd.exe` estraga o quoting na PTY.
- ConPTY não tem fd para `poll`: leitura da PTY em thread dedicada + canal. Ao fim do processo, feche o pseudoconsole, senão a leitura nunca vê EOF.
- O ConPTY do `portable-pty` (com `PSEUDOCONSOLE_INHERIT_CURSOR`) manda `ESC[6n` ao iniciar e trava o filho até a resposta. O daemon responde `ESC[1;1R` à primeira consulta.
- Cada bot é `claude -p` com `stream-json` no stdin e no stdout (spec 7.4, 8, 9.2). O processo fica calado até a primeira mensagem; fechar o stdin o encerra. O formato de entrada não é documentado: qualquer mudança passa por teste real e vai para a seção 19.
- Bots rodam com `--setting-sources project,local` e `--strict-mcp-config`: nada de hooks, skills, modo de permissão ou MCP pessoais do dono. Aprovações passam pela tool `permission_prompt` do nosso MCP.
- Servidor MCP por HTTP: o Claude Code aborta a request em 60 s e a chamada em 5 min sem resposta, a menos que o `mcp.json` tenha `timeout` no servidor. A aprovação depende disso.
- Só o `claude.exe` nativo roda. O `claude.cmd` do npm é recusado: passar por `cmd.exe` estraga o quoting dos argumentos.
- O bot recebe o ambiente padrão do usuário (`CreateEnvironmentBlock`), nunca o do daemon: em dev o daemon herda variáveis da sessão do Claude Code (`CLAUDE_CODE_MESSAGING_SOCKET`, `ANTHROPIC_BASE_URL`...).
- PATH real pode ter aspas soltas. Separe só por `;`; `std::env::split_paths` trata aspas como agrupamento e engole o resto.
- Numa sessão interativa, os hooks só rodam depois de aceitar a confiança da pasta. Teste manual de bot novo começa pelo diálogo de confiança no terminal.
- Todo processo de bot entra num Job Object com kill-on-close.
- Todo processo de bot entra num Job Object com kill-on-close e roda sem console (`CREATE_NO_WINDOW`).
- Permissão de arquivo é ACL (SID do usuário atual), não modo Unix.
- Estado em `%LOCALAPPDATA%`, nunca `%APPDATA%` (roaming).
- Cuidado com o limite de 260 caracteres em caminhos de workspace.

## Segurança e privacidade

- Daemon só em `127.0.0.1`.
- Nunca logar token, corpo de mensagem ou saída de terminal em nível `info` ou acima. Bots podem lidar com dado pessoal e de saúde.
- Nunca logar token, corpo de mensagem, anexo ou item do chat (resposta, saída de ferramenta) em nível `info` ou acima. Bots podem lidar com dado pessoal e de saúde.
- Tokens de bot ficam no banco só como SHA-256.
- Nada de telemetria.

Expand All @@ -83,10 +81,10 @@ Em dev, use `$env:BOTLOFT_HOME = "$PWD\.dev\home"` (caminho absoluto) no daemon
Uma tarefa só está pronta quando:

1. `cargo fmt`, `clippy -D warnings` e `cargo test` passam (e `pnpm check`, se mexeu no app);
2. comportamento novo tem teste (supervisor, courier e terminal testados com `FakeRuntime`);
2. comportamento novo tem teste (supervisor, courier e chat testados com `FakeRuntime`);
3. a spec continua verdadeira;
4. o que depende do Claude Code real está listado no PR com o passo de teste manual.

## Ordem de trabalho

Siga os marcos da spec (seção 17): M0 -> M1 -> M2 -> M3 -> M4 -> M5. Não comece rotinas, caixa de perguntas, busca ou acesso remoto antes do M5.
Siga os marcos da spec (seção 17): M0 -> M1 -> M2 -> M3 -> M4 -> M4.1 -> M5. Não comece rotinas, caixa de perguntas, busca ou acesso remoto antes do M5.
96 changes: 2 additions & 94 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
"@fontsource/ibm-plex-mono": "^5.3.0",
"@fontsource/ibm-plex-sans": "^5.3.0",
"@tauri-apps/api": "^2.12.0",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-webgl": "^0.19.0",
"@xterm/xterm": "^6.0.0",
"lucide-react": "^1.48.0",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"zustand": "^5.0.15"
},
"devDependencies": {
Expand Down
Loading
Loading