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, fullstack-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