Skip to content

Use hooks as deterministic guardrails

Hooks move selected checks from prompt memory into executable policy at defined lifecycle events. Full credit on Q12 requires layered guardrails that protect sensitive paths, format or lint changed files, detect credential exposure, and verify repository policy. A hook is only as reliable as its matcher, failure behavior, and tests, so treat it as one control beside sandboxing, least privilege, CI, and human approval.

Scorecard question: How do you use build-time hooks as deterministic guardrails?

Maximum-score answer: Layered and tested hooks block protected actions, run quality checks, detect secret leaks, and produce retained policy evidence.

The following layers are useful when they match real repository risks:

RiskLifecycle controlRequired evidence
Agent edits generated, vendored, or protected pathsPre-tool or pre-write gateA denied fixture exits with the documented blocking result
Changed code violates formatting or lint rulesPost-edit or stop checkThe repository command runs on representative changed files
A diff contains a credential patternPre-commit or stop secret scanA synthetic test token is detected without exposing a real secret
A command targets production or a destructive resourcePermission rule plus pre-command hookThe known-dangerous fixture is denied; indirect forms are tested
A task claims completion without verificationStop policy checkMissing test evidence prevents the completion transition

Keep formatters separate from security gates. A formatter can fail open and report a fix; a production or credential gate should fail closed when the host supports that behavior.

ToolProject configurationVerification surface
Claude Code.claude/settings.json with lifecycle events such as PreToolUse, PostToolUse, and StopUse the current Claude Code hooks guide; confirm matcher and exit/JSON semantics per event
Cursor.cursor/hooks.json with events such as beforeShellExecution, beforeMCPExecution, afterFileEdit, and stopUse the current Cursor hooks reference; set failClosed: true explicitly for supported security-critical gates
Codex.codex/hooks.json or [hooks] in the matching config.toml layerUse /hooks to review and trust changed project hooks; see the current Codex hooks reference

The names and output contracts are not interchangeable. Reimplement the same policy against each host’s documented schema instead of copying one JSON file across tools.

  1. List protected invariants. Name exact paths, command classes, data types, and completion evidence the repository requires.
  2. Choose the earliest supported event. Block before a dangerous action; run repairable quality checks after an edit or at stop.
  3. Implement one small hook. Parse structured input, handle missing fields, write diagnostics without secrets, and return the host’s documented decision.
  4. Add allow and deny fixtures. Test a safe action, a direct forbidden action, an indirect equivalent, malformed input, timeout, and script failure.
  5. Configure failure behavior. Use fail-closed behavior for security gates where supported; make non-security automation report failures without hiding them.
  6. Mirror critical checks in CI. Treat local hooks as fast feedback and CI as the merge boundary.
  7. Review and trust the configuration. Inspect project-local hook changes like executable code before enabling them.
Read the repository policy and the selected tool's official hook schema.
Design the smallest hook that enforces one invariant. Include allow, deny,
indirect-bypass, malformed-input, timeout, and hook-failure fixtures.
Do not install or enable it until I review the script and test results.
Audit every configured hook. For each, report the event, matcher, command,
expected input, decision contract, timeout, failure mode, secret exposure,
and equivalent CI control. Flag any claimed guarantee without a passing test.

The matcher sees only one spelling. Add environment prefixes, absolute executable paths, wrappers, and equivalent tool calls to the bypass suite.

The hook silently fails open. Select the host’s explicit fail-closed option where available and test a crashing fixture.

A formatter becomes a deployment gate. Keep low-risk repair automation separate from protected-resource policy.

The hook logs sensitive input. Redact credentials and personal data before diagnostics or telemetry leave the process.

Local enforcement differs from CI. Reuse the same script or fixture set at both boundaries and compare exit behavior.

  • Every hook maps to a named repository risk.
  • Safe, denied, bypass, malformed, timeout, and failure fixtures pass.
  • Security-critical hooks use the intended failure behavior.
  • Logs and retained outputs contain no credentials or sensitive payloads.
  • CI enforces merge-critical invariants independently of the agent host.
  • Project hook changes receive code review and, where required, a trust action.

Place hooks inside the permission boundaries in Governance and autonomy and use them to retain evidence for Build and Test.