Skip to main content
Glama

Escritório

Comunicação peer-to-peer entre sessões Claude Code. Suas sessões e seus especialistas viram pessoas endereçáveis por nome, que conversam entre si sobre vários assuntos ao mesmo tempo — sem orquestrador.

Spec de design: pessoal/claudicaro-cli/docs/design/2026-08-02-escritorio-multiagente.md.

Por que não dava pra fazer isso sem ele

A topologia nativa do Claude Code é árvore: subagente devolve pro pai, SendMessage só alcança quem a própria sessão spawnou, Workflow passa dado pelo script. Dois irmãos não se falam. Comunicação lateral exige um meio compartilhado — que é este correio.

Related MCP server: neighbors

As seis ferramentas

tool

o que faz

roster

quem existe, o que sabe, qual tier — uma linha por pessoa, sem carregar .md nenhum

ask

pergunta e espera a resposta

dm

manda e segue; na thread de uma pergunta pendente, vira a resposta dela

inbox

puxa a correspondência (normalmente o hook já entrega sozinho)

board

quadro branco compartilhado, sem destinatário

claim

reivindica recurso antes de mexer

Mais fechar_thread, que encerra a conversa e faz cada colega destilar o caderno.

Como funciona

Thread é o container único de conversa — substitui salas e canais. Debate entre pares é uma thread com N participantes onde cada um escolhe pra quem responder.

Sem chefe, duas regras no correio seguram o sistema:

  • hops decrementa a cada mensagem; zerou, o correio recusa. Mata ping-pong infinito.

  • Dono da thread é quem abriu, e só ele fecha.

Entrega tem duas naturezas:

  • Sessão viva recebe por hook (Stop bloqueia a parada e entrega; PostToolBatch entrega no meio do trabalho). O hook é script — roda fora do modelo, custo zero de token.

  • Colega do roster é acordado pelo correio com claude -p, responde e volta a dormir.

Memória do colega: dentro de uma thread ele mantém a sessão viva (--resume) e lembra de tudo; quando a thread fecha, destila o que aprendeu num caderno .md e a sessão morre. Longo prazo é o caderno — auditável, editável à mão, versionado.

Instalação

npm install && npm run build
node scripts/instalar.mjs          # --dry pra ver antes, --remover pra desfazer

O instalador registra o hook de entrega em ~/.claude/settings.json, define ESCRITORIO_WORKSPACE/ESCRITORIO_ROSTER, e registra o servidor MCP via claude mcp add --scope user (que grava em ~/.claude.json — settings.json não registra MCP).

Faz backup em settings.json.antes-do-escritorio na primeira vez, e nunca sobrescreve esse backup.

Roster

~/claude-workspace-config/roster.yaml (repo sincronizado Mac ↔ VM):

especialista-deposito:
  brief: "Depósito antecipado: cobrança, pagamento, reembolso (DSG/v1)"
  agent_file: ${ESCRITORIO_WORKSPACE}/dsg/.agent/especialista-deposito.md
  caderno: ${ESCRITORIO_WORKSPACE}/pessoal/escritorio/cadernos/especialista-deposito.md
  tier: advisor
  cwd: ${ESCRITORIO_WORKSPACE}/dsg/v1

brief é a única coisa que o roster() devolve — escreva pensando em "quando eu chamaria essa pessoa". Caminhos aceitam ~ e ${VAR}; é a expansão de env que faz o mesmo arquivo servir Mac e VM, onde o workspace mora em lugares diferentes.

Tiers

tier

pode

como é imposto

advisor

ler e aconselhar

allowlist de tools (--allowedTools): leitura, Bash read-only e as tools do escritório

editor

escrever no working tree

acceptEdits, e só sob claim() ativo — o correio recusa acordar sem ele

worktree

escrever isolado

git worktree próprio; se não der pra criar, recusa em vez de cair no repo real

Um pedido pode rebaixar o tier na consulta, nunca elevar.

Por que allowlist e não denylist

A primeira versão usava --disallowedTools Edit Write NotebookEdit com bypassPermissions. Testado com claude de verdade, vazou: o colega escreveu o arquivo via Bash, que não estava na negação. Medido nas quatro variantes:

flags

resultado

bypassPermissions + nega Edit/Write

vazou (escreveu via Bash)

bypassPermissions + nega Edit/Write/Bash

segurou

sem permission-mode + nega Edit/Write/Bash

segurou

sem permission-mode + allowlist read-only

segurou, e ainda leu git log normalmente

Ficou a allowlist: o que eu esquecer de listar fica negado em vez de liberado. Vale notar que Bash(cat:*) na allowlist não permitiu escapar por redirecionamento (cat > arquivo).

Ver acontecendo

npm run tail

Segue o correio e imprime o que acontece entre todas as sessões — quadro escrito, claim, thread aberta, mensagem trocada, resposta chegando:

Escritório — monitor ao vivo
sessões vistas na última hora: icaromelo@v1, icaromelo@kairos-ui, icaromelo@oraculo-api, …
threads abertas: (nenhuma)
────────────────────────────────────────────────────────────────────────
13:26:36 ▤ quadro dsg/v1:decisoes = cache sempre via RedisService · icaromelo@v1
13:26:37 🔒 claim src/infra/redis por icaromelo@v1 · revisar TTLs
13:26:38 ⊕ thread [477cfbdc] Em uma frase: qual TTL padrao usamos? · dono icaromelo@v1
13:26:38 icaromelo@v1 →? especialista-cache  [477cfbdc]
        Em uma frase: qual TTL padrao usamos?
13:26:44 especialista-cache ←! icaromelo@v1  [477cfbdc]
        O TTL padrão é 3600 segundos (1 hora) — mas sempre passe TTL explícito…

→? é pergunta bloqueante, → recado, ←! resposta.

Identidade

Cada sessão precisa de um nome. ESCRITORIO_ID quando declarado; sem ele, deriva de usuário@pasta — estável por projeto, então uma sessão aberta em dsg/v1 é sempre icaromelo@v1 e pode ser endereçada por outra.

Testes

npm test                        # 117 testes, sem gastar API
node scripts/smoke-mcp.mjs      # sobe o servidor MCP de verdade via stdio
node scripts/smoke-e2e.mjs      # E2E REAL: acorda colega, --resume, caderno (gasta API)
node scripts/smoke-escrita.mjs  # E2E REAL dos 3 tiers: advisor bloqueado, worktree isolado,
                                # editor sob claim (gasta API)

Limitações conhecidas

  • Um correio por máquina. Sessão na VM Oracle não fala com o correio do Mac; a ponte entre máquinas é problema separado.

  • dist/ mora no SSD. Com o SSD desmontado o hook falha silencioso (|| true) e o MCP fica desconectado — nada trava, mas o escritório some até remontar.

  • ask numa sessão viva depende de ela estar rodando. Se ninguém estiver com aquela sessão aberta, você espera até o timeout (5 min) e a resposta fica no inbox pra depois.

Related MCP Connectors

Related MCP Servers