Skip to content

Commit edf7b31

Browse files
m9751claude
andauthored
feat(v1.8): AGENTS.md enforcement + empirical enforcement (#22)
* feat(v1.8): AGENTS.md enforcement + empirical enforcement 6 new hook ports, 2 guides, 1 smoke test, updated normalize lib. Two Codex adversarial passes — 6 findings fixed before tag. Hooks: - agentsmd-bash-gate.sh (normalize + __NH_CONFLICT__ fail-closed + scoped allowlist) - agentsmd-session-inject.sh - three-failure-stop-gate.sh (normalize Grok payloads) - claim-evidence-gate-dispatch.sh - claim-evidence-gate.sh (bash floor, Gate 4) - aof-eval-opportunity-counter.sh (env-var secret scrub + whitespace trim) Guides: - guides/advanced/when-to-write-a-hook.md (advisory exception + dedup question) - guides/advanced/go-hook-dispatch-pattern.md Tests: - tests/smoke/hooks/grok-shape-normalize.sh (8/8 pass) Docs: - AGENT_FRAMEWORK.md v1.7 → v1.8, §5.3 matrix +5 rows - CHANGELOG.md v1.8 section - README.md + examples/hooks/README.md updated Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * fix(v1.8): resolve 5 PRM-INFRA-001 Stage 1 findings before ship HIGH agentsmd-bash-gate: remove broad case-arm allowlist (cat *AGENTS.md bypass); replaced with anchored grep -qF on $AGENTS_PATH only. HIGH three-failure-stop-gate: add no-op stubs for bc_record_exit/bc_write when breadcrumb-lib.sh is absent — prevents exit-code corruption (127) masking legitimate exit 2 blocks. MED aof-eval-opportunity-counter: fix python3 silent-continue in insert_opportunity (|| return on json-encode failure); use json.dumps for tool_name and session_id to prevent JSON injection. MED claim-evidence-gate: extract ALL backtick-quoted paths per hit, not just the first — multi-path claims now check every cited path. MED smoke test: add snake_case control payload to Test 6 to prevent false-green from gate-blocks-everything scenario. Smoke: 9/9 pass. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent d7b3237 commit edf7b31

15 files changed

Lines changed: 1420 additions & 53 deletions

AGENT_FRAMEWORK.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Agent Operating Framework v1.7
1+
# Agent Operating Framework v1.8
22

33
> A behavioral operating system for AI coding agents — born from production failures, not theory.
44
>
@@ -304,7 +304,7 @@ See [`guides/enforcement-architecture.md`](guides/enforcement-architecture.md) f
304304

305305
### 5.3 Rule-to-Hook Coverage
306306

307-
The escalation ladder above (memory → rule → hook) is aspirational — not every rule has a hook backing it, and the framework does not pretend otherwise. The matrix below is the accurate accounting of what ships in v1.6:
307+
The escalation ladder above (memory → rule → hook) is aspirational — not every rule has a hook backing it, and the framework does not pretend otherwise. The matrix below is the accurate accounting of what ships in v1.8:
308308

309309
| Rule | Hook | Fail mode | Blast radius | Coverage |
310310
|---|---|---|---|---|
@@ -324,6 +324,16 @@ Five of six rules ship with hook backing as of v1.5. The single remaining adviso
324324
- If you adopt the framework expecting all rules to be system-enforced, this matrix is the reality check.
325325
- If you need stronger guarantees on the advisory rules, write your own `PreToolUse` hooks against your environment's specifics — the framework's hooks are reference implementations, not exhaustive coverage.
326326

327+
**AGENTS.md enforcement hooks** (v1.8 — repo governance):
328+
- [`agentsmd-bash-gate.sh`](examples/hooks/agentsmd-bash-gate.sh) — blocks Bash commands that touch `~/repos/<name>/` unless AGENTS.md for that repo was Read this session *(fail-mode: closed, blast-radius: destructive)*
329+
- [`agentsmd-session-inject.sh`](examples/hooks/agentsmd-session-inject.sh) — SessionStart hook; when cwd is inside a repo, prints AGENTS.md to stdout as session context *(fail-mode: open, blast-radius: advisory)*
330+
331+
**Empirical enforcement hooks** (v1.8 — claim and discipline gates):
332+
- [`three-failure-stop-gate.sh`](examples/hooks/three-failure-stop-gate.sh) — blocks the 4th `fix(...)` commit in 2 hours unless a `# halted-and-researched:` attestation is present; 6,262 fires / 13 blocks in production *(fail-mode: advisory — fail-open on repo-resolve failure)*
333+
- [`claim-evidence-gate-dispatch.sh`](examples/hooks/claim-evidence-gate-dispatch.sh) — cross-platform front door for Gate 4; probes native Go binary (two-probe trust check) before falling back to bash floor; live telemetry Mac 2026-06-27 PR #571 *(fail-mode: closed, blast-radius: security)*
334+
- [`claim-evidence-gate.sh`](examples/hooks/claim-evidence-gate.sh) — bash floor for Gate 4; blocks assertion language and path-cited claims without a session Read breadcrumb *(fail-mode: closed, blast-radius: security)*
335+
- [`aof-eval-opportunity-counter.sh`](examples/hooks/aof-eval-opportunity-counter.sh) — PostToolUse/SessionStart/UserPromptSubmit hook; POSTs to `eval.opportunities` for DPMO measurement; health signal = `eval.opportunities` rows (NOT `hook_events` fire_count); requires `AOF_EVAL_SUPABASE_URL` + `AOF_EVAL_SUPABASE_KEY` env vars *(fail-mode: open, blast-radius: telemetry)*
336+
327337
**Meta-hooks** (not bound to a single rule):
328338
- [`deprecated-field-gate.sh`](examples/hooks/deprecated-field-gate.sh) — template for blocking writes that reference deprecated DB columns or API fields *(fail-mode: closed, blast-radius: destructive)*
329339
- [`empty-rule-body-gate.sh`](examples/hooks/empty-rule-body-gate.sh) — pre-merge CI check that rejects rule files with empty bodies (< 200 bytes) or missing `## Why` sections *(fail-mode: closed, blast-radius: security — protects framework integrity against false-positive "applied" claims)*
@@ -371,7 +381,7 @@ See [`guides/rule-consolidation.md`](guides/rule-consolidation.md) for a worked
371381

372382
---
373383

374-
## Framework Structure (v1.5)
384+
## Framework Structure (v1.8)
375385

376386
```
377387
AGENT_FRAMEWORK.md ← This file. The complete behavioral spec.
@@ -391,6 +401,8 @@ guides/
391401
hook-audit-methodology.md ← 4-track audit pattern (v1.6)
392402
silent-failure-discipline.md ← Every fail-open path must log (v1.7)
393403
agents-md-standard.md ← Three-level repo governance contract (v1.7)
404+
when-to-write-a-hook.md ← Decision test for hook vs. rule (v1.8)
405+
go-hook-dispatch-pattern.md ← Go binary + bash floor dispatch pattern (v1.8)
394406
examples/
395407
claude-code-rules/ ← Sample rule files for Claude Code
396408
hooks/ ← Reference hook implementations (Claude Code-specific)
@@ -406,6 +418,7 @@ Full per-release notes live in [CHANGELOG.md](CHANGELOG.md). The framework file
406418

407419
Headline changes from recent versions:
408420

421+
- **v1.8** — AGENTS.md enforcement + empirical enforcement release. 6 new hooks: `agentsmd-bash-gate.sh`, `agentsmd-session-inject.sh`, `three-failure-stop-gate.sh`, `claim-evidence-gate-dispatch.sh`, `claim-evidence-gate.sh`, `aof-eval-opportunity-counter.sh`. 2 new guides: `when-to-write-a-hook.md` and `go-hook-dispatch-pattern.md`. New smoke test: `tests/smoke/hooks/grok-shape-normalize.sh`. Updated `lib/normalize-hook-input.sh` with dual-shape conflict detection. §5.3 matrix extended with 5 new hook rows. CEG telemetry live Mac PR #571.
409422
- **v1.7** — Provable hooks release: `startup-gate.sh` (SessionStart governance check), `normalize-hook-input.sh` (cross-runtime payload normalization), `hook-telemetry-stop.sh` (session-end telemetry). New guides: `silent-failure-discipline.md` (ADR 0012 — every fail-open path must log) and `agents-md-standard.md` (three-level repo governance contract). Incidents #36#38.
410423
- **v1.6** — Hook operations layer: `breadcrumb-lib.sh` shared session library, `CLAUDE_HOOKS_SAFE_MODE` emergency bypass pattern, `# fail-mode: silent-skip` taxonomy tier for watcher-class hooks. New guides: `hook-operations.md` (the three operational questions) and `hook-audit-methodology.md` (4-track audit pattern). §5.2 updated with bypass + breadcrumb protocol as standard requirements. AOF self-eval harness (`b3d8451`) on main.
411424
- **v1.5**`secure-config-gate.sh`, `focus-breadcrumb.sh` + `focus-confirmation-gate.sh`, `dormant-code-gate.sh`. §5.3 coverage moves from 3-of-6 enforced to **5-of-6 enforced**. `no-local-infrastructure` rewritten as a hosting decision framework (advisory by design).

CHANGELOG.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,74 @@ All notable changes to this framework follow [Keep a Changelog](https://keepacha
44

55
---
66

7+
## [1.8] — 2026-06
8+
9+
### Background
10+
11+
v1.7 answered: can you prove hooks work? v1.8 answers: do you ship the hooks that enforce the rules you already have written? Two rule gaps had hooks drafted in the private config but not ported to the public repo: AGENTS.md enforcement (repo governance) and empirical discipline gates (three-failure stop, claim-evidence). Both are now public.
12+
13+
### What v1.8 covers ("AGENTS.md enforcement + empirical enforcement" release)
14+
15+
Six new hook ports, two new guides, one new smoke test, and updated `lib/normalize-hook-input.sh` with dual-shape conflict detection.
16+
17+
### Added
18+
19+
- **`examples/hooks/agentsmd-bash-gate.sh`** — PreToolUse gate for Bash. Blocks commands that touch `~/repos/<name>/` unless AGENTS.md for that repo was Read this session. Complements `read-gate.sh` (which covers Edit/Write) with Bash-side coverage. Port hardening: added `source lib/normalize-hook-input.sh` and fixed the parser to read `tool_input.command` (not `input.command`) for correct Claude Code envelope handling.
20+
21+
- **`examples/hooks/agentsmd-session-inject.sh`** — SessionStart advisory hook. When cwd is inside `~/repos/<name>/`, prints AGENTS.md to stdout so Claude loads it as session context before the first user prompt. Ports directly; no hardening needed.
22+
23+
- **`examples/hooks/three-failure-stop-gate.sh`** — PreToolUse gate for Bash. Blocks the 4th `fix(...)` commit within 2 hours unless the commit body contains `# halted-and-researched: <one-line>`. State stored in `~/.claude/state/three-failure-stop/<repo>__<file>.log`. Production telemetry: 6,262 fires / 13 blocks. Fail-open on repo-resolve failure (advisory by design — false-positives more disruptive than false-negatives for this pattern).
24+
25+
- **`examples/hooks/claim-evidence-gate-dispatch.sh`** — Cross-platform dispatch wrapper for Gate 4. Probes the native Go binary with a two-probe trust check (must allow a clean payload AND block a claim-shaped payload) before trusting it. Falls back to `claim-evidence-gate.sh` if the binary is missing, wrong architecture, or fails either probe. Fail-closed with no runnable gate at all. Telemetry breadcrumb fires at the dispatch layer (single choke point). CEG fire_count>0 on Mac confirmed 2026-06-27 (PR #571).
26+
27+
- **`examples/hooks/claim-evidence-gate.sh`** — Bash floor for Gate 4. Blocks assertion language patterns and explicit path-cited claims without a session Read breadcrumb. Pattern list aligned one-for-one with the Go binary's `assertionPatterns` (softened per ADR 0064 — bare "confirmed"/"verified" removed after 58/59 audit showed false positives). Empty stdin fails closed. Self-exempts via path-allowlist (the file itself is allowlisted to prevent gate self-block during deployment).
28+
29+
- **`examples/hooks/aof-eval-opportunity-counter.sh`** — Fires on PreToolUse, SessionStart, and UserPromptSubmit (three settings.json registrations). POSTs to `eval.opportunities` table for DPMO measurement. **Health signal: `eval.opportunities` row count.** `telemetry.hook_events` fire_count is expected to be 0 for this hook (it does not use `bc_write` / `hook-telemetry-stop`). Port hardening: replaced hardcoded Supabase URL + anon key with `AOF_EVAL_SUPABASE_URL` + `AOF_EVAL_SUPABASE_KEY` env vars; hook fails open if either is unset.
30+
31+
- **`guides/advanced/when-to-write-a-hook.md`** — Decision test for hook vs. rule. Three questions: (1) has the rule been violated with real consequence? (2) can the hook detect the violation mechanically? (3) is the blast radius acceptable? Includes hook type table by blast radius, what belongs in a rule (not a hook), hook anatomy invariants, and a 4-step test matrix before shipping.
32+
33+
- **`guides/advanced/go-hook-dispatch-pattern.md`** — Canonical pattern for shipping Go binary hooks with a bash fallback. Explains the 2026-06-13 incident (Mach-O binary failing open on Win11), the two-probe trust model, build-at-install-time pattern, gitignore for architecture-specific binaries, bash floor alignment requirements, and settings.json registration via dispatch wrapper only.
34+
35+
- **`tests/smoke/hooks/grok-shape-normalize.sh`** — 6-case smoke test for `lib/normalize-hook-input.sh`. Tests: camelCase normalization, snake_case passthrough, dual-shape conflict sentinel (`__NH_CONFLICT__`), empty input, malformed JSON. Gate: all 6 PASS before tagging v1.8.
36+
37+
- **`examples/hooks/lib/normalize-hook-input.sh`** — Updated from v1.7 with dual-shape conflict detection. When a payload carries a field in both camelCase and snake_case shapes, `nh_normalize` now emits `__NH_CONFLICT__` sentinel instead of normalizing. The dispatch wrapper and gate check for this sentinel and fail closed (block) — a dual-shape payload is unevaluable; scanning one branch while the runtime executes the other risks claim bypass.
38+
39+
- **3 new sanitized incidents** in `INCIDENTS.md` (#39, #40, #41).
40+
41+
### Changed
42+
43+
- **`AGENT_FRAMEWORK.md`** — version bump to v1.8. §5.3 matrix extended with 5 new hook rows (AGENTS.md enforcement + empirical gates). Framework structure updated with two new advanced guides. Version history entry added.
44+
- **`README.md`** — v1.8 references, 41 incidents, 5 new hooks in hook table.
45+
- **`examples/hooks/README.md`** — 5 new inventory rows (one per new hook, plus counter).
46+
47+
### What is NOT in v1.8 (deferred to v1.9)
48+
49+
- **Go binary for claim-evidence-gate** — the dispatch wrapper + bash floor ship; the public Go source does not. The private Go binary is architecture-specific (Mach-O arm64) and requires build tooling. Public port deferred until a portable build pipeline exists for the AOF repo.
50+
- **FORGET mechanism** — carried from v1.7. Still the hard prerequisite for Phase D global deploy of the memory system.
51+
- **`distill-memory.py` regex fix** — resolved in private config (2026-06-27); not a public AOF artifact. Removed from deferred list.
52+
53+
### Release checklist
54+
55+
- [x] Port `agentsmd-bash-gate.sh` (with normalize-hook-input + tool_input.command fix)
56+
- [x] Port `agentsmd-session-inject.sh`
57+
- [x] Port `three-failure-stop-gate.sh`
58+
- [x] Port `claim-evidence-gate-dispatch.sh`
59+
- [x] Port `claim-evidence-gate.sh` (bash floor)
60+
- [x] Port `aof-eval-opportunity-counter.sh` (with secret scrub)
61+
- [x] Write `guides/advanced/when-to-write-a-hook.md`
62+
- [x] Write `guides/advanced/go-hook-dispatch-pattern.md`
63+
- [x] Write `tests/smoke/hooks/grok-shape-normalize.sh`
64+
- [x] Update `lib/normalize-hook-input.sh` (dual-shape conflict)
65+
- [x] Smoke test PASS (6/6)
66+
- [x] Edit `AGENT_FRAMEWORK.md` v1.7 → v1.8 + §5.3 matrix + structure
67+
- [x] Edit `README.md`
68+
- [x] Edit `examples/hooks/README.md`
69+
- [x] Insert CHANGELOG v1.8
70+
- [ ] `git tag v1.8 && git push --tags`
71+
- [ ] Create GitHub release
72+
73+
---
74+
775
## [1.7] — 2026-06
876

977
### Background

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ See [guides/getting-started.md](guides/getting-started.md) for the full adoption
1818

1919
You've set up CLAUDE.md. You've built a few skills. You're using Projects Memory. But outputs are still inconsistent, the agent ignores rules under pressure, and you're manually reviewing everything.
2020

21-
This framework is the next step. It adds rules with documented enforcement contracts (some advisory by design), circuit breakers (stop after 3 failures), and an escalation model (advice → law → barriers) that makes your CLAUDE.md actually stick. See the [rule-to-hook coverage matrix](AGENT_FRAMEWORK.md#53-rule-to-hook-coverage) for what is system-enforced versus advisory in v1.7 — five of six rules ship with hooks; one (`no-local-infrastructure`) is a decision framework that is advisory by design.
21+
This framework is the next step. It adds rules with documented enforcement contracts (some advisory by design), circuit breakers (stop after 3 failures), and an escalation model (advice → law → barriers) that makes your CLAUDE.md actually stick. See the [rule-to-hook coverage matrix](AGENT_FRAMEWORK.md#53-rule-to-hook-coverage) for what is system-enforced versus advisory in v1.8 — five of six rules ship with hooks; one (`no-local-infrastructure`) is a decision framework that is advisory by design.
2222

2323
If you're just getting started with Claude Code, read the beginner guides first. If you've hit the wall where your CLAUDE.md "stops working," [start here](guides/from-beginner-to-framework.md).
2424

@@ -49,7 +49,7 @@ Every rule exists because its absence caused a specific, documented failure. See
4949
## Library Contents
5050

5151
### The Framework
52-
- **[AGENT_FRAMEWORK.md](AGENT_FRAMEWORK.md)** — The complete framework (v1.7). Use as your project's CLAUDE.md.
52+
- **[AGENT_FRAMEWORK.md](AGENT_FRAMEWORK.md)** — The complete framework (v1.8). Use as your project's CLAUDE.md.
5353

5454
### Guides
5555
- **[From Beginner to Framework](guides/from-beginner-to-framework.md)** — You've built CLAUDE.md and skills but outputs are inconsistent. Here's why and what to do next.
@@ -93,13 +93,19 @@ Shell scripts that enforce rules at the tool-call level — the third tier of th
9393
| [startup-gate.sh](examples/hooks/startup-gate.sh) | SessionStart advisory | Checks repo, AGENTS.md, active plan, and hook registration gap at session start; writes drift report |
9494
| [hook-telemetry-stop.sh](examples/hooks/hook-telemetry-stop.sh) | Stop advisory | Reads fire/block breadcrumbs at session end; bulk-INSERTs telemetry rows |
9595
| [lib/normalize-hook-input.sh](examples/hooks/lib/normalize-hook-input.sh) | Library (source only) | Normalizes hook payload field names and tool-name literals across Claude Code and Grok runtimes |
96+
| [agentsmd-bash-gate.sh](examples/hooks/agentsmd-bash-gate.sh) | PreToolUse hard block | Blocks Bash in `~/repos/<name>/` unless AGENTS.md for that repo was Read this session |
97+
| [agentsmd-session-inject.sh](examples/hooks/agentsmd-session-inject.sh) | SessionStart advisory | Injects AGENTS.md into session context when cwd is inside a repo |
98+
| [three-failure-stop-gate.sh](examples/hooks/three-failure-stop-gate.sh) | PreToolUse advisory block | Blocks 4th `fix(...)` commit in 2 hours without a halted-and-researched attestation |
99+
| [claim-evidence-gate-dispatch.sh](examples/hooks/claim-evidence-gate-dispatch.sh) | PreToolUse hard block | Cross-platform Gate 4 dispatcher; probes Go binary (two-probe trust check), falls back to bash floor |
100+
| [claim-evidence-gate.sh](examples/hooks/claim-evidence-gate.sh) | PreToolUse hard block | Bash floor for Gate 4; blocks assertion language and path-cited claims without a session Read |
101+
| [aof-eval-opportunity-counter.sh](examples/hooks/aof-eval-opportunity-counter.sh) | Multi-event advisory | DPMO counter; POSTs to `eval.opportunities` per tool call; health = row count |
96102

97103
See [§5.3 Rule-to-Hook Coverage](AGENT_FRAMEWORK.md#53-rule-to-hook-coverage) for which rule each hook backs and the full enforced-vs-advisory accounting.
98104

99105
See [examples/hooks/README.md](examples/hooks/README.md) for setup instructions and the breadcrumb pattern.
100106

101107
### Incident Log
102-
- **[INCIDENTS.md](INCIDENTS.md)**38 sanitized incidents linking real failures to the rules they produced. Month-precision dates.
108+
- **[INCIDENTS.md](INCIDENTS.md)**41 sanitized incidents linking real failures to the rules they produced. Month-precision dates.
103109

104110
## The Key Insight
105111

0 commit comments

Comments
 (0)