Hooks y guards
Activa los hooks de contexto que achican la salida de herramientas, y corre las verificaciones locales de guardrail que mantienen sano un workshop compartido.
Objetivo#
Activar los dos hooks de contexto opcionales del harness (ambos apagados
por defecto), instalar y correr las verificaciones de orch guard, y
elegir un guard.profile que decide cuanto de esto conecta Orchemax por ti.
Hooks de contexto (opt-in, apagados por defecto)#
orch.yaml:
context:
hooks:
post_tool: true # Claude Code PostToolUse / OpenCode tool.execute.after
pre_compact: true # Claude Code PreCompact
post_toolachica un resultado de herramienta sobredimensionado antes de que llegue al modelo (orch hook post-tool), usando los mismos ajustes de crush/externalize quecontext.guidance. Se salta cualquier nombre de herramienta listado encontext.guidance.protect_tools(por defecto:Bash,PowerShell,Read,Grep,Glob,Edit,Write,Agent,Task,WebFetch,Shell,bash,read_file,write_file— herramientas de codigo donde una reescritura con perdida ocultaria un resultado real).pre_compactcorre el mismo condensador queorch memory condensesobre.workflow/BOARD.mdy.orch/LAST_SESSION.mdjusto antes de que la compactacion nativa del harness descarte la transcripcion — asi la seccion## Clarifieddel board y los checkboxes abiertos sobreviven byte por byte en vez de resumirse.
Ninguno de los dos hooks hace algo por si solo: ambos necesitan
orch guard wire --claude (o --profile) para instalarse de verdad en
~/.claude/settings.json / la carpeta del plugin de OpenCode.
Verificaciones de orch guard#
orch guard dup <file> # deniega/advierte sobre un archivo que duplica un simbolo compartido o clona un cuerpo de funcion
orch guard code-lang [root] # los identificadores/strings deben coincidir con workspace.code_lang
orch guard lang [root] # los docs deben coincidir con workspace.docs_lang
orch guard ddl [files...] # migraciones/CREATE TABLE necesitan un companero seeder/repository
orch guard tracker [TRACKER.md] # sanidad de la tabla de estado de TRACKER.md (T1–T4)
orch guard lock <path> --holder # deniega editar shared/** sin un lock valido
orch guard dup es advisory por defecto — imprime donde vive la copia
existente y deja que la escritura continue. Define guard.dup.mode: block
en orch.yaml para denegar la escritura en vez de eso (off desactiva el
escaneo por completo). guard.dup.window / min_tokens / max_files
ajustan el escaneo de clones.
Un guard bloqueante — dup en modo block, una escritura sin lock en
shared/, un DDL sin companero seeder/repository, un deny de idioma en
docs/codigo, una regla de usuario con severity: block, o uno de los seis
genesis guards cuando guard.profile lo hace bloqueante — falla la tarea
despachada y hace que worktree_promote la rechace, nombrando el guard que
denego; los hallazgos advisory y warn solo anotan el reporte y nunca
cambian el estado de la tarea.
orch guard tracker y su recordatorio code staged without TRACKER.md al
sellar son opt-in: no dicen nada hasta que el proyecto ya tiene un
TRACKER.md en algun lugar del arbol, o se define guard.tracker: true en
orch.yaml. Un workspace nuevo que nunca adopto la convencion no recibe
ninguna nota de tracker en ningun lado — hooks, guard hooks run o sellado.
orch guard lang --count y orch guard code-lang --count recorren el
arbol e imprimen una fila rule(lang) hits sample_path:line por cada
idioma detectado, sin denegar nunca (sale con 0 siempre) — corre uno antes
de cambiar un codebase existente a guard.profile: strict, que corre el
mismo conteo primero y se niega sin --yes si encuentra hits.
Idiomas naturales#
workspace.docs_lang y workspace.code_lang aceptan cualquiera de estos
codigos (tambien xx-YY, p. ej. es-US); un codigo sin soporte salta el
guard con una nota en vez de fallar.
| Codigo | Idioma | lang marca prosa en… |
code-lang marca identificadores/strings en… |
|---|---|---|---|
en |
ingles | cualquier otro idioma soportado | cualquier otro idioma soportado |
es |
espanol | cualquier otro idioma soportado | cualquier otro idioma soportado |
pt |
portugues | cualquier otro idioma soportado | cualquier otro idioma soportado |
fr |
frances | cualquier otro idioma soportado | cualquier otro idioma soportado |
de |
aleman | cualquier otro idioma soportado | cualquier otro idioma soportado |
it |
italiano | cualquier otro idioma soportado | cualquier otro idioma soportado |
El ingles nunca se marca dentro de identificadores para un
code_lang que no sea ingles (las APIs de librerias y las palabras clave
del lenguaje son en ingles por convencion) — define
guard.code_lang_strict: true para marcarlo tambien ahi. Los strings
(literales entre comillas) siempre se revisan contra todos los idiomas
soportados, incluido el ingles, porque un string de producto en el idioma
equivocado es un bug de producto de cualquier forma.
orch guard comment-prose [path] es advisory en todo perfil — nunca
deniega. Por archivo de codigo anota bloques de 6+ lineas de comentario
consecutivas (el encabezado del archivo, el doc de paquete/modulo, los
bloques de licencia y los archivos generados quedan exentos) y cualquier
bloque con un marcador narrativo (una fecha ISO, "before the fix", "used to",
"we saw", "the founder", "historically"). Corre como nota en
orch guard hooks run y en cada verification report; --count imprime una fila resumen
en vez de cada hit.
Al sellar (la verificacion de un worker despachado), codigo que cambio sin
que ningun archivo de test/spec cambiara en el mismo diff recibe una nota
advisory tests: none touched — nunca una falla, y en silencio cuando lo
unico que cambio es docs/config.
Gate-silla: cuando el seat que corre orch guard ide-hook es el Chair
(ORCH_ROLE=chair, o sin rol con un Chair ya corriendo para este
workspace), cuenta los archivos de codigo que el propio Chair escribe en la
sesion. La 3ra escritura recibe un advisory que nombra dispatch_worker; la
4ta en adelante se deniega en shared/strict (solo advisory en lite,
apagado en none). ORCH_GUARD_CHAIR_WRITES=0 lo desactiva para el resto
de la sesion.
Sandbox y litter#
orch guard litter [files...] deniega un archivo o dot-directory nuevo
que se lee como scratch de agente en vez de codigo de proyecto — editar un
archivo existente nunca es litter. Las mismas formas se juzgan en el write
hook del IDE, al sellar, y (solo lectura) en orch harness scan /
workspace clean para lo que ya esta en disco.
Reglas de nombre y sufijo#
Un basename se juzga junto con su extension, asi que el codigo comun nunca cae en la regla:
| Forma del basename | Extension tipo doc (.md .txt .log .out .rtf .csv .json .html), o sin extension fuera de bin//scripts/ |
Cualquier otra extension |
|---|---|---|
Stem de prueba/scratch solo — test(s) tmp temp scratch verify check e2e gate audit debug dump poc draft note(s) report transcript consulta (p. ej. report.md, scratch solo) |
litter | nunca litter (report.go, check.py, verify.ts, tmp.go) |
El mismo stem + mas palabras (gate-x.sh, verify_login.sh, e2e-smoke.sh) |
litter | litter, salvo que la extension sea de codigo compilado/modulo/config (.go .rs .c .cs .java .tsx .jsx .vue .svelte .php .dart .sql .proto .py .ts .js .mjs .cjs .rb .pl .lua .yaml .yml .toml .ini .cfg .json … — decision del chair, el codigo normal nunca se deniega por nombre; las extensiones de shell/batch .sh .ps1 .cmd .bat quedan afuera a proposito, asi que verify_login.sh sigue siendo litter, y un .py/.js/.ts/.rb/.pl sin referencia se juzga en cambio por la regla de scripts sin referencia de abajo) |
Los marcadores de sufijo se suman a la regla de nombre:
| Sufijo | Extension | Litter? |
|---|---|---|
-final -copy -backup -bak -orig -rej -swp |
cualquiera | si |
(1), (2), … (copia generada por el OS) |
cualquiera | si |
-v2/_v2/.v2, -new, -old |
solo tipo doc | si |
-v2/_v2/.v2, -new, -old |
codigo/schema (.go, .sql, .proto, …) |
no — es una version normal, no una copia |
Duplicados#
- Un archivo nuevo cuyos bytes son identicos a un archivo ya versionado del
mismo tamano es litter —
duplicate of <path>(solo se leen los archivos del mismo tamano). El paso de arbol completo deorch harness scan/workspace cleansolo corre esta regla dentro de un repositorio git, y solo contra archivos sin versionar de 64 bytes o mas — un duplicado ya versionado es decision del usuario, y una coincidencia de tamano por debajo de ese piso es demasiado probable que sea casualidad. - Un doc nuevo bajo la carpeta de docs cuyo stem (quitando primero los
sufijos de arriba) o primer encabezado
#coincide con un doc ya versionado es litter —update the canonical doc <path>.
Scripts nuevos sin referencia#
Al sellar, un archivo nuevo con forma de script (.sh .ps1 .cmd .bat, o
cualquier archivo nuevo con el bit ejecutable de Unix) que nada en el cambio
ni en el arbol versionado nombra por ruta es litter — muevelo a
.sandbox/<seat>/ o conectalo a deploy/Makefile/CI. .py .js .ts .rb .pl
tienen una segunda forma de pasar: un hermano ya versionado con la misma
extension en ese mismo directorio, o que el stem del archivo aparezca como
palabra completa (al estilo import) en algun otro archivo. Los nombres de
punto de entrada por convencion de framework (index.*, main.*,
__init__.py, *.config.*, *.d.ts, …) nunca necesitan referencia.
Dot-directories#
Solo .sandbox/, .orch/, .git/, .cursor/rules/, .github/, y los
archivos .claude/settings.local.json (y el legado .claude/settings.json),
.gitignore, .gitattributes, .editorconfig, .mcp.json los conecta Orchemax. Cualquier otro dot-directory
nuevo se deniega por diseno — un agente no puede crear .vscode/,
.devcontainer/, .husky/, .storybook/, ni ninguna otra carpeta de
herramienta que empiece con punto. Si necesitas uno de esos en el arbol,
subelo tu mismo a mano (un archivo existente anterior al propio wiring de
Orchemax, o cuyo ultimo commit no es de una identidad orch-<seat>, nunca lo
reporta harness scan/workspace clean), o agrega su glob a keep en el
proyecto.
Shell write gate#
El mismo veredicto cubre el shell: el hook PreToolUse de Bash/PowerShell
(y el beforeShellExecution de cursor) lee la linea de comando buscando las
rutas que crearia — >/>>, cat > x <<EOF, tee, destinos de cp/mv,
Out-File, Set-Content, Add-Content, New-Item, Copy-Item,
Move-Item —, las resuelve contra el cwd del shell y deniega un destino
litter o un nombre de dispositivo de Windows (> nul, que deja un archivo
literal imposible de borrar; descarta con >/dev/null o $null), mientras
que /dev/null, $null, NUL: y un > dentro de comillas quedan intactos.
Severidad, el sandbox, y "tuyo, no litter"#
La severidad sigue a guard.profile: deniega en el hook PreToolUse del
IDE y al sellar en lite/shared/strict, solo advisory en bring, apagado
en none.
orch harness scan y orch workspace clean nunca reportan un archivo
existente y versionado como litter cuando se cumple alguna de estas:
| Excepcion | Condicion |
|---|---|
| referenciado | otro archivo de texto versionado lo nombra, por ruta o por dir/basename |
| pre-Orchemax o humano | versionado, y o bien fue agregado antes del propio wiring de Orchemax en este proyecto, o su ultimo commit no tiene autor orch-<seat> |
| en keep | su ruta coincide con un glob de projects[].keep (soporta **) en orch.yaml |
Un archivo no versionado solo puede recibir la primera o la tercera
excepcion — nunca la segunda, porque no tiene historial de commits que
revisar. Cada commit que hace un worker despachado lleva
GIT_AUTHOR_NAME/GIT_COMMITTER_NAME = orch-<seat> y correo
<seat>@orch.local, asi que esa revision es una identidad real, no un
trailer adivinado. El nombre de seat/worker en si debe coincidir con
[A-Za-z0-9][A-Za-z0-9._-]{0,63} (1 a 64 caracteres, sin separador, sin
punto inicial) y no puede ser un nombre de dispositivo de Windows — se
rechaza antes del dispatch, porque se vuelve un segmento de ruta bajo
.sandbox/.
orch project add siembra <project>/.sandbox/README.md y marca
.sandbox/ en el .gitignore del proyecto. Al cerrar cada tarea, cualquier
archivo que esa tarea creo bajo su seat con prefijo tmp/temp o
terminacion .log/.out/.tmp se borra de inmediato; todo lo demas en
.sandbox/<seat>/ espera el barrido por edad una vez que pasa
guard.sandbox_days (default 14) — que nunca borra README.md, nunca borra
un directorio, y nunca sigue un symlink o junction fuera del sandbox.
orch workspace clean --dry-run lista la carpeta de sandbox de cada seat con
su tamano. orch harness scan lista el litter que ya existe en disco
(conteo y primeras 10 rutas) y nunca lo borra.
La regla en palabras, para cualquier agente que trabaje bajo Orchemax: todo
lo que no es codigo de producto va a .sandbox/<seat>/; los archivos
temporales ahi se borran al cerrar la tarea, no esperan al barrido. Nunca
crear archivos -v2/-final/copia — actualizar el canonico en su lugar.
Nunca > nul; usar /dev/null o $null. Los logs de build tambien van a
.sandbox/<seat>/ (tee build.log en el arbol versionado se deniega igual
que cualquier otra escritura litter). Un script que se invoca desde el shell
no se inspecciona por dentro — el hook solo ve la linea de comando, no el
cuerpo del script — asi que la misma regla aplica: su salida va bajo
.sandbox/<seat>/, por disciplina propia.
Referencias colgantes#
Al sellar, Orchemax lee cada ruta que el cambio borro o renombro y busca el
resto del arbol versionado por ella — la ruta relativa completa, o su forma
mas corta dir/basename — solo cuenta si coincide en un limite real de
segmento de ruta, asi que db/client.go nunca dispara sobre un
mongodb/client.go borrado, y mover main.go a cmd/app/main.go con el
Makefile actualizado no da falso positivo. Un hit en una linea de
codigo/deploy/config falla el sellado y lista file:line → ruta vieja; un
hit en una linea de puro comentario o dentro de un doc .md es solo
advisory. orch harness scan reporta la misma forma para rutas que git ya
no encuentra en disco (borradas, sin git rm todavia) pero que un archivo
versionado sigue llamando, y por separado marca un core.hooksPath que
apunta a un directorio que ya no existe. La severidad sigue la misma
escalera de guard.profile que litter: advisory en bring, apagado en
none.
Pasos#
orch setup ya ofrece instalar el scope de proyecto una vez, justo despues de
enlazar el workspace (default si; --yes acepta, nunca toca el scope de
usuario; --allow-user-scope hace falta para la entrada MCP global de agy).
Los pasos de abajo son para instalar, reinstalar, o elegir otro perfil a mano.
-
Elige un perfil (o acepta el default recomendado):
orch guard profile lite # docs + skills; sin hooks (recomendado dia 1) orch guard profile shared # + hooks de git pre-commit/pre-push en repos shared/project orch guard profile strict # + wire de hooks de usuario en Claude, conciencia de locale/tracker orch guard profile bring # mantiene tu propio CLAUDE/rules; orch solo agrega locks/simbolos orch guard profile none # solo orch.yaml -
Conecta los adaptadores de ese perfil:
orch guard wire --profileO conecta adaptadores especificos directamente:
--git,--claude,--cursor,--copilot. Todo wire es scope de proyecto por defecto:--claudeescribe/mezcla<workspace>/.claude/settings.local.json— ignorado por git, la entrada se agrega al.gitignoredel proyecto en el primer wire — y nunca abre~/.claude/settings.json. Para conectar el scope de usuario — la configuracion que lee toda sesion de Claude Code en la maquina, mas el MCP global de agy y el plugin de OpenCode — agrega--scope user; Orchemax te pide confirmacion nombrando el archivo, el bloque marcado, el respaldo (settings.json.bak-<yyyymmdd-hhmmss>) y el comando para deshacer. En un script,--allow-user-scopees ese consentimiento; un--yesgeneral no lo es.--copilotno hace nada: una corrida real decopilot -pen modo headless nunca carga.github/hooks/*.json(verificado en vivo contra el CLI instalado) — la confirmacion interactiva de confianza de carpeta que lo condiciona nunca aparece en modo headless, asi que Orchemax se niega a escribir un hook que solo parecería activo. Copilot queda cubierto por el sellado (la revision de guardrails que igual corre sobre el diff de cada worker al cerrar su sesion), igual que un agente sin hook en tiempo real.orch harness scanreporta cada scope (claudede usuario,claude.project,copilot) como conectado o solo-sellado —copilothoy siempre es solo-sellado. -
Instala los hooks de git directamente (independiente de
guard wire):orch guard hooks install [repo] orch guard hooks status [repo] orch guard hooks run [repo] # lo que realmente llaman los hooks instalados
Verificar#
orch guard profile
orch guard hooks status
Deshacer#
orch guard unwire # quita el bloque marcado de orch en ambos scopes (deja respaldo)
orch guard unwire --git # tambien quita pre-commit/pre-push de git
orch guard unwire --project # solo scope de proyecto — no abre ningun archivo del usuario
orch guard hooks uninstall [repo]
Relacionado#
your-own-rules.md— las verificaciones que son tuyas, corriendo donde corren estas.memory-and-ledger.md— que es lo que condensapre_compact.troubleshooting.md— "el hook no hizo nada" cuando el workspace no esta registrado.