{"slug": "config-files-vs-hooks-where-agent-enforcement-actually-belongs", "title": "Config files vs hooks: where agent enforcement actually belongs", "summary": "A developer outlined a four-level enforcement ladder for AI coding agents, arguing that rules which must never be violated belong in deterministic hooks and CI rather than in prose configuration files like CLAUDE.md. The approach places linters and CI at the most reliable level, PreToolUse hooks next, and reserves prose for judgment-based scoped and always-on rules, since prose is sampled rather than executed. The developer packaged the split into a commercial kit, AgentConfig Studio, with a free MIT-licensed Next.js sample.", "body_md": "A rule in CLAUDE.md is a request. A hook is a guarantee. Mixing these\n\ntwo up is the most common config mistake I see: teams write \"never\n\ncommit secrets\" as prose, then act surprised when a secret gets\n\ncommitted. This post is the split I use: what belongs in prose, what\n\nbelongs in a hook, and the four-level ladder that decides.\n\nProse config changes what the model tries to do. Hooks and CI change\n\nwhat is possible to do. Anything that must never happen does not\n\nbelong in prose, because prose is sampled, not executed.\n\nFor any rule you want, ask which level it actually needs:\n\n```\nLevel 1  Linter/types/CI      deterministic, catches most code issues\nLevel 2  Hooks (PreToolUse)   blocks the command/file before it runs\nLevel 3  Scoped rules         prose, loads only for matching files\nLevel 4  Always-on config     prose, worth spending context on every call\n```\n\nThe ladder is ordered by reliability, and the reliable end is free of\n\ntokens. Every rule you can push down a level saves context and removes\n\na failure mode.\n\nConcrete examples from my own setup:\n\n```\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      { \"matcher\": \"Bash\", \"command\": \"block-dangerous.sh\" },\n      { \"matcher\": \"Edit|Write\", \"command\": \"protect-env.sh\" }\n    ]\n  }\n}\n```\n\n`rm -rf` outside a target dir, force-push\nto main, `drop table`. A regex in a PreToolUse hook blocks these\nwith certainty. In prose, \"be careful with rm\" works maybe nine\ntimes out of ten, and you only hear about the tenth.`.env`, keys, generated files. The hook\nreturns a block reason and the agent adapts. No token spent until\nthe moment of the attempt.\nThe things hooks cannot decide, because they need judgment:\n\nThe clearest smell is any line in CLAUDE.md that starts with \"always\n\nrun\" or \"never commit\". If CI can check it, CI should check it.\n\nEvery prose duplicate of a linter rule is a line of context spent on\n\nsomething the machine already guarantees, and a contradiction waiting\n\nwhen the two drift.\n\nOur kits keep prose for judgment and push everything checkable down\n\nthe ladder. That is also why the validator rejects placeholder\n\ninstruction files: prose that restates the linter is worse than no\n\nfile, because it trains you to stop reading your own config.\n\nOlder setups (plain .cursorrules, bare AGENTS.md) have no hook layer.\n\nThe ladder still applies, one rung lower: CI and linters carry the\n\nhard guarantees, prose carries judgment, and the \"hard guarantees in\n\nprose\" gap is covered by a pre-commit hook in git itself, which every\n\nsetup has.\n\n*Our kits ship this split pre-built: prose for judgment, hooks and validator rules for guarantees, in [AgentConfig Studio](https://piekwerk.gumroad.com/l/agentconfig-studio). Try the approach on Next.js first: [free sample kit (MIT)](https://piekwerk.gumroad.com/l/free-sample-nextjs).*", "url": "https://wpnews.pro/news/config-files-vs-hooks-where-agent-enforcement-actually-belongs", "canonical_source": "https://dev.to/piekwerk/config-files-vs-hooks-where-agent-enforcement-actually-belongs-2gi8", "published_at": "2026-09-22 06:01:16+00:00", "updated_at": "2026-09-22 06:22:48.571605+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "mlops"], "entities": ["AgentConfig Studio", "Next.js", ".cursorrules", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/config-files-vs-hooks-where-agent-enforcement-actually-belongs", "markdown": "https://wpnews.pro/news/config-files-vs-hooks-where-agent-enforcement-actually-belongs.md", "text": "https://wpnews.pro/news/config-files-vs-hooks-where-agent-enforcement-actually-belongs.txt", "jsonld": "https://wpnews.pro/news/config-files-vs-hooks-where-agent-enforcement-actually-belongs.jsonld"}}