Hooks and guards

Everything on this page is off until you turn it on — and most of it advises rather than denies.

What it is#

Guards are checks you can run by hand, from a git hook, or from an IDE hook:

Command What it denies
orch guard dup <file> A file duplicating a shared symbol; also reports copied function bodies
orch guard code-lang [root] Identifiers and user-visible strings that do not match workspace.code_lang
orch guard lang [root] Docs that do not match workspace.locale
orch guard ddl [files...] A migration or CREATE TABLE change with no seeder or repository companion
orch guard tracker [path] A TRACKER state table that breaks T1–T4: bad status, SPEC with no .md, VERIFIED with no evidence, narrative dump

There are more: comment, lock, add-all, shared-brand, control-bytes, artifacts, encoding.

Hooks are two entry points into your harness, each gated by its own consent key in orch.yaml:

Key Fires on What it does
context.hooks.post_tool Claude Code PostToolUse, OpenCode tool.execute.after Shrinks a tool result before it lands in the context window
context.hooks.pre_compact Claude Code PreCompact Runs the orch memory condense condenser on workshop memory before the harness compacts

Both default to false. Copilot CLI and Cursor expose the same capability but orch has no wiring path for either yet, so neither is installed; Codex CLI cannot replace tool output at all.

Wiring:

orch guard wire            # from guard.profile, or --git / --claude / --cursor
orch guard unwire          # add --git to remove the git hooks too
orch guard hooks install   # git pre-commit + pre-push, orch-marked
orch guard hooks status
orch guard profile         # show, or set: lite | shared | strict | bring | none

Advisory or block#

The distinction is per guard.

  • Advisory — the clone scan, by default. guard.dup.mode: advisory reports what it found and injects it as context; the write proceeds. Set block and the same finding fails the call with clone guard denied N duplicated block(s); set off and it does not look.
  • Block — every other guard. A finding prints to stderr and the command exits non-zero, so a pre-commit hook stops the commit.
  • Soft-skip — outside a bound workshop, or when the relevant setting is unset. orch guard lang with no workspace.locale skips rather than guessing.

Why it exists#

Field lessons, each cheap to state and expensive to learn. git add -A on a shared layer steals another session's work in progress. Chatting with a model in one language quietly puts that language into identifiers and error strings. A migration without a seeder passes review and fails in production. None of these need a policy engine — they need one check at the moment the mistake is made.

They are opt-in because the workshop is yours: orch init calls the starter kit recommendations, not mandates.

How it relates to the rest#

  • The same guardrail suite runs twice: from the pre-commit hook you installed, and again when a session closes, over exactly the files that session touched. That second run is the observed half of the verification report.
  • orch harness scan reports which AI tools and doctrine surfaces it can see, before you decide what to wire.
  • Guard profiles control what orch init wires: lite seeds docs and skills with no hooks, none skips the doctrine seeds entirely.

Nothing to run here#

Nothing here runs unless you wire it. Run the guards by hand if that is all you want; orch guard wire is the switch that enforces them.