feat(v1.8): AGENTS.md enforcement + empirical enforcement#22
Conversation
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>
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>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6b6f2ce7a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # Broad pattern matching (any command containing "AGENTS.md") was bypassable via | ||
| # "cat /other/repo/AGENTS.md; <dangerous command targeting $REPO_NAME>". | ||
| # Fix: anchor to $AGENTS_PATH only. The anchored grep below is the sole allow path. | ||
| if echo "$COMMAND" | grep -qF "$AGENTS_PATH"; then |
There was a problem hiding this comment.
Reject compound AGENTS.md read commands
When the first Bash call for a repo contains the exact AGENTS.md path plus any other repo operation, this branch exits 0 before checking the read breadcrumb (for example, cat ~/repos/foo/AGENTS.md; git -C ~/repos/foo status). That lets a single compound shell command bypass the AGENTS.md enforcement the hook is meant to provide, so the allow path needs to verify the command is only reading that AGENTS.md file rather than just containing its path.
Useful? React with 👍 / 👎.
| GC_MSG_BODY=$(echo "$COMMAND" | grep -oE -- '(-m[[:space:]]+|--message[[:space:]]+|--message=)("[^"]*"|[^ ]+)' | head -1 \ | ||
| | sed -E 's/^(-m[[:space:]]+|--message[[:space:]]+|--message=)//; s/^"(.*)"$/\1/') |
There was a problem hiding this comment.
Parse every commit message paragraph
This only captures the first -m/--message occurrence, but Git supports repeated -m options and concatenates them as separate paragraphs (git-scm docs: If multiple -m options are given, their values are concatenated as separate paragraphs.). In the common git commit -m "fix(x): ..." -m "# halted-and-researched: ..." form, the gate sees only the subject, misses the attestation in the body, and blocks the documented override on the 4th fix commit.
Useful? React with 👍 / 👎.
| reads_log="$(bc_dir)/$(bc_session_key)-reads-log" | ||
| [ -f "$reads_log" ] || return 1 |
There was a problem hiding this comment.
Ship or reuse the read breadcrumb producer
This hard-blocking gate relies on $(bc_dir)/$(bc_session_key)-reads-log entries containing READ, but I checked the public hooks with rg -n "reads-log| READ " examples/hooks and found no producer for that contract; the existing read-gate.sh uses a different agent-reads-${CLAUDE_SESSION_ID}.log format. With only the v1.8 public hooks installed, a user can Read the cited file and still every verified against \path`` claim is blocked because this log is never populated.
Useful? React with 👍 / 👎.
Summary
AOF v1.8 — "AGENTS.md enforcement + empirical enforcement"
6 new hook ports:
agentsmd-bash-gate.sh— blocks Bash in repos without AGENTS.md readagentsmd-session-inject.sh— injects AGENTS.md at session startthree-failure-stop-gate.sh— blocks 4th fix(...) commit without attestationclaim-evidence-gate-dispatch.sh— cross-platform Gate 4 dispatcherclaim-evidence-gate.sh— bash floor for Gate 4aof-eval-opportunity-counter.sh— DPMO telemetry counter2 new guides:
when-to-write-a-hook.md,go-hook-dispatch-pattern.mdSmoke test:
tests/smoke/hooks/grok-shape-normalize.sh— 9/9 passQuality gates passed:
Test plan
bash tests/smoke/hooks/grok-shape-normalize.shagentsmd-bash-gate.shblocks Grok payload, allows harmless snake_case🤖 Generated with Claude Code