Plan Canvas
Bucle de revisión para planes y artefactos visuales: tú escribes el artefacto, el humano lo revisa en el navegador — anotando el elemento exacto al que se refiere, chateando y entregando un veredicto de Aprobar plan / Solicitar cambios — mientras tú te bloqueas en una única llamada CLI que devuelve sus comentarios como JSON.
Inspirado en lavish-axi; reconstruido de forma nativa en ECC alrededor de la puerta de confirmación /plan, con cero dependencias.
Cuándo Usarlo
- Acabas de escribir un artefacto de plan (
.claude/plans/*.plan.mddesde/plan) y necesitas la decisión de CONFIRMAR/aprobar — el veredicto del lienzo reemplaza un "sí/continuar" escrito. - El usuario debe señalar qué cambiar: revisando diseños, comparaciones, informes o cualquier artefacto local
.md/.html. - El usuario solicita
/plan-canvas, una revisión visual o "ábrelo en el navegador".
NO usar para: revisión de código de diffs (/code-review), aplicaciones web en ejecución o URLs remotas. El lienzo solo sirve archivos de artefactos locales.
Cómo Funciona
Invoca el CLI como ecc-plan-canvas — el binario distribuido por el paquete ecc-universal (en PATH tras una instalación global/plugin; node "$CLAUDE_PLUGIN_ROOT/scripts/plan-canvas.js" también funciona para instalaciones plugin). Ejecútalo desde el proyecto que estás revisando; funciona desde cualquier directorio de trabajo. Gestiona un servidor de bucle invertido separado (127.0.0.1:4517) compartido por todas las sesiones, identificado por la ruta del artefacto — sin IDs de sesión que rastrear.
El flujo de trabajo es un bucle CLI más JSON simple, por lo que es agnóstico al modelo y al arnés: cualquier agente que pueda ejecutar un comando de shell y leer la salida estándar lo maneja de la misma manera (Claude Code, Codex, Cursor, Gemini, OpenCode, Copilot). Actívalo como tu arnés exponga las habilidades — por ejemplo, /plan-canvas en Claude Code, $plan-canvas en Codex — o simplemente ejecuta los comandos ecc-plan-canvas directamente.
# 1. Abre el artefacto en el navegador del usuario (regresa inmediatamente)
ecc-plan-canvas open .claude/plans/feature.plan.md
# 2. Bloquéate hasta que el humano responda. Déjalo ejecutándose; vuelve a ejecutarlo si se interrumpe:
# los comentarios en cola nunca se pierden.
ecc-plan-canvas await .claude/plans/feature.plan.md
Mantente a la escucha, o el humano habla con una silla vacía
Los comentarios solo te llegan mientras un await está realmente estacionado en la sesión. Si tu turno termina sin que nada esté escuchando, el mensaje permanece en la cola y, desde el lado humano del cristal, enviar parece no hacer nada en absoluto.
Por lo tanto, ejecuta await como una tarea en segundo plano cuando tu arnés lo admita (en Claude Code, una llamada Bash con run_in_background: true). Sale en el momento en que llegan los comentarios y el arnés te entrega el JSON, manteniendo el bucle vivo a lo largo de los turnos en lugar de morir con la llamada en primer plano. Un await en primer plano también funciona, pero solo hasta que el arnés lo limite por tiempo.
Existen dos salvaguardas, y ninguna es excusa para saltarse lo anterior:
ecc-plan-canvas pendinglista los comentarios en cola sin oyente. Revísalo cada vez que no estés seguro de si te has perdido algo.- El hook
stop:plan-canvas-pendingbloquea el final de tu turno mientras haya comentarios del lienzo no entregados, y te entrega los mensajes. Si estás leyendo comentarios de ese hook, dejaste de escuchar demasiado pronto.
await imprime JSON cuando el humano actúa:
{
"status": "feedback",
"items": [
{ "kind": "annotation", "text": "Divide esto en dos fases",
"anchor": { "selector": "h2:nth-of-type(3)", "tag": "h2", "snippet": "Fase 2: Migración" } },
{ "kind": "verdict", "verdict": "request-changes" }
]
}
kind: "chat"— mensaje libre; responde en el lienzo, no en la terminal.kind: "annotation"— comentario anclado a un elemento (anchor.selector,anchor.snippetmuestran a qué apuntaron;anchor.textRange.textcuando resaltaron un pasaje).kind: "verdict"—approvesignifica que el plan está CONFIRMADO: deja de preguntar, finaliza la sesión y comienza a implementar.request-changessignifica revisa el artefacto (el lienzo lo recarga en vivo) y mantén el bucle activo.
3. Responde siempre en el lienzo, luego sigue escuchando. Un comando hace ambas cosas:
ecc-plan-canvas await <archivo> --reply "Dividida la Fase 2 como se solicitó. Échale un vistazo."
Cada mensaje humano recibe una respuesta en el lienzo, incluso una línea como "En ello, reescribiendo la tabla de riesgos ahora". El silencio en el panel de chat es indistinguible de un lienzo roto, que es exactamente el fallo que este bucle existe para prevenir. Responde allí, no solo en la terminal.
Mientras trabajas, mantén el chat honesto con el indicador de actividad:
# burbuja animada "el agente está pensando..."; refréscala durante trabajos largos
ecc-plan-canvas typing <archivo> --state thinking
# cambia a "el agente está escribiendo..." justo antes de que llegue una respuesta
ecc-plan-canvas typing <archivo> --state typing
await establece thinking por ti en el momento en que te entrega un lote, y --reply lo limpia. Ambos estados se auto-expiran, por lo que un agente bloqueado decae a un honesto "en cola" en lugar de dejar al humano viendo puntos para siempre. Refresca thinking si una revisión lleva más de un minuto.
4. Finaliza cuando la revisión concluya: ecc-plan-canvas end <archivo>.
Diagramas (Mermaid)
Cuando parte del plan sea un flujo, arquitectura, secuencia, máquina de estados, modelo ER o gráfico de dependencias, escríbelo como un bloque de código ```mermaid en lugar de arte ASCII o un muro de prosa — el lienzo lo renderiza como un diagrama temático al que el humano puede señalar. Recurre a ello cuando una imagen se lea más rápido que un párrafo; evítalo para listas o tablas simples.
```mermaid
flowchart LR
A[Mercado resuelve] --> B{¿Observadores?}
B -->|sí| C[Encolar trabajos] --> D[Trabajador de distribución]
```
Los diagramas se renderizan en el tema oscuro de ECC con la paleta de acentos. Mermaid se carga en el navegador desde un CDN fijo; si no está disponible (fuera de línea), el bloque degrada mostrando su fuente, por lo que la revisión nunca se bloquea. Apunta un espejo local a ECC_PLAN_CANVAS_MERMAID_URL para uso en entornos aislados.
Reglas
- Los artefactos Markdown se renderizan en la plantilla de plan de ECC (incluyendo bloques Mermaid); los artefactos
.htmlse renderizan tal cual con la capa de anotación inyectada. Para obtener orientación sobre la creación de HTML, usa las habilidadesfrontend-design-directionyartifact-design. - Edita el archivo del artefacto para revisar — el lienzo se recarga en vivo al guardar. Nunca vuelvas a ejecutar
openpara actualizar. {"status": "ended", "endedBy": "user"}(osessionEnded: trueen un lote de comentarios) significa que el usuario cerró la revisión: deja de preguntar, entrega las actualizaciones restantes en el chat y no vuelvas a abrir. Unopensimple en esa sesión es rechazado; pasa--reopensolo cuando el usuario pida reanudar.- Los activos hermanos (imágenes, CSS) deben estar junto al artefacto y referenciarse mediante ruta relativa.
- El servidor es solo de bucle invertido y se cierra después de 30 minutos de inactividad (
ECC_PLAN_CANVAS_IDLE_MS);stoplo apaga explícitamente. El estado reside en~/.claude/plan-canvas/(ECC_PLAN_CANVAS_STATE_DIR).
Ejemplos
Flujo de aprobación de plan — /plan escribe .claude/plans/notifications.plan.md y debe ESPERAR confirmación:
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
# plan confirmado — comenzar implementación
Bucle de revisión — llegan comentarios, editas el archivo, respondes, sigues escuchando:
# await devolvió anotaciones → edita el .plan.md (el lienzo se recarga en vivo)
ecc-plan-canvas await <archivo> --reply "Tabla de riesgos rehecha."
# → se bloquea de nuevo hasta la siguiente respuesta
Anti-Patrones
- Preguntar con
--timeout-msen un bucle. Existe para pruebas. Deja elawaitsimple ejecutándose. - Terminar tu turno sin un
awaitescuchando mientras la revisión aún está abierta. Ese es el único fallo que el humano experimenta como "envié un mensaje y no pasó nada". - Leer los comentarios pero responder solo en la terminal. El humano está mirando el lienzo.
- Volver a abrir después de un cierre iniciado por el usuario "solo para mostrar" algo.
- Pegar todo el plan en el chat y abrir un lienzo — elige el lienzo y mantén el resumen en la terminal en una línea.
- Analizar el chat del lienzo desde los archivos de estado — todo lo que necesitas llega a través de
await.
Notas de diseño y origen: docs/design/plan-canvas.md.