Tela de Plano (Plan Canvas)
Loop de revisão para planos e artefatos visuais: você escreve o artefato, o humano revisa no navegador — anotando o elemento exato a que se refere, conversando e entregando um veredito de Aprovar plano / Solicitar alterações — enquanto você bloqueia em uma única chamada CLI que retorna o feedback como JSON.
Inspirado por lavish-axi; reconstruído
como nativo do ECC em torno do portão de confirmação /plan, com zero dependências.
Quando Usar
- Você acabou de escrever um artefato de plano (
.claude/plans/*.plan.mddo/plan) e precisa da decisão CONFIRMAR/aprovar — o veredito da tela substitui um "sim/prossiga" digitado. - O usuário deve apontar o que alterar: revisando designs, comparações,
relatórios, ou qualquer artefato
.md/.htmllocal. - O usuário pede
/plan-canvas, uma revisão visual, ou "abra no navegador".
NÃO use para: revisão de código de diffs (/code-review), aplicativos web em execução, ou
URLs remotas. A tela serve apenas arquivos de artefato locais.
Como Funciona
Invoque a CLI como ecc-plan-canvas — o binário fornecido pelo pacote ecc-universal
(no PATH após uma instalação global/plugin; node "$CLAUDE_PLUGIN_ROOT/scripts/plan-canvas.js"
também funciona para instalações via plugin). Execute-o a partir do projeto que você está
revisando; funciona de qualquer diretório de trabalho. Ele gerencia um servidor loopback
desacoplado (127.0.0.1:4517) compartilhado por todas as sessões, indexado pelo caminho
do artefato — sem IDs de sessão para rastrear.
O fluxo de trabalho é um simples loop CLI-mais-JSON, portanto é agnóstico de modelo e
plataforma: qualquer agente que possa executar um comando shell e ler stdout o utiliza
da mesma forma (Claude Code, Codex, Cursor, Gemini, OpenCode, Copilot). Acione-o como
sua plataforma expõe skills — ex.: /plan-canvas no Claude Code, $plan-canvas no
Codex — ou apenas execute os comandos ecc-plan-canvas diretamente.
# 1. Abra o artefato no navegador do usuário (retorna imediatamente)
ecc-plan-canvas open .claude/plans/feature.plan.md
# 2. Bloqueie até o humano responder. Deixe executando; execute novamente se interrompido:
# feedback enfileirado nunca é perdido.
ecc-plan-canvas await .claude/plans/feature.plan.md
Fique ouvindo, senão o humano fala com uma cadeira vazia
O feedback só chega até você enquanto um await está estacionado na sessão.
Se sua vez terminar sem nada ouvindo, a mensagem fica na fila e, do lado do humano
na tela, o envio parece não fazer nada.
Portanto, execute await como tarefa em segundo plano quando sua plataforma
suportar (no Claude Code, uma chamada Bash com run_in_background: true). Ela
encerra no momento em que o feedback chega e a plataforma entrega o JSON, o que
mantém o loop vivo entre as rodadas em vez de morrer com a chamada em primeiro plano.
Um await em primeiro plano também funciona, mas apenas até o limite de tempo da
plataforma.
Existem duas salvaguardas, e nenhuma é desculpa para ignorar o acima:
ecc-plan-canvas pendinglista feedback enfileirado sem ouvinte. Verifique-o sempre que não tiver certeza se perdeu algo.- O gancho
stop:plan-canvas-pendingbloqueia o fim da sua rodada enquanto houver feedback da tela não entregue e entrega as mensagens. Se você está lendo feedback desse gancho, parou de ouvir cedo demais.
await imprime JSON quando o humano age:
{
"status": "feedback",
"items": [
{ "kind": "annotation", "text": "Divida isso em duas fases",
"anchor": { "selector": "h2:nth-of-type(3)", "tag": "h2", "snippet": "Fase 2: Migração" } },
{ "kind": "verdict", "verdict": "request-changes" }
]
}
kind: "chat"— mensagem livre; responda na tela, não no terminal.kind: "annotation"— feedback ancorado a um elemento (anchor.selector,anchor.snippetmostram o que apontaram;anchor.textRange.textquando destacaram uma passagem).kind: "verdict"—approvesignifica que o plano está CONFIRMADO: pare de consultar, encerre a sessão e comece a implementar.request-changessignifica revisar o artefato (a tela recarrega ao vivo) e manter o loop ativo.
3. Sempre responda na tela, depois continue ouvindo. Um comando faz ambos:
ecc-plan-canvas await <arquivo> --reply "Dividi a Fase 2 como solicitado. Dê uma olhada."
Cada mensagem humana recebe uma resposta na tela, mesmo que seja uma linha como "Estou nisso, reescrevendo a tabela de riscos agora." Silêncio no painel de chat é indistinguível de uma tela quebrada, que é exatamente a falha que este loop existe para prevenir. Responda lá, não apenas no terminal.
Enquanto trabalha, mantenha o chat honesto com o indicador de atividade:
# bolha animada "agente está pensando..."; atualize-a durante trabalhos longos
ecc-plan-canvas typing <arquivo> --state thinking
# alterne para "agente está digitando..." pouco antes de uma resposta chegar
ecc-plan-canvas typing <arquivo> --state typing
await define thinking automaticamente no momento em que entrega um lote, e
--reply o limpa. Ambos os estados expiram sozinhos, então um agente que travou
decai para um "enfileirado" honesto em vez de deixar o humano vendo pontos para sempre.
Atualize thinking se uma revisão levar mais de um minuto.
4. Encerre quando a revisão terminar: ecc-plan-canvas end <arquivo>.
Diagramas (Mermaid)
Quando parte do plano é um fluxo, arquitetura, sequência, máquina de estados, modelo
ER ou grafo de dependências, autores como um bloco cercado ```mermaid em vez de
arte ASCII ou um monte de prosa — a tela o renderiza como um diagrama temático que o
humano pode apontar. Use quando uma imagem é mais rápida que um parágrafo; pule para
listas simples ou tabelas.
```mermaid
flowchart LR
A[Mercado resolve] --> B{Observadores?}
B -->|sim| C[Enfileirar tarefas] --> D[Trabalhador fan-out]
```
Diagramas são renderizados no tema escuro ECC com a paleta de destaque. Mermaid é
carregado no navegador a partir de uma CDN fixa; se estiver indisponível (offline),
o bloco degrada para mostrar seu código-fonte, então a revisão nunca é bloqueada.
Aponte um mirror local em ECC_PLAN_CANVAS_MERMAID_URL para uso em ambiente
sem conexão.
Regras
- Artefatos Markdown renderizam no template de plano da ECC (incluindo blocos Mermaid);
artefatos
.htmlrenderizam como estão com a camada de anotação injetada. Para orientação de autoria HTML, use as skillsfrontend-design-directioneartifact-design. - Edite o arquivo do artefato para revisar — a tela recarrega ao vivo ao salvar. Nunca
reexecute
openpara atualizar. {"status": "ended", "endedBy": "user"}(ousessionEnded: trueem um lote de feedback) significa que o usuário fechou a revisão: pare de consultar, entregue atualizações restantes no chat e não reabra. Umopensimples nessa sessão é recusado; passe--reopenapenas quando o usuário pedir para retomar.- Ativos irmãos (imagens, CSS) devem estar ao lado do artefato e ser referenciados por caminho relativo.
- O servidor é apenas loopback e termina após 30 minutos ociosos
(
ECC_PLAN_CANVAS_IDLE_MS);stopo encerra explicitamente. O estado fica em~/.claude/plan-canvas/(ECC_PLAN_CANVAS_STATE_DIR).
Exemplos
Fluxo de aprovação de plano — /plan escreve
.claude/plans/notifications.plan.md e deve AGUARDAR confirmação:
ecc-plan-canvas open .claude/plans/notifications.plan.md
ecc-plan-canvas await .claude/plans/notifications.plan.md
# → {"status":"feedback","items":[{"kind":"verdict","verdict":"approve"}]}
ecc-plan-canvas end .claude/plans/notifications.plan.md
# plano confirmado — comece a implementação
Loop de revisão — feedback chega, você edita o arquivo, responde, continua ouvindo:
# await retornou anotações → edite o .plan.md (a tela recarrega ao vivo)
ecc-plan-canvas await <arquivo> --reply "Retrabalhei a tabela de riscos."
# → bloqueia novamente até a próxima resposta
Antipadrões
- Consultar com
--timeout-msem um loop. Existe para testes. Deixe oawaitsimples executando. - Encerrar sua rodada sem um
awaitouvindo enquanto a revisão ainda está aberta. Essa é a falha que o humano experimenta como "enviei uma mensagem e nada aconteceu". - Ler o feedback mas responder apenas no terminal. O humano está olhando a tela.
- Reabrir após um encerramento iniciado pelo usuário "só para mostrar" algo.
- Colar o plano inteiro no chat e abrir uma tela — escolha a tela e mantenha o resumo no terminal em uma linha.
- Analisar o chat da tela a partir de arquivos de estado — tudo que você precisa
chega via
await.
Notas de design e origem: docs/design/plan-canvas.md.