Disenar un gate de dos modos: explorar un repo desconocido en Plan Mode read-only, firmar un plan.md por hash, y bloquear escritura via hook hasta que la firma habilite Execute Mode.
Operar un repo o dominio desconocido en dos modos explícitos: un Plan Mode read-only (solo Read, Grep, Glob, Bash de inspección) que produce un plan.md, y un Execute Mode que se habilita únicamente tras la firma de ese plan. La transición no depende del modelo: la aplica un hook que enumera y bloquea las write-tools mientras el modo sea plan. [CONFIG] Lo construible es el diseño del gate: estado de modo, contrato del plan, evento de firma y enforcement por hook. No es una convención de prosa; es un dato que un hook puede leer y denegar. [INFERENCIA]
No usarla / anti-scope: tareas sin escritura a repo (resúmenes, tablas, análisis de datos) no necesitan el gate; activar el skill ahí es ruido — degrada a no-activación. [INFERENCIA] Tampoco sustituye permisos de plataforma ni revisión de código: el gate autoriza ejecutar el plan, no garantiza que el plan sea correcto. [SUPUESTO]
plan.md que firmar → entrada vacía detiene la ejecución ({VACIO_CRITICO} → stop + ask), nunca auto-completa el plan. [INFERENCIA]mode, signed_plan_hash); (2) plan.md firmable; (3) evento de firma (hash + approved_by + plan_signed_at); (4) hook PreToolUse; (5) write-blocklist explícita; (6) diff final. El plan firmado + el diff son el rastro auditable. [CONFIG]mode: "plan" | "execute"), no intención en prosa. Arranca en plan. [CÓDIGO]plan (Write, Edit, MultiEdit, NotebookEdit, Bash mutante, MCP de mutación). Allowlist de lectura; todo lo demás se bloquea — fail-closed, no fail-open. [INFERENCIA]plan.md como artefacto: objetivo, archivos a tocar, orden de cambios, criterio de aceptación y riesgos. Es el objeto que se firma. [DOC]plan_signed_at, approved_by, hash del plan), no un "ok" conversacional. La firma referencia el hash exacto. [CÓDIGO]PreToolUse que lee el modo: si mode == "plan" y la tool está en la write-list, deniega con motivo. Solo approve_plan(hash) cambia mode a execute. [CÓDIGO]plan.md cambia (hash distinto al firmado), el modo vuelve a plan y exige nueva aprobación. [CÓDIGO]# GOOD: el modo es estado; el hook bloquea writes hasta firma del hash exacto.
STATE = {"mode": "plan", "signed_plan_hash": None}
WRITE_TOOLS = {"Write", "Edit", "MultiEdit", "NotebookEdit"}
MUTATING_BASH = ("rm ", "sed -i", "mv ", "git commit", "git push", ">", ">>")
def pre_tool_use(tool_name: str, plan_hash_now: str, bash_cmd: str = "") -> dict:
# plan.md changed after signing -> revert before allowing anything
if STATE["signed_plan_hash"] and plan_hash_now != STATE["signed_plan_hash"]:
STATE["mode"] = "plan"
return {"decision": "deny", "reason": "plan.md changed; re-approval required."}
if STATE["mode"] == "plan":
if tool_name in WRITE_TOOLS:
return {"decision": "deny",
"reason": "Plan Mode is read-only. Sign plan.md to enter execute."}
if tool_name == "Bash" and any(m in bash_cmd for m in MUTATING_BASH):
return {"decision": "deny",
"reason": "Mutating Bash (rm/sed -i/redirects) blocked in Plan Mode."}
return {"decision": "allow"}
def approve_plan(plan_hash: str, approver: str) -> None:
STATE["signed_plan_hash"] = plan_hash # auditable artifact
STATE["mode"] = "execute" # only path into write mode# ANTI: bypassPermissions + escritura desde el primer turno, sin plan ni firma.
settings = {"permissionMode": "bypassPermissions"} # no read-only gate
def run(repo):
edit_file(repo / "main.py", patch) # writes before exploration
edit_file(repo / "config.yaml", patch)
# no plan.md, no signed hash, no hook; el modelo decide solo.Otros anti-patrones: aprobar un plan sin hash (un "ok" en el chat no es firma); whitelist de writes en vez de blocklist (fail-open); permitir Bash mutante (rm -rf, sed -i, redirecciones >) en plan por considerarlo "preparación". [INFERENCIA]
rm -rf tmp, sed -i): es escritura disfrazada de inspección → el hook debe denegar por patrón de comando, no solo por nombre de tool. [CÓDIGO]bypassPermissions: anula el gate; el validador lo rechaza como caso bloqueado, Guardian no lo aprueba. [CONFIG]plan antes de permitir cualquier write. [CÓDIGO]Re-abre el diseño si: ejecutaste un write sin un signed_plan_hash que coincida; la aprobación vive en la conversación y no como evento con hash; el hook bloquea por convención y no por enumeración explícita; un cambio de plan.md no revirtió a plan; o un Bash mutante pasó en modo plan. Cualquiera de estos invalida el gate. [INFERENCIA]
plan por hook, no por convención? [DOC]plan.md tras firmado revierte a plan y re-pide firma? [DOC]bypassPermissions y la entrada vacía no fabrica plan? [DOC]assets/ define el contrato determinístico de modo, plan firmado, aprobación, hook, write-tools y decisión de ejecución. [CÓDIGO]scripts/check.sh valida fixtures locales sin red, tiempo real ni aleatoriedad. [CÓDIGO]scripts/validate_plan_mode_workflow.py rechaza: write en plan, firma faltante, hash que no coincide, hook que no bloquea, Bash mutante en plan, bypassPermissions, o Guardian aprobando un caso bloqueado. [CÓDIGO]evals.json cubre happy path, gate de aprobación, workspace compartido, re-firma, Bash mutante bloqueado, falso positivo, entrada vacía y upgrade seguro. [CÓDIGO]katas-plan-mode-exploration, custom-tooling-extension, human-escalation-design. [DOC]fdad39c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.