{"slug": "i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce", "title": "I stopped writing rules for coding agents that CI could not enforce", "summary": "A developer at AgentsKit.io published a zero-dependency CLI called Agents Playbook that enforces coding rules for AI coding agents through executable gates rather than prose instructions. The tool allows teams to test individual rules like 'no-any' before pull requests, with explicit exception handling to prevent invisible bypasses.", "body_md": "I used to treat repository instructions as the finished product.\n\nWrite a careful `AGENTS.md`\n\n. Explain the architecture. Ban `any`\n\n. Require named\n\nexports. Tell the coding agent to keep files small and update the ADR when a\n\ncontract changes.\n\nThe document could be excellent and the next pull request could still violate\n\nit.\n\nThat is not always the agent's fault. A rule that exists only as prose asks\n\nevery contributor, human or automated, to remember it at exactly the right\n\nmoment. Review becomes the first place where the repository discovers that the\n\nrule was ignored.\n\nI started treating the instruction as the explanation and a gate as the\n\nenforcement.\n\nThe tempting response is to automate everything. That creates a different\n\nproblem: a wall of noisy checks that nobody understands and everyone learns to\n\nbypass.\n\nI now start with a failure that has already happened.\n\nSuppose an agent uses `any`\n\nto get a TypeScript change through quickly. The\n\nrepository rule says to use `unknown`\n\n, narrow the value, and validate external\n\ninput at runtime. The reviewer catches the shortcut, asks for a revision, and\n\nthe same mistake returns two pull requests later.\n\nThat is a good gate candidate because the rule is:\n\n“Choose the right abstraction” is not a good gate candidate. It still needs\n\nengineering judgment.\n\nI published the executable gates from\n\n[Agents Playbook](https://github.com/AgentsKit-io/agents-playbook) as a\n\nzero-dependency CLI. You can test one gate without adopting the rest of the\n\nplaybook.\n\nCreate a small fixture:\n\n``` js\nmkdir -p /tmp/playbook-gate-demo/src\nprintf 'export const answer: number = 42\\n' \\\n  > /tmp/playbook-gate-demo/src/example.ts\n```\n\nRun only the `no-any`\n\ngate:\n\n```\nnpx --yes @agentskit/playbook@0.1.0 \\\n  run no-any \\\n  --cwd /tmp/playbook-gate-demo\n```\n\nThe valid file passes:\n\n```\nno-any: OK. 0 escape-hatched.\n```\n\nNow replace it with the shortcut:\n\n``` js\nprintf 'export const unsafe: any = 42\\n' \\\n  > /tmp/playbook-gate-demo/src/example.ts\n\nnpx --yes @agentskit/playbook@0.1.0 \\\n  run no-any \\\n  --cwd /tmp/playbook-gate-demo\n```\n\nThe command exits non-zero and points to the violation:\n\n```\nsrc/example.ts:1:22 — `any` in type position.\nUse `unknown` + a runtime schema parse, or a specific type.\n```\n\nThe useful part is not that a script can search for `any`\n\n. Mature TypeScript\n\nrepositories should normally use the AST-based\n\n`@typescript-eslint/no-explicit-any`\n\nrule. The useful part is the shape of the\n\nfeedback:\n\nThe policy and the gate have different jobs, but they point in the same\n\ndirection.\n\nAn absolute rule often becomes dishonest.\n\nThere are boundaries where a legacy dependency, generated type, or migration\n\nreally does require a temporary exception. If the only available responses are\n\n“rewrite the dependency” or “disable the check,” people disable the check.\n\nThe reference gate accepts an explicit same-line exception:\n\n``` js\nexport const legacyValue: any = input // allow-any: upstream SDK has no types\n```\n\nThat comment is not a magic phrase that makes the type safe. It makes the\n\ndecision visible. The gate counts escape hatches, and a repository can keep a\n\nbaseline so the number does not quietly grow.\n\nThis is the difference between an exception and an invisible bypass:\n\nA gate that cannot represent a legitimate exception will eventually be worked\n\naround outside the gate.\n\nI want the shortest useful loop to be available before a pull request.\n\nFor a repository using the Playbook CLI, the package scripts can stay small:\n\n```\n{\n  \"scripts\": {\n    \"check:agent-rules\": \"agents-playbook run no-any named-exports\",\n    \"precommit\": \"pnpm check:agent-rules\"\n  },\n  \"devDependencies\": {\n    \"@agentskit/playbook\": \"0.1.0\"\n  }\n}\n```\n\nCI should run the same command. A pre-commit hook is a convenience, not the\n\ntrust boundary: hooks can be skipped, while the required CI check protects the\n\nshared branch.\n\nThe fast local path matters for coding agents in particular. If an agent can\n\nrun a focused gate immediately after editing, it can repair a violation while\n\nthe relevant context is still active. Waiting for a large repository pipeline\n\nturns a five-second correction into another review cycle.\n\nThe `no-any`\n\ngate can prove that it did not find the pattern it recognizes. It\n\ncannot prove that the replacement type is correct.\n\nThe named-export gate cannot prove that an API is well designed. The file-size\n\ngate cannot prove that splitting a file improved cohesion. A secret scanner\n\ncannot prove that authorization is correct.\n\nThis boundary is important when agents are involved. Machine-checkable rules\n\nare attractive because they produce a clean pass or fail, but engineering\n\nquality is larger than the set of things that are easy to count.\n\nI use three categories:\n\n| Rule | Best enforcement |\n|---|---|\n| Deterministic syntax or repository invariant | Automated gate |\n| Contextual design choice | Review checklist and examples |\n| High-impact ambiguous decision | Explicit human approval |\n\nIf a design rule cannot be checked without guessing intent, I leave it in the\n\nreview layer. Automating a weak proxy can be worse than admitting that a human\n\ndecision remains.\n\nThe Playbook currently includes 13 zero-dependency reference gates covering\n\nconcerns such as secrets, file size, named exports, ADR/RFC requirements,\n\ninternationalization, design tokens, native HTML, and PR intent.\n\nI would not enable all 13 on day one.\n\nThe sequence I use is:\n\nThat keeps governance attached to evidence. Every check should be able to\n\nanswer: “Which failure are you here to prevent?”\n\nI created and maintain Agents Playbook, so this is not a neutral tool review.\n\nThe CLI and all 13 reference gates are open source, and the narrow experiment\n\nabove is intentionally easy to reproduce without an API key or model call.\n\nPreparation disclosure: I used AI tools to help organize and critique this\n\ndraft. I ran the commands against the published package, inspected the gate\n\nsource and tests, checked the claims against the public repository, and stand\n\nbehind the final text.\n\nIf you already enforce a coding-agent rule in CI, I am interested in the rule\n\nthat produced the most useful failure message—not the largest policy file.", "url": "https://wpnews.pro/news/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce", "canonical_source": "https://dev.to/agentskit/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce-5hn9", "published_at": "2026-07-28 16:38:11+00:00", "updated_at": "2026-07-28 17:04:39.833768+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["AgentsKit.io", "Agents Playbook", "TypeScript"], "alternates": {"html": "https://wpnews.pro/news/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce", "markdown": "https://wpnews.pro/news/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce.md", "text": "https://wpnews.pro/news/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce.txt", "jsonld": "https://wpnews.pro/news/i-stopped-writing-rules-for-coding-agents-that-ci-could-not-enforce.jsonld"}}