Proposta de re-arquitetura · 20 Jul 2026 · análise 100% read-only — nada foi modificado

A Workroom deixa de ser um sistema operacional e vira um contrato.

Hoje a Workroom reimplementa à mão, em ~10,7 mil linhas, três camadas que o Herdr já entrega pronto neste Mac: runtime de processos/PTY, detecção de estado e liveness, e wake-up em tempo real. Esta proposta mantém intacto o que é genuinamente dela — o protocolo de coordenação, o ledger e os gates humanos — e entrega todo o resto ao Herdr.

Base: relatório Herdr Agent Factory Inventário: Collab Room real (read-only) Verificado: herdr 0.7.4 · protocolo 16 · socket ativo
10.750 LOC
sistema hoje (room + dashboard)
≈3.000 LOC
alvo: só domínio (−70%)
3 → 1
mecanismos de spawn
4 → 1
mecanismos de tempo real
90s → evento
detecção de worker morto
01 · Veredito executivo

O Herdr é o chão de fábrica.
A Workroom é o contrato social.

O relatório de pesquisa foi taxativo: “Herdr is the factory floor. It is not the foreman.” O inventário do sistema real confirmou o diagnóstico inverso: a Workroom atual construiu o chão de fábrica à mão — três vezes. A proposta é inverter isso, peça por peça.

Eliminar / delegar ao Herdr

Spawn de processos com detach + PID files + guarda via lsof; heartbeat próprio de 30s + sweep de 90s; liveness via kill(pid,0); reconciliação por polling herdr agent list a cada 5s por worker; o dashboard React de 4,3 mil linhas. ≈7,7 mil LOC saem.

Encolher drasticamente

O MCP (25 → ~18 tools), o tempo real (SSE + long-poll + heartbeat + polling → eventos Herdr + 1 stream de domínio), o dispatcher (fila em memória → fila durável na tabela; capacidade por regex em texto de erro → erro estruturado), a telemetria recomputada a cada snapshot.

Manter — é o produto

O ledger SQLite com as 13 tabelas de domínio, as 11 invariantes de coordenação, obrigações de resposta, handoffs versionados, deliverables com hash do conteúdo real, review cross-provider, gate humano, memória da sala, idempotência. Nada disso existe no Herdr — nem deveria.

Regra de ouro da proposta: o Herdr responde “onde o trabalho está rodando e como ele está”; a Workroom responde “o que deve acontecer, quem é dono e se foi aceito”. Eventos do Herdr são visibilidade e wake-up — nunca verdade. O socket do Herdr só é tocado por um adapter único dentro do hub (o broker); workers e agentes interativos jamais falam com ele diretamente.
Por que agora é barato: a Workroom tem um adapter Herdr em produção (room/herdr-runtime.mjs, 136 LOC) que spawna workers de implementação via herdr agent start — ou seja, a “Fase 0” do plano do relatório já aconteceu organicamente. E já existe até um workspace Herdr chamado workroom-herdr-pivot com um pane rotulado workroom-hub: a tentativa anterior de migrar o hub para dentro do Herdr só parou num bloqueio de permissão de socket dentro do sandbox do worker. Esta proposta retoma exatamente esse fio.
02 · O que existe hoje

Um sistema operacional escrito à mão

A Collab Room real, mapeada read-only em …/2026-07-18/https-x-com-devjuninho-status-…/room/: 6.404 LOC em room/*.mjs + 4.343 LOC de dashboard React + hooks de lifecycle + 13 tabelas SQLite. O hub estava vivo na porta 4789 durante toda a inspeção — e continua intacto.

Claude Code/DesktopCodex App/CLIPi mcp.mjs — MCP stdio room-hook.mjs hub.mjs · :4789 store.mjs · 2.031 LOC room.sqlite3 seam.mjs runner.mjs · 368 LOC codex exec / claude -p work-dispatch.mjs herdr CLI Dashboard React :3000 · 4.343 LOC MCP + hooksMCP + hooksMCP + hooks 25 tools · heartbeat 30s próprio lifecycle HTTP + SSE + long-poll hand-rolled 13 tabelas · invariantes WAL · 2 MB+ ensureHub + spawnRunner detached + PID file fila em memória (Map) poll agent list 5s TanStack · SSE + long-poll spawn+pidfile spawn+pidfile poll O(N) 5s fluxo de domínio infra hand-rolled que sai fica (domínio ou Herdr)
3 mecanismos de spawn · 4 mecanismos de tempo real · 2 fontes de verdade sobre liveness — tudo mantido à mão

Onde estão as linhas

dashboard src/ (React 19 · TanStack)
4.343
store.mjs (ledger + ações)
2.031
testes room/*.test.mjs
1.827
work-dispatch.mjs
471
mcp.mjs (25 tools)
465
seam.mjs
387
runner.mjs
368
hub.mjs
216
herdr-runtime.mjs (adapter)
136
telemetry.mjs
114
names.mjs
79
doctor · talk-cli · e2e · demo
150

verde fica  vermelho sai ou encolhe  azul neutro

As três camadas que o Herdr já resolve — e a Workroom refez à mão

1 Runtime de processos

3 mecanismos de spawn coexistindo: Herdr para workers de implementação; spawn(detached) + PID file + guarda lsof para o hub e os reply runners; pipes com timeout SIGKILL para os CLIs dos providers. O próprio relatório de cutover proíbe o padrão detached para o hub — mas ele ainda é o padrão.

2 Estado & liveness

Heartbeat próprio de 30s no MCP bridge; sweep markStaleAgents a cada leitura com cutoff de 90s; liveness via kill(pid,0); SESSION_IDENTITY.json + hooks de cleanup por sessão; estado de stall derivado em três lugares que precisam concordar.

3 Tempo real & wake-up

Tabela events + SSE /events hand-rolled + long-poll /api/wait + polling de resposta a cada 20s + reconciliação Herdr por shell-out O(N) a cada 5s por dispatch — sem usar nenhum evento push que o Herdr já oferece.

Dores concretas encontradas no inventário (amostra das 14)

  • Fila de dispatch volátil: pendingDispatches é um Map em memória do hub — restart perde a fila (durabilidade declarada: “re-despacha manual”).
  • Capacidade sinalizada por texto de erro: o dispatcher faz regex na mensagem work capacity is exhausted para decidir enfileirar ou rejeitar.
  • Aprovação por regex em texto livre: decideApproval casa padrões EN/PT (aprovo|autorizo…) no corpo de uma mensagem — frágil a paráfrase.
  • Migrações ad-hoc: ALTER TABLE condicional coluna a coluna, sem tabela de versão.
  • Estado sem retenção: events (1.499 linhas), idempotency (996), agents (231) só crescem.
  • Identidade por heurística two-provider no MCP — quebra silenciosamente com uma terceira identidade.
Importante: nada disso é incompetência — é o custo natural de construir chão de fábrica à mão. O relatório de pesquisa mostrou que esse chão já existe produtizado (Herdr, rodando neste Mac, versão estável). A pergunta certa não é “consertar cada dor”, é deletar a camada inteira.
03 · O que o Herdr entrega

Verificado no binário instalado — não na documentação

Cada capacidade abaixo foi confirmada por sondagem read-only do herdr 0.7.4 deste Mac (helps, api schema com 85 métodos, api snapshot, estado ao vivo: 7 workspaces, 2 agentes). Server rodando, socket ~/.config/herdr/herdr.sock, protocolo 16.

Spawn de agentes gerenciados

PTY persistente server-owned, com cwd, workspace, env e split — attachável depois.

herdr agent start <nome> --cwd … --workspace … --env K=V -- <argv>
Estado semântico dos agentes

idle / working / blocked / done / unknown, com roll-up em workspace, tab e snapshot. Autoridade: hooks de integração > manifests de tela.

herdr agent list · agent get · pane.agent_status_changed
Stream de eventos push

26 tipos assináveis, incluindo os dois que hoje são polling na Workroom.

events.subscribe → pane.agent_status_changed · pane.output_matched · pane.exited
Waits bloqueantes

Espera nativa por texto/regex na saída ou por mudança de status — substitui loops de polling.

herdr wait output <pane> --match/--regex · wait agent-status · events.wait
Leitura e envio de texto

Lê tela do agente (visible/recent) e envia texto ou teclas — base do “acordar” um agente.

herdr agent read/send <alvo> · pane send-text/send-keys/run
Worktrees gerenciados

Cria checkout + workspace Herdr num passo; remove sem deletar a branch. Um worktree por task vira uma linha.

herdr worktree create/open/list/remove · [worktrees] directory
Attach humano estável

O humano entra em qualquer worker a qualquer momento — local ou via SSH. Hoje isso é impossível com runners detached.

herdr agent attach <alvo> [--takeover] · herdr --remote <ssh>
Notificações de atenção

A “attention queue” que a pesquisa comunitária elegeu como O valor — nativa.

herdr notification show <título> [--sound done|request]
Plugins out-of-process

11 métodos plugin.*, panes custom, event hooks — o caminho nativo para um painel Workroom dentro do Herdr.

plugin.link · plugin.pane.open · event hooks (herdr-plugin.toml)
API completa + schema descobrível

85 métodos NDJSON sobre unix socket; snapshot do estado inteiro; schema JSON do binário.

herdr api snapshot · herdr api schema --json
Report de estado/metadata

Pane/workspace reportam agente, estado, título e tokens — a Workroom pode anotar a frota sem tabela própria de presença.

pane report-agent/report-metadata · workspace report-metadata
Sessões nomeadas + live handoff

Isolamento hard por sessão quando preciso; panes sobrevivem a restart do server.

herdr --session workroom · server live-handoff
Fila / scheduler / DAG — NÃO existe

Confirmado: zero ocorrências de queue/schedul no schema de 235 KB. Leases, roteamento, capacidade, prioridade → ficam na Workroom. É exatamente o que o relatório manda construir por cima.

grep "queue|schedul" no schema → 0 · agent_panel_sort="priority" é só ordenação visual
Verdade sobre tasks — NÃO é dele

Eventos Herdr são visibilidade e wake-up. Aceite, review, aprovação e memória ficam no ledger da Workroom (seção 06).

“Herdr is the factory floor. It is not the foreman.”
0 integrações instaladas hoje

Status de agente hoje vem de manifests de tela (menos autoritativo). Quick win da Fase 1: instalar as integrações claude + codex para status por lifecycle hooks.

herdr integration status → 14 suportadas, 0 instaladas
04 · Mapa de substituição

Peça por peça: o que o Herdr absorve

Cada linha: a peça custom de hoje (com evidência no código), o substituto nativo verificado, e o destino. eliminar encolher manter

A

Runtime & spawn

o fim dos PID files
seam.mjs · ensureHub()spawn detached do hub + guarda lsof + retry 20×250msseam.mjs:56–89 · padrão proibido pelo próprio cutover report
Hub como agente Herdr gerenciadoherdr agent start workroom-hub -- node room/hub.mjs — supervisionado, attachável, PTY persistenteretoma o cutover bloqueado (workspace w2 “workroom-herdr-pivot”)
eliminar−60 LOC + dor
seam.mjs · spawnRunner() + writePidFilereply runners detached, liveness por kill(pid,0)seam.mjs:99–122, 382+
Reply lanes como panes Herdr persistentesherdr agent start sol-reply --env COLLAB_ROOM_* — estado semântico nativo e agent attach para o humano olharagent start --workspace --env · attach estável
eliminar−120 LOC
runner.mjsspawn de codex exec/claude -p com pipes, timeout SIGKILL, cwd sandbox, build de promptrunner.mjs · 368 LOC
Worker Herdr com brief canônicocomando do provider pinned pelo dispatcher (já existe p/ implementação); prompt vira template, não processocanonicalWorkerPrompt() já faz isso p/ work dispatches
encolher368 → ~80 LOC
work-dispatch · reconciliação por pollingshell-out herdr agent list completo a cada 5s por dispatch ativowork-dispatch.mjs:165, 447–469
Assinatura de eventosevents.subscribe em pane.agent_status_changed/pane.exited + events.wait — reconcilia dirigida a evento, não a timer26 tipos de evento · protocolo 16
encolherpoll loop morre
herdr-runtime.mjs (adapter)a peça certa que já existe: workspace, start, inspect, stop via CLIherdr-runtime.mjs · 136 LOC · em produção
Vira o único broker do socket+ events.subscribe, worktree.*, notification.show; NDJSON direto no socket em vez de shell-out por chamadaherdr.sock · 85 métodos · schema descobrível
manter+136 → ~250 LOC
B

Presença & liveness

o fim do heartbeat de 30s
room_heartbeat (tool MCP + timer 30s)cada bridge MCP emite heartbeat enquanto vivamcp.mjs heartbeatTimer · PROTOCOL.md realtime
Presença = projeção do Herdragent list sob demanda + pane.exited = morte instantânea. Sem timer, sem sweeppane.exited · pane.agent_status_changed
eliminartool sai do MCP
markStaleAgents() — sweep 90smarca stale a cada snapshot por last_seen_atstore.mjs:1625–1628
Liveness derivado de eventoo Herdr é dono do PTY: se o processo morreu, ele sabe na hora — a Workroom assina, não varrefase de trabalho continua vindo dos checkpoints (reading/editing/…)
eliminarsweep morre
SESSION_IDENTITY.json + hooks de cleanupidentidade de sessão por arquivo + hooks por providerscripts/room-hook.mjs
Identidade mora no panepane report-agent --agent "Sol (direct)" --state … + report-metadata com tokens — sem arquivo, sem cleanuppane report-agent/report-metadata
encolherhooks viram 1 linha
doctor.mjs · checkPidhealth por PID file + /healthdoctor.mjs · 38 LOC
Health por Herdr + domínioherdr status + api snapshot + /health do hubherdr status [server|client]
encolher38 → ~20 LOC
C

Tempo real & wake-up

4 mecanismos → 1
SSE /events hand-rolledkeepalive 25s, replay por Last-Event-ID, fan-out manualhub.mjs:146–167
1 stream de domínio + eventos Herdrruntime wake vem do Herdr; o SSE que sobra carrega só eventos de domínio para o painelevents.subscribe (herdr) + /events enxuto (domínio)
encolherresponsabilidade −80%
long-poll /api/wait + waitForEventwaiters com setTimeout clamp 30shub.mjs:83–98, 139–145
events.wait do Herdrbloqueio nativo com filtro e timeout; para domínio, consulta direta ao ledgerevents.wait · 19 tipos de match
eliminarendpoint morre
get_answer com polling de 20sawaitAnswer em loop sobre snapshotseam.mjs:201–228
talk com wait híbridopane.output_matched / agent_status_changed acordam na hora; ledger confirma a respostaget_answer funde em talk · −1 tool
encolherpolling → push
tabela events como mecanismo de wake1.499 linhas e crescendo, alimenta SSE + long-poll + telemetriastore.mjs:251–258
Audit log / outbox purocontinua canônica para domínio, mas para de ser barramento de wake; ganha política de retençãoalinha com “transactional outbox” do relatório
manter papel+ retenção
D

Superfície — UI & MCP

a maior economia única
Dashboard React 19 + TanStack4 views (board/conversations/memory/telemetry), Vite, shadcn — um app web inteiro para ver a frotasrc/ · 4.343 LOC · porta 3000
Painel como plugin Herdrplugin.pane.open + event hooks: o board mora no chão de fábrica, com attention queue nativa. Alternativa conservadora: congelar o app lendo só /api/snapshotplugin.* · padrão comunitário (Cmd+P command center)
eliminar−4.343 LOC
mcp.mjs — 25 toolsinclui heartbeat, wait, get_answer, live_fleet_status…mcp.mjs · 465 LOC
MCP fino — ~18 toolssaem room_heartbeat, room_wait, get_answer, live_fleet_status; room_claim_reply/room_reply fundem em respond; identidade sem heurística two-providertools de domínio ficam intactas
encolher465 → ~300 LOC
live_fleet_status + task-detail paginadoprojeções keyset por streamstore.mjs:1464–1623
Projeções sob demandafrota viva vem do api snapshot do Herdr cruzado com o ledger; detalhe de task permanece, mas simplesmenos código de paginação hand-rolled
encolher−50%
telemetry.mjsrecomputa métricas e traces a cada snapshottelemetry.mjs · 114 LOC · store.mjs:1461
Contadores derivados + métricas Herdrqueue age, lease e stall saem do ledger sob demanda; estado da frota vem do Herdralertas do relatório: queue age, lease-expiry, event-stream lag
encolher114 → ~60 LOC
E

Domínio — fica e endurece

é o produto, não é plumbing
store.mjs — ledger + ações de domíniotasks, obrigações, handoffs versionados, deliverables com hash do conteúdo real, reviews cross-family, approvals, memória, idempotência, 11 invariantes2.031 LOC · o coração do produto
Fica — enxutosaem apenas os guards de runtime que viram projeção Herdr (stale sweep, liveness); invariantes e gates intactosseção 06 detalha por quê não delegar
manter~1.600 LOC
pendingDispatches — fila em memóriarestart do hub perde a filawork-dispatch.mjs:175, 296–352
Fila durável na tabela work_dispatchesestados queued→leased→running na mesma tabela que já existe; Postgres + SKIP LOCKED só quando multi-hostexatamente o que o relatório prescreve (Fase 1)
manter+endurece
decideApproval por regex EN/PTautorização casada em texto livrestore.mjs:1366–1378
Aprovação por ato explícitobotão no painel / approval_decide direto do humano; a regex vira fallback legado, não o caminhohumano continua gate final — invariante #8
manter+endurece
names.mjs · PROTOCOL.md · SKILL.mdidentidades, rubrica R1–R4, ritos da sala79 LOC + docs
Fica — com uma ediçãoo SKILL.md hoje diz “Herdr é plumbing escondido”; vira “Herdr é o runtime oficial — o MCP fino continua a superfície de coordenação”a cultura não muda; a fiação sim
manterintacto

A conta

10.750
LOC hoje (6.404 room + 4.343 dashboard)
≈3.000
LOC alvo: store enxuto + MCP fino + adapter + dispatch
−70%
de código para manter
0
PID files e timers de liveness na v2
O que sobra é só o que nenhum produto pronto faz: o protocolo de coordenação entre agentes — fila durável, roteamento R1/R2, obrigações, handoffs, reviews, aprovações, memória. ~3 mil linhas de domínio puro, testáveis, sem um único PID file.
05 · Arquitetura-alvo

Duas zonas, uma fronteira nítida

Em cima, o que é seu e fica: o protocolo. Em baixo, o que é produto e absorve: o runtime. A fronteira é um adapter único — o único processo que fala com o socket do Herdr.

DOMÍNIO — fica (≈3.000 LOC) HERDR — delega (produto, 0 LOC sua) Humano — Herdr GUI: attention queue · attach · notificações Agentes interativos — Claude · Codex · Pi (MCP + hooks) MCP fino — ~18 tools de domínio Painel Workroom — plugin Herdr Hub de domínio — store + invariantes + fila durável + gates SQLite — só tabelas de domínio HerdrAdapter — único broker do socket herdr.sock — NDJSON · 85 métodos Herdr server — workspaces · panes/PTYs · worktrees · status · notify Workers — herdr agents · 1 worktree por task · reportam via integração collab-room v2 · sem heartbeat/wait/polling plugin.pane.open + event hooks · lê /api/snapshot roda SOB o Herdr (herdr agent start workroom-hub) tasks · obrigações · handoffs · reviews · approvals · memória herdr-runtime.mjs ampliado · events.subscribe events.wait · agent/worktree/notification já instalado: 0.7.4 stable · protocolo 16 attach · attention cmds eventos
azul = domínio Workroom (fica) · verde = Herdr (delega) · tracejado = acesso humano direto pelo Herdr

As três regras da fronteira

1 Broker único

Só o HerdrAdapter (dentro do hub) fala com herdr.sock. Workers nunca recebem acesso ao socket — recebem comandos estreitos via MCP/brief. É o controle #1 do relatório (“broker the Herdr socket”) e hoje ele é impossível porque cada processo faz shell-out livre.

2 Eventos ≠ verdade

Eventos Herdr acordam e informam; quem decide é o ledger. pane.exited dispara reconciliação — mas é o hub que marca a task, aplica o lease e re-enfileira. Nuance verificada: done é estado de atenção da UI; para automação de conclusão, espera-se idle.

3 Um writer por worktree

Cada task de implementação: um worktree Herdr (worktree.create), uma branch, um dono, um lease — exatamente o isolamento que o relatório e o padrão comunitário (worktrees por milestone/epic) recomendam.

O ciclo de uma task na v2

  • 1. Orquestrador: task_createtask_dispatch (MCP fino). O hub clama atomicamente e grava queued na tabela — durável desde o nascimento.
  • 2. Hub → HerdrAdapter: worktree.create + agent start com brief canônico e env COLLAB_ROOM_*. Lease abre no ledger.
  • 3. Worker checkpointa fases (reading/editing/testing/submitting) via MCP; o Herdr reporta agent_status por eventos. Silêncio além do threshold → stalled (regra já existente, agora com detecção imediata).
  • 4. Entrega: deliverable_submit (hash do conteúdo real) → review cross-provider → gate humano → merge. O pane do worker permanece attachável até o cleanup.
  • 5. Humano acompanha tudo pelo painel Herdr (plugin) + notificações de atenção — sem abrir um app web separado.
06 · O que não muda

O Herdr não é o encarregado — e é por isso que estas peças ficam

O relatório verificou duas vezes: fila, scheduler, leases, autorização e memória não existem no Herdr (grep no schema de 235 KB: zero). É exatamente aí que a Workroom é um produto, não plumbing.

Ledger SQLite canônico

As 13 tabelas de domínio continuam a única verdade. SQLite é suficiente para single-host (veredito do relatório); Postgres + SKIP LOCKED só quando houver controllers concorrentes/multi-host.

As 11 invariantes

Claim atômico; dono responsável até handoff aceito; efeitos idempotentes; review target = hash do conteúdo real; stale handoff não sobrescreve versão nova. Nada disso é terceirizável.

Review cross-provider + gate humano

Anti-self-review, família diferente aprovando, humano como gate final. Um gerenciador de terminal não decide aceite — nem deve.

Memória da sala

Decisões, constraints e procedimentos com supersession e proveniência. “Novas sessões não são novos contratados com amnésia.”

Fila, leases, roteamento, capacidade

O scheduler que o Herdr deliberadamente não tem: rubrica R1/R2, lanes reply/work, prioridade, backpressure. Endurece: a fila sai do Map em memória para a tabela.

Envelopes causais + idempotência

Hops, depth, visited, request hash contra replay alterado. At-least-once por construção, efeitos observáveis idempotentes.

Traduzindo a tese do relatório para cá: o Herdr pode start, observe, read, signal e wait em agentes — isso torna a orquestração possível, mas não decide o que é seguro despachar nem quando o trabalho é aceito. A Workroom v2 é exatamente essas duas decisões, e mais nada.
07 · Plano em fases

Quatro fases — e a primeira já aconteceu

Mapeado sobre as fases do relatório (adapter spike → fila local segura → handoffs → failure drills), ajustado à realidade encontrada: o spike já está em produção.

Fase 0 · Adapter spike já existe

O herdr-runtime.mjs (136 LOC) já provisiona workspace, spawna workers e reconcilia estado — com testes. O que falta é disciplina de versão:

  • Pinnar herdr 0.7.4 / protocolo 16 / schema_version 1 e gravar o api schema no repo (o relatório manda registrar o observado).
  • Gate de compatibilidade no boot do hub: protocolo inesperado → degraded mode explícito, nunca falha silenciosa.
Critério de saída: boot do hub verifica protocolo == 16 e registra o schema versionado.

Fase 1 · Tudo sob o Herdr ~1 semana

  • Retomar o cutover bloqueado: hub como herdr agent start workroom-hub — de um contexto privilegiado (a lição do cutover report: nunca de dentro de worker sandboxed).
  • Reply lanes como panes persistentes; morrem os PID files, o detached spawn, o lsof e o kill(pid,0).
  • herdr integration install claude + codex → status por lifecycle hooks (autoridade maior que manifest de tela).
  • Fila de dispatch durável na tabela work_dispatches; capacidade com erro estruturado (fim da regex em mensagem).
Critério de saída: herdr agent list mostra hub + lanes; restart do hub não perde um único dispatch enfileirado; zero PID files no repo.

Fase 2 · Eventos nativos ~1 semana

  • Adapter assina pane.agent_status_changed, pane.exited, pane.output_matched; reconciliação vira dirigida a evento.
  • Apagar: heartbeat de 30s, sweep de 90s, polling de 5s por dispatch, polling de 20s do get_answer (funde em talk com wait híbrido).
  • notification.show para obrigação de resposta vencendo e para approval pendente — a attention queue trabalha para o humano.
Critério de saída: worker morto detectado por evento (<2s); canário de 3 workers concorrentes pelo MCP (regra já existente no SKILL.md); nenhum timer de liveness no código.

Fase 3 · Superfície fina + drills ~1–2 semanas

  • MCP 25 → ~18 tools; identidade sem heurística two-provider.
  • Painel Workroom como plugin Herdr (plugin.pane.open + event hooks) — ou, na rota conservadora, dashboard congelado lendo só /api/snapshot.
  • Aprovação por ato explícito no painel; regex EN/PT vira fallback legado.
  • Failure drills do relatório: restart do hub, restart do Herdr, worker órfão, quarentena de ambíguo, retry storm — com reconciliação antes de re-despachar.
Critério de saída: drills verdes; LOC de infra −60% ou mais; retro do fleet-principal medindo rework-rate por modo (R4) como antes.
08 · Riscos e limites

O que pode dar errado — e a contenção

RiscoContenção propostaPrioridade
Workers falando direto com o herdr.sockbypass do broker — controle #1 do relatórioSó o hub carrega o adapter; workers recebem env sem HERDR_SOCKET_PATH e comandos estreitos via MCP/brief; audit no ledger.P0
Restart do Herdr com workers vivosestado ambíguo pós-restartReconcile before dispatch: comparar leases do ledger × api snapshot; quarentenar o que for ambíguo antes de criar replacements. Live-handoff existe mas é opt-in.P0
Cutover executado de dentro de worker sandboxedfoi exatamente o blocker de 20 Jul: PermissionDenied no socketOperações de cutover/migração só de contexto privilegiado (sessão interativa do humano), nunca despachadas como task.P0
Confundir done com conclusãonuance verificada no binário“done é estado de atenção da UI”: automação espera idle + evidência no ledger; nunca aceitar por status visual.P1
Drift de versão do Herdrupdate muda protocolo/schemaPin 0.7.4/16 + gate no boot + schema gravado no repo; canal stable; update vira mudança revisada, não surpresa.P1
Plugin do painel é supply chainmarketplace herdr não é curadoPlugin próprio, revisado, sem auto-fetch de manifests remotos após baseline; roda com os mesmos privilégios do usuário — tratar como código de produção.P1
Herdr como SPOF do runtimeDegraded mode já existe no SKILL.md (trabalha desconectado, reporta backlog); fila durável sobrevive ao Herdr cair; hub responde “indisponível” honesto em vez de fingir.P1
09 · Métricas

Antes → depois, medível

MétricaHojeAlvo v2
LOC de infra para manter10.750 (room 6.404 + dashboard 4.343)≈3.000 (−70%)
Mecanismos de spawn3 (herdr, detached+pidfile, pipes)1 (herdr)
Mecanismos de tempo real4 (SSE, long-poll, heartbeat, polling)eventos Herdr + 1 stream de domínio
Detecção de worker mortosweep de 90sevento pane.exited (<2s)
Wake de replypolling 20spush (output_matched / status)
Attach humano em workerimpossível (detached)herdr agent attach
Tools MCP25~18
Integrações de status instaladas0 (manifest de tela)2+ (claude, codex — lifecycle)
Fila de dispatchMap em memória (volátil)durável na tabela
Supervisão de hub/runnersPID files + lsof + operadorherdr server

As métricas de domínio não mudam: rework-rate por modo (R4), accept-rate e time-to-catch dos principals, reply P50/P95, queue age — agora derivadas sob demanda em vez de recomputadas a cada snapshot.

10 · Fontes, método e decisões abertas

Como esta proposta foi construída

Três frentes de investigação em paralelo, todas 100% read-only — nenhum arquivo do sistema, processo ou banco foi modificado; o SQLite foi inspecionado numa cópia em /tmp.

outputs/herdr-agent-factory-research.html — relatório de pesquisa Herdr Agent Factory (a análise encomendada)
work/analysis/room-inventory.md — inventário completo da Collab Room: 17 módulos, 25 tools MCP, 13 tabelas, 14 pontos de complexidade
work/analysis/herdr-capabilities.md — sondagem do herdr 0.7.4: 85 métodos, 26 eventos, matriz a–j com comandos exatos
work/analysis/research-synthesis.md — síntese fiel do relatório: arquitetura, contratos, fases, segurança
Código-fonte lido em primeira mão: room/{PROTOCOL.md, mcp.mjs, herdr-runtime.mjs, store.mjs (schema), hub.mjs, work-dispatch.mjs} + cutover report 20260720T013853Z

Decisões que são suas (não ousei decidir por você)

? Painel: plugin Herdr ou web congelado?

Plugin é o padrão comunitário e vive no chão de fábrica, mas é supply chain e código novo. O web app existe hoje e funciona — congelá-lo lendo só /api/snapshot custa zero. Minha recomendação: começar congelado, plugin na Fase 3 se fizer falta.

? Reply lane: pane persistente ou runner sob Herdr?

Pane persistente por identidade é o ideal (attachável, observável); manter o runner.mjs apenas spawnado pelo Herdr é o passo intermediário seguro. Propus o intermediário na Fase 1 e o ideal como evolução.

? Sessão Herdr default ou nomeada “workroom”?

O relatório recomenda sessão compartilhada por default e nomeada só para isolamento hard. Como o hub+workers são infra, uma sessão workroom separada da sua sessão interativa pode ser mais limpa — mas custa um segundo socket.

? SQLite agora, Postgres quando?

O relatório: SQLite OK single-host; Postgres obrigatório para controllers concorrentes/multi-host. Hoje você é single-host — eu ficaria no SQLite e deixaria a migração como decisão registrada na memória da sala.

Nada aqui foi aplicado. Esta proposta não tocou em nenhum arquivo do sistema, não parou nenhum processo, não escreveu no ledger. O hub continua vivo na 4789, os runners continuam detached com seus PID files, e o dashboard continua na 3000 — exatamente como encontrei. A decisão de executar as fases é sua.