O que Plan Canvas faz?
Loop de revisão para planos e artefatos visuais: você escreve o artefato, o humano o revisa no navegador — anotando o elemento exato a que se refere, conversando e entregando um veredito Aprovar plano / Solicitar alterações — enquanto você fica bloqueado em uma única chamada CLI que retorna o feedback como JSON.
Inspirado por lavish-axi; reconstruído nativo para o 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 do canvas substitui um "sim/continuar" digitado. - O usuário deve apontar o que mudar: revisando designs, comparações, relatórios ou qualquer artefato local
.md/.html. - 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), aplicações web em execução ou URLs remotas. O canvas serve apenas arquivos de artefatos locais.
Como Funciona
Invoque a CLI como ecc-plan-canvas — o binário enviado pelo pacote ecc-universal (no PATH após instalação global/plugin; node "$CLAUDE_PLUGIN_ROOT/scripts/plan-canvas.js" também funciona para instalações via plugin). Execute-a a partir do projeto que você está revisando; funciona de qualquer diretório de trabalho. Ela gerencia um servidor loopback destacado (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 a modelo e plataforma: qualquer agente que possa executar um comando shell e ler stdout o aciona da mesma forma (Claude Code, Codex, Cursor, Gemini, OpenCode, Copilot). Acione-o conforme sua plataforma expõe skills — por exemplo /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; reexecute se interrompido:
# o feedback enfileirado nunca é perdido.
ecc-plan-canvas await .claude/plans/feature.plan.md
Fique ouvindo, ou o humano conversa com uma cadeira vazia
O feedback só chega até você enquanto um await está realmente estacionado na sessão. Se seu turno terminar sem nada ouvindo, a mensagem fica na fila e, do lado do humano, enviar parece não fazer nada.
Portanto, execute await como uma tarefa em segundo plano quando sua plataforma suportar uma (no Claude Code, uma chamada Bash com run_in_background: true). Ela sai no momento em que o feedback chega e a plataforma entrega o JSON, o que mantém o loop vivo entre turnos em vez de morrer com a chamada em primeiro plano. Um await em primeiro plano também funciona, mas apenas até que a plataforma limite seu tempo.
Existem duas salvaguardas, e nenhuma delas é desculpa para pular o acima:
ecc-plan-canvas pendinglista feedback enfileirado sem ouvinte. Verifique sempre que não tiver certeza se perdeu algo.- O hook
stop:plan-canvas-pendingimpede que seu turno termine enquanto houver feedback do canvas não entregue e entrega as mensagens. Se você está lendo feedback desse hook, 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 no canvas, 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 (o canvas recarrega ao vivo) e manter o loop.
3. Sempre responda no canvas, depois continue ouvindo. Um comando faz ambos:
ecc-plan-canvas await <file> --reply "Dividindo a Fase 2 conforme solicitado. Dê uma olhada."
Toda mensagem humana recebe uma resposta no canvas, mesmo uma linha como "Fazendo, reescrevendo a tabela de riscos agora." Silêncio no painel de chat é indistinguível de um canvas quebrado, 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 "agente está pensando..." animada; atualize durante trabalho longo
ecc-plan-canvas typing <file> --state thinking
# mude para "agente está digitando..." pouco antes de uma resposta chegar
ecc-plan-canvas typing <file> --state typing
await define thinking para você no momento em que entrega um lote, e --reply o limpa. Ambos os estados expiram sozinhos, então um agente quebrado decai para um honesto "enfileirado" em vez de deixar o humano observando pontos para sempre. Atualize thinking se uma revisão levar mais de um minuto.
4. Termine quando a revisão concluir: ecc-plan-canvas end <file>.
Diagramas (Mermaid)
Quando parte do plano é um fluxo, arquitetura, sequência, máquina de estados, modelo ER ou gráfico de dependências, escreva-o como um bloco ```mermaid em vez de arte ASCII ou um muro de prosa — o canvas o renderiza como um diagrama temático que o humano pode apontar. Use-o quando uma imagem é mais rápida que um parágrafo; pule para listas ou tabelas simples.
```mermaid
flowchart LR
A[Mercado resolve] --> B{Observadores?}
B -->|sim| C[Enfileirar jobs] --> D[Worker fan-out]
```
Diagramas renderizam no tema escuro do ECC com a paleta de destaque. Mermaid carrega no navegador de uma CDN fixa; se isso não estiver disponível (offline), o bloco degrada para mostrar seu código fonte, então a revisão nunca é bloqueada. Aponte um espelho local em ECC_PLAN_CANVAS_MERMAID_URL para uso em ambientes isolados.
Regras
- Artefatos Markdown renderizam no modelo de plano do ECC (incluindo blocos Mermaid); artefatos
.htmlrenderizam como estão com a camada de anotação injetada. Para orientação de criação de HTML, use as skillsfrontend-design-directioneartifact-design. - Edite o arquivo do artefato para revisar — o canvas 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. Um simplesopennessa sessão é recusado; passe--reopenapenas quando o usuário solicitar retomar.- Ativos irmãos (imagens, CSS) devem ficar ao lado do artefato e ser referenciados por caminho relativo.
- O servidor é loopback-only e sai após 30 minutos ociosos (
ECC_PLAN_CANVAS_IDLE_MS);stopo desliga explicitamente. O estado reside 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 — iniciar implementação
Loop de revisão — feedback chega, você edita o arquivo, responde, continua ouvindo:
# await retornou anotações → edite o .plan.md (canvas recarrega ao vivo)
ecc-plan-canvas await <file> --reply "Refiz a tabela de riscos."
# → bloqueia novamente até a próxima resposta
Anti-Padrões
- Consultar com
--timeout-msem um loop. Existe para testes. Deixe oawaitsimples executando. - Terminar seu turno sem nenhum
awaitouvindo enquanto a revisão ainda está aberta. Essa é a única falha que o humano experimenta como "enviei uma mensagem e nada aconteceu". - Ler o feedback mas responder apenas no terminal. O humano está olhando para o canvas.
- Reabrir após um encerramento iniciado pelo usuário "só para mostrar" algo.
- Colar o plano inteiro no chat e abrir um canvas — escolha o canvas e mantenha o resumo no terminal em uma linha.
- Analisar o chat do canvas a partir de arquivos de estado — tudo o que você precisa chega via
await.
Notas de design e origem: docs/design/plan-canvas.md.