Governed Agent Cookbook
Patterns for structurally constraining AI agents. Each pattern is independent: adopt the ones that fit your risk profile.
Pattern Overview
| # | Pattern | When | Prevents |
|---|---|---|---|
| 1 | Catastrophic Command Block | Before shell commands | Irreversible filesystem destruction |
| 2 | Security Pattern Interceptor | Before code writes | SSRF, injection, XSS in source |
| 3 | Pre-Write Linter Gate | Before code writes | Invalid or lint-failing code |
| 4 | Convention Allowlist | Before frontend writes | Banned libraries, deprecated patterns |
| 5 | Triggered Test Runner | After high-risk edits | Security regressions |
| 6 | Tiered Autonomy Gate | Before safety-critical writes | Unreviewed changes to core paths |
| 7 | Duty-Shirking Detector | Before commits | Stubs, TODO placeholders, CI weakening |
| 8 | Completion Quality Gate | Before completion | Unverified code reaching review |
| 9 | Credential Deny List | Before any file operation | Agent accessing secrets |
Choosing Patterns
| Building... | Start with |
|---|---|
| A personal tool (just you) | 1, 3, 9 |
| A tool that affects others | 1, 2, 3, 6, 9 |
| A tool with autonomous actions | 1, 2, 3, 5, 6, 7, 9 |
| A tool in a regulated domain | All nine |
Pattern 1: Catastrophic Command Block
Fires: Before any shell command. Prevents: rm -rf ~/, force pushes to main, database drops.
const BLOCKED = [
// rm with a recursive and a force flag (any order, combined or separate: -rf, -fr, -r -f,
// --recursive --force) aimed at ~, / or $HOME
/\brm\b(?=[^;&|\n]*\s(?:-[a-zA-Z]*[rR]|--recursive\b))(?=[^;&|\n]*\s(?:-[a-zA-Z]*f|--force\b))[^;&|\n]*\s(?:--\s+)?(?:~|\/|\$HOME\b|\$\{HOME\})/,
// git push with -f, --force, --force-with-lease or a +refspec, naming main or master
/\bgit\s+push\b(?=[^;&|\n]*(?:\s-[a-zA-Z]*f\b|\s--force(?:-with-lease|-if-includes)?\b|\s\+\S))(?=[^;&|\n]*\b(?:main|master)\b)/,
/DROP\s+DATABASE/i
];
function checkCommand(cmd) {
for (const pattern of BLOCKED) {
if (pattern.test(cmd))
return { blocked: true, reason: `Matched destructive pattern` };
}
return { blocked: false };
}Principle: Structural prevention is more reliable than agent judgment for irreversible actions.
Pattern denylists are a floor, not a guarantee: shell aliases, variables, eval, scripts and other tools can all reach the same effect without matching. For irreversible actions, pair them with an allowlist of permitted commands or run the agent in a sandbox that cannot reach the protected paths.
Pattern 2: Security Pattern Interceptor
Fires: Before any code is written to disk. Prevents: SSRF, injection, XSS, and other vulnerability patterns landing in source files.
Scans proposed file content for known dangerous patterns (eval with user input, unsanitised HTML interpolation, open redirects). Blocks the write and explains the vulnerability.
Principle: Catch dangerous code before it persists, not after.
Pattern 3: Pre-Write Linter Gate
Fires: Before any code is written to disk. Prevents: Syntactically invalid or lint-failing code entering the codebase.
Runs the language-appropriate linter on the proposed file content. If it fails, the write is blocked with the lint errors.
Principle: The write boundary is the last safe point to enforce code quality.
Pattern 4: Convention Allowlist
Fires: Before code is written to frontend files. Prevents: Banned libraries, deprecated API patterns, framework anti-patterns.
Scans for specific imports, function calls, or syntax patterns that violate project conventions.
Principle: Convention drift compounds silently. Denylist enforcement makes violations structural, not advisory.
Pattern 5: Triggered Test Runner
Fires: After any edit to files in high-risk directories (auth, security, safety). Prevents: Security regressions going undetected.
A post-write hook checks whether the modified file is in a designated high-risk path. If so, it automatically runs the relevant test suite.
Principle: High-risk file classes should auto-trigger their test suite.
Pattern 6: Tiered Autonomy Gate
Fires: Before any modification to safety-critical files. Prevents: Autonomous modification of the most consequential code paths.
Files are classified into zones (green/yellow/red) by path. Green: modify freely. Yellow: warning. Red: require human approval.
Principle: Automation trust should be graduated by consequence.
Pattern 7: Duty-Shirking Detector
Fires: Before code is committed. Prevents: Stub implementations (TODO + pass), CI weakening (continue-on-error), error hiding (|| true), test weakening (assert True).
Principle: An agent that cannot complete a task should raise an error, not silently defer.
Pattern 8: Completion Quality Gate
Fires: Before code is marked as complete. Prevents: Code reaching review without passing mutation testing, dead code analysis, clone detection, complexity checks.
Principle: Code correctness is a measurable property; a suite of formal tools approximates it better than any single check.
Pattern 9: Credential Filesystem Deny List
Fires: Before any file read, write, or edit. Enforced by tool runtime, not a hook script. Prevents: Agent reading or modifying .env, .pem, .key, credentials* files.
{
"permissions": {
"deny": [
"Read(.env)", "Read(.env.*)", "Read(**/.env)",
"Write(.env)", "Write(.env.*)", "Write(**/.env)",
"Read(**/*.pem)", "Read(**/*.key)", "Read(**/credentials*)"
]
}
}Principle: Sensitive files should be structurally inaccessible, not merely prohibited by instruction.
Layering Patterns
A single tool modification might pass through:
- Convention allowlist: right library/framework?
- Security interceptor: vulnerability patterns?
- Pre-write linter: syntactically valid?
- Tiered autonomy gate: high-risk zone?
- [write happens]
- Triggered test runner: tests still pass?
Together, these layers make the governance structural rather than instructional.
Related
- Personal Creeds: the values declaration that informs which patterns you choose
- Guardian: runtime constitutional enforcement
- Gateway: enterprise governance with decision tokens