Skip to main content

Hook Enforcement Reference

12 scripts | 11 active in settings.json | 6 enforcement layers | ZERO standalone execution

The ADLC framework enforces constitutional governance through 12 shell scripts that fire automatically at different points in the agent lifecycle. Together they form a defense-in-depth chain where every agent action passes through multiple validation gates.


Coverage Matrix

Every tool call passes through at least one enforcement layer. The matrix below shows which hooks fire for each event type.

EventHook(s)Exit CodesWhat Gets Blocked
UserPromptSubmitremind-coordination.sh0/1All prompts when PO+CA logs missing
UserPromptSubmitdetect-nato-violation.sh0/2Completion claims without evidence
PreToolUse Bashvalidate-bash.sh0/2Destructive commands, git mutations, IaC mutations
PreToolUse Bashenforce-container-first.sh0/2Bare-metal terraform/tflint/checkov/infracost
PreToolUse Edit/Writeblock-sensitive-files.sh0/2Access to .env, .pem, .key, .tfstate, credentials
PreToolUse Edit/Writeenforce-coordination.sh0/1Code changes without PO+CA coordination logs
PreToolUse Edit/Writeenforce-specialist-delegation.sh0/2Raw Edit/Write on domain files without specialist lock
PreToolUse Taskenforce-coordination.sh0/1Agent dispatch without PO+CA coordination logs
PreToolUse Taskwrite-specialist-lock.sh0(writes lock file, never blocks)
PostToolUse Tasklog-coordination-wrapper.sh0(logs evidence, never blocks)
PostToolUse Taskenforce-pdca-cycle.sh0(tracks cycles, escalates at limit)
SessionStartload-project-context.sh0(initialization, never blocks)

Manual utility: log-coordination.sh is not wired into settings.json hooks. It is called by agents directly to create structured coordination logs with --scope and --scope-keywords flags.


Layer 1: Prompt-Level Enforcement (UserPromptSubmit)

These hooks fire before Claude processes the user's prompt. They cannot be bypassed by plan mode, permission overrides, or accept-all-edits settings.

remind-coordination.sh v4.3.0

Purpose: Block all prompts until product-owner and cloud-architect coordination logs exist for today.

Smart Bypass Architecture (solves the chicken-and-egg problem from v1.0.0-v3.0.0):

Prompt TypeDetection PatternAction
Coordination-invokinginvoke|run|launch + product.owner|cloud.architectAllow through (exit 0)
Informationalhelp|status|continue|what.*should|/help|/clearAllow with reminder (exit 0)
Work prompt (no logs)Anything elseBLOCK (exit 1)

Validation chain when logs exist:

  1. File existence check (product-owner-YYYY-MM-DD.json, cloud-architect-YYYY-MM-DD.json)
  2. JSON syntax validation (jq empty)
  3. Required fields check (timestamp, agent, status)
  4. Status must be "success"
  5. Session scope (v4.2.0): If ADLC_SESSION_SCOPE_STRICT=true, logs from a different session are rejected
  6. HITL report scope drift (v4.3.0): Detects when prompt requests a HITL/manager report but coordination logs lack matching scope_keywords (anti-pattern #19)

Version history:

  • v1.0.0: BLOCKING — caused chicken-and-egg (can't invoke agents when blocked)
  • v2.0.0: BLOCKING + JSON validation — same problem
  • v3.0.0: ADVISORY (exit 0) — too weak (Claude ignores stderr guidance)
  • v4.0.0: BLOCKING + smart bypass — reads prompt from stdin JSON
  • v4.2.0: Requires action verbs in patterns (bare @agent-product-owner no longer passes)
  • v4.3.0: HITL report scope drift detection

detect-nato-violation.sh v3.0.0

Purpose: Block completion claims that lack evidence paths.

Detection:

  • 9 completion keywords: complete, done, finished, implemented, resolved, fixed, delivered, shipped, ready for review
  • Evidence path patterns required: tmp/, evidence/, artifacts/, coordination-logs/, test-results/, .json, screenshot
  • Strict mode (ADLC_STRICT_EVIDENCE=true): Evidence paths must resolve to actual files on disk

Layer 2: Tool-Level Enforcement (PreToolUse)

These hooks fire before a tool executes. They inspect the tool input and block if the action violates governance rules.

Bash Tool: Dual-Hook Chain

When Claude calls the Bash tool, two hooks fire sequentially:

validate-bash.sh v2.1.0

Blocks dangerous shell commands across 7 categories:

CategoryBlocked PatternsPrinciple
Destructiverm -rf /, sudo rm, chmod 777, mkfs, dd if=I
Sudosudo without explicit HITL contextI
Path traversal../../.. patternsII
Credentialscat .env, cat .pem, curl password=II
Git mutationsgit add/commit/push/merge/rebase/reset/revert/checkout/stash/cherry-pick/tagI
IaC mutationsterraform apply/destroy/import/taint, terraform state rm/mv, cdk deploy/destroy/bootstrap, tofu apply/destroyI
Publishingnpm publish, docker push, kubectl delete, helm delete/uninstallI

v2.1.0 addition (GITHUB_API_TREE_CORRUPTION incident):

Blocks gh api calls targeting git object mutation endpoints (repos/.../git/blobs, /trees, /commits, /refs). This closes the HOOK_BYPASS_VIA_API vector where agents used the GitHub API to circumvent git mutation blocks.

Allowed read-only operations: terraform state list/show, terraform output/show/graph/version/providers, all git read commands.

enforce-container-first.sh v1.0.0

Blocks bare-metal tool invocations that must route through container-first task commands:

Blocked CommandCorrect Alternative
terraform fmttask build:validate
terraform validatetask build:validate
terraform inittask build:validate
terraform testtask test:tier1
terraform plantask plan:cost
tflinttask build:lint
checkovtask build:lint
infracosttask plan:cost
trivytask security:trivy

Always allowed: task:* commands, docker exec/run/compose, DOCKER_HOST=* prefixed commands, _exec helper calls.

Bypass: ADLC_CONTAINER_FIRST_BYPASS=true in settings.local.json.

Edit/Write Tool: Triple-Hook Chain

When Claude calls Edit or Write, three hooks fire sequentially:

block-sensitive-files.sh v2.0.0

Blocks access to 22 sensitive file patterns:

.env, .env.*, .env.local, secrets/, credentials, .pem, .key,
.p12, .pfx, id_rsa, id_ed25519, .aws/credentials, .ssh/,
terraform.tfstate, .tfvars, .secret, .secrets.*, kubeconfig,
token.json, oauth*.json, service[-_]account*.json

All blocked attempts are logged to tmp/audit/sensitive-access-YYYY-MM-DD.jsonl for audit trail.

enforce-coordination.sh v4.0.0

Validates that product-owner + cloud-architect coordination has occurred:

  1. Checks for coordination log files (coordination-logs/product-owner-YYYY-MM-DD.json and cloud-architect-YYYY-MM-DD.json)
  2. Validates JSON syntax (jq empty)
  3. Checks required fields: timestamp, agent, status
  4. Verifies status is "success"
  5. Validates agent agreement >= threshold (default 95%, configurable via ADLC_AGENT_AGREEMENT_THRESHOLD)

No escape hatch: ADLC_AUTONOMOUS_MODE was removed entirely in v4.0.0. Zero standalone execution.

enforce-specialist-delegation.sh v2.0.0

Blocks raw Edit/Write on domain-specific files unless a specialist agent is active:

Delegation rules (16 patterns):

File PatternRequired Specialist
*.tf, *.tftest.hcl, modules/**infrastructure-engineer
.github/workflows/*.ymlinfrastructure-engineer or qa-engineer
scripts/*.shinfrastructure-engineer or qa-engineer
tests/**, *_test.go, *_test.py, *.test.tsqa-engineer
security/**, *.policy.json, CODEOWNERSsecurity-compliance-engineer
.claude/agents/**, .claude/commands/**, .claude/skills/**, .claude/hooks/**meta-engineering-expert

Detection mechanism (file-based lock, not env var):

  • write-specialist-lock.sh writes a lock file before the specialist Task starts
  • This hook reads the lock file and checks age < 300 seconds (TTL)
  • log-coordination-wrapper.sh removes the lock when the Task completes

See File-Lock Mechanism below for details.

Task Tool: Dual-Hook Chain

When Claude dispatches a specialist agent via the Task tool:

enforce-coordination.sh v4.0.0

Same coordination validation as Edit/Write (described above).

write-specialist-lock.sh v1.0.0

Writes a time-stamped lock file before the specialist agent executes. Only fires for known specialist agents (not coordination agents like product-owner or cloud-architect).

Specialist agents recognized: infrastructure-engineer, kubernetes-engineer, qa-engineer, security-compliance-engineer, observability-engineer, frontend-docs-engineer, meta-engineering-expert.

Lock file path: tmp/<project>/specialist-lock/<agent>-active.lock

Lock file content:

{
"agent": "infrastructure-engineer",
"started_at": "2026-03-08T10:00:00Z",
"epoch": 1772996400,
"session_id": "abc123",
"lock_file": "tmp/terraform-aws/specialist-lock/infrastructure-engineer-active.lock",
"ttl_seconds": 300,
"written_by": "write-specialist-lock.sh v1.0.0"
}

Layer 3: Post-Execution Audit (PostToolUse)

These hooks fire after a tool completes. PostToolUse hooks must never block (exit 0 always).

log-coordination-wrapper.sh v2.1.0

Purpose: Auto-log evidence for ALL agent completions (coordination + specialist).

  • Classifies agents into agent_class: "coordination" (product-owner, cloud-architect) or agent_class: "specialist" (all others)
  • Writes structured JSON log to coordination-logs/<agent>-YYYY-MM-DD.json
  • Coordination agents get agreement: 97 (design-level); specialists get agreement: 100 (binary done/not-done)
  • v2.1.0: Removes the specialist lock file on Task completion, immediately closing the delegation window

Log schema:

{
"timestamp": "2026-03-08T10:05:00Z",
"agent": "infrastructure-engineer",
"agent_class": "specialist",
"status": "success",
"agreement": 100,
"session_id": "abc123",
"description": "Implement ECS module",
"source": "log-coordination-wrapper.sh v2.0.0",
"project": "terraform-aws"
}

enforce-pdca-cycle.sh v1.0.0

Purpose: Track Plan-Do-Check-Act cycles per specialist per day. Escalates to HITL when a specialist exceeds the cycle limit.

  • State file: tmp/<project>/pdca-cycles/<agent>-YYYY-MM-DD.json
  • Default limit: 7 cycles (ADLC_MAX_PDCA_CYCLES)
  • When cycle_count >= max_cycles: emits HITL escalation warning via stderr
  • Status transitions: active -> escalated
  • Specialists only (coordination agents are excluded from PDCA tracking)

Layer 4: Session Initialization (SessionStart)

load-project-context.sh v2.1.0

Fires once at session start. Never blocks (exit 0 always).

Actions:

  1. Auto-creates evidence directories (8 directories + 3 test-result tiers):
    coordination-logs/
    test-results/ (+ tier1-static/, tier2-unit/, tier3-integration/)
    evidence/
    screenshots/
    cross-validation/
    architecture-decisions/
    cost-reports/
    pdca-cycles/
  2. Version drift detection: Compares VERSION file against 7 config files (settings.json, MANIFEST.json, package.json variants, docker-compose.yml, devcontainer.json)
  3. Prerequisite checks: docker, node, jq, terraform
  4. Memory loading: Detects .claude/memory/MEMORY.md and project-specific memory from .adlc/projects/<project>/MEMORY.md
  5. Coordination status: Reports whether PO+CA logs exist for today

Layer 5: Permission-Based Blocking (settings.json)

The settings.json permission model is the second line of defense (hooks are first). Permissions are enforced by Claude Code itself before hooks even fire.

3-Tier Permission Model

TierCountBehaviorExamples
allow34Auto-approved, no user promptRead(*), Glob(*), Grep(*), git status/log/diff, task:*, terraform state list/show
ask4User prompted for approvalterraform plan, tofu plan, Write(*), Edit(*)
deny30Permanently blockedterraform apply/destroy, git add/commit/push, rm -rf, sudo, npm publish, Read(.env/.pem/.key)

Environment Variables (16)

VariableValuePurpose
ADLC_ENFORCEMENT_MODEBLOCKINGAll hooks enforce (not advisory)
ADLC_AGENT_AGREEMENT_THRESHOLD95Minimum PO+CA agreement percentage
ADLC_STRICT_EVIDENCEtrueEvidence paths must resolve to real files
ADLC_MAX_PDCA_CYCLES7HITL escalation trigger per specialist
ADLC_NO_NATOtrueCompletion claims require evidence
ADLC_MANDATORY_AGENTSproduct-owner,cloud-architectRequired coordination agents
ADLC_CONSTITUTION_VERSION2.1.0Active constitution version
ADLC_EVIDENCE_DIRtmp/Root evidence directory

Layer 6: Rules-Layer Mitigation (CLAUDE.md + adlc-governance.md)

Some attack surfaces cannot be covered by hooks. The rules layer provides behavioral constraints enforced by Claude's instruction-following.

Ungated Surface: Text Response

Hook EventFires OnCan Block
UserPromptSubmitUser's incoming promptYes
PreToolUseTool calls (Edit/Write/Bash/Task)Yes
PostToolUseTool completionNo (audit only)
Text responseNOT HOOKABLENo

Mitigation: adlc-governance.md Content Classification requires PO+CA coordination logs before Claude produces implementation content (code blocks, architecture decisions, design comparisons, technology selection) in text output.

Content Classification

ClassificationExamples
REQUIRES PO+CAArchitecture decisions, design comparisons, technology selection, business value analysis, implementation recommendations, HITL deliverables
EXEMPTFactual lookups, CLI output interpretation, reading/summarising existing files, status checks, error debugging
Boundary defaultWhen ambiguous, requires coordination

Anti-Pattern Tracking

The governance rules document 23 anti-patterns with root causes, hooks/prevention mechanisms, and fix descriptions. See Governance Rules for the complete table.


File-Lock Mechanism (Specialist Delegation)

The file-lock mechanism solves the ENV_VAR_DETECTION_DEAD_ZONE problem discovered in v1.x of enforce-specialist-delegation.sh.

The Problem

Claude Code's Task tool does not export custom environment variables when spawning subagents. ADLC_ACTIVE_AGENT is never set in the Claude Code runtime, making env-var-based specialist detection permanently inert.

The Solution

Three hooks cooperate to create a file-based lock lifecycle:

PreToolUse Task                    Specialist Executing              PostToolUse Task
| | |
write-specialist-lock.sh enforce-specialist-delegation.sh log-coordination-wrapper.sh
| | |
Writes lock file ──────────────> Reads lock file (age < 300s?) ──> Removes lock file
(JSON with epoch, agent, If valid: ALLOW Edit/Write (immediate cleanup)
TTL=300s) If stale/missing: BLOCK

Lock File Details

PropertyValue
Pathtmp/<project>/specialist-lock/<agent>-active.lock
FormatJSON: {agent, started_at, epoch, session_id, ttl_seconds: 300}
TTL300 seconds (5 minutes)
Created bywrite-specialist-lock.sh (PreToolUse Task)
Read byenforce-specialist-delegation.sh (PreToolUse Edit/Write)
Removed bylog-coordination-wrapper.sh (PostToolUse Task)
Stale cleanupLocks older than TTL are silently deleted during read
HITL bypassADLC_DELEGATION_BYPASS=true in settings.local.json

Detection Priority

  1. File-based lock (primary) - works in all Claude Code contexts
  2. ADLC_ACTIVE_AGENT env var (fallback) - useful for CI/scripted invocations
  3. ADLC_ACTIVE_SPECIALIST env var (alias fallback)

Evidence Requirements (NATO Prevention)

Required Directory Structure

Created automatically by load-project-context.sh at session start:

tmp/<project>/
coordination-logs/ # PO, CA, and specialist agent logs
test-results/ # Test output
tier1-static/
tier2-unit/
tier3-integration/
evidence/ # Feature validation, deployment proof
screenshots/ # Visual verification
cross-validation/ # Multi-source accuracy checks
architecture-decisions/ # ADR evidence
cost-reports/ # FinOps evidence
pdca-cycles/ # PDCA state per specialist

Coordination Log Schema

{
"timestamp": "ISO8601",
"agent": "product-owner|cloud-architect|infrastructure-engineer|...",
"agent_class": "coordination|specialist",
"status": "success|failed",
"agreement": 97,
"session_id": "optional",
"description": "task description",
"source": "log-coordination-wrapper.sh v2.0.0",
"project": "terraform-aws"
}

NATO Detection Chain

  1. detect-nato-violation.sh scans prompt for 9 completion keywords
  2. If found, checks for evidence path patterns in the prompt text
  3. If ADLC_STRICT_EVIDENCE=true, validates that referenced paths resolve to actual files on disk
  4. Blocks (exit 2) if completion is claimed without evidence