samples/
June 20, 2026 · View on GitHub
Drop-in examples for extending agentjail beyond the core policies and 7 library rules. Everything here is optional — copy what you want, edit what you need.
samples/
├── policies/ ← additional .rego rules
│ ├── mcp_filesystem_readonly.rego deny mcp__filesystem__write_file
│ ├── mcp_filesystem_arg_aware.rego inspect read_file's path arg
│ ├── mcp_github_writes_ask.rego ask before PR creates/merges
│ ├── custom_no_npm_global.rego block `npm i -g`
│ └── custom_no_kubectl_prod.rego block kubectl against prod context
└── configs/ ← drop-in policy.yaml fragments
├── policy-strict.yaml lock everything down (recommended for CI/CD)
├── policy-dev-permissive.yaml loosened for daily local dev
├── policy-mcp-heavy.yaml for teams using many MCP servers
└── policy-aws.yaml AWS pack: per-account posture + AWS MCP allowlist
How to load a custom policy
agentjail reads policies from two places:
agentpolicy/policies/(shipped with the binary, baked in viago:embed)~/.agentjail/rules/(user-installed; you put files here)
The daemon loads both directories on startup and on SIGHUP. Anything you
drop in ~/.agentjail/rules/ is merged with the core policies — no rebuild
needed.
Option A — agentjail policy add (recommended)
# Validates + installs in one step; SIGHUPs the daemon automatically.
agentjail policy add samples/policies/mcp_filesystem_readonly.rego
# Verify
agentjail policy list # shows your rule under Custom
agentjail logs # watch denies in real time
# Remove when no longer needed
agentjail policy remove mcp_filesystem_readonly
policy add validates the file before installing it:
package agentjailmust be declared.- Only
candidate contains r if { ... }entries are allowed — NOTdecision = .... - Every
rule_idmust use the prefixcustom/<filename_stem>/<rule>(e.g. a file namedmy_rule.regomust emit ids likecustom/my_rule/no-something). - The full bundle (core + library + your file) must compile in OPA — a file that passes alone but breaks the bundle is rejected with a clear error.
Option B — copy a sample and SIGHUP (manual, no validation)
# Copy whichever sample you want
cp samples/policies/mcp_filesystem_readonly.rego ~/.agentjail/rules/
# Tell the daemon to reload (zero-downtime — in-flight evals complete on the old engine)
kill -HUP $(pgrep -f agentjail-daemon)
# Verify
agentjail policy list # should show your rule
agentjail logs # watch denies in real time
Note: the samples use rule_id prefixes like samples/ — if you use them as
custom rules you should rename the rule_ids to custom/<stem>/... and then
use agentjail policy add for proper validation and lifecycle management.
Option C — write your own from scratch
A minimum-viable .rego file (note the required custom/<stem>/ rule_id prefix):
# ~/.agentjail/rules/my_rule.rego
#
# Required header for agentjail policy add validation:
# @rule_id: custom/my_rule/no-yolo-deploys
package agentjail
import future.keywords.if
import future.keywords.contains
# Use `candidate contains r if { ... }` — the partial rule set pattern.
# The resolver.rego picks the most restrictive candidate (deny > ask > allow).
candidate contains r if {
input.hook_event == "PreToolUse"
input.tool_name == "Bash"
contains(input.tool_input.command, "kubectl apply -f")
r := {
"action": "deny", # or "ask" or "allow"
"rule_id": "custom/my_rule/no-yolo-deploys", # must start with custom/<stem>/
"reason": "deploys after 5pm are banned per the on-call agreement",
"impact": "would deploy outside business hours", # shown in `agentjail logs`
}
# add a real time-of-day check via Rego's time package, or external eval
}
Then agentjail policy add ~/.agentjail/rules/my_rule.rego. The impact
field shows up in agentjail logs automatically — no Go code changes needed.
Option D — enable a built-in library rule via the CLI
For the 7 opt-in hardening rules that ship inside the binary:
agentjail policy list # see what's available
agentjail policy enable no_shell_init_write # turn one on
agentjail policy enable no_history_read
agentjail policy disable no_shell_init_write # turn one off
These are managed by the CLI — you don't copy files by hand.
Bad rules are quarantined, not fatal
If a manually-edited custom rule breaks the bundle after the daemon starts, the daemon will quarantine it (skip with a WARN log) on the next SIGHUP reload. The baseline (core + valid rules) always loads — the daemon never goes open because of a bad custom rule.
Fix the file and send SIGHUP to reload:
kill -HUP $(pgrep -f agentjail-daemon)
How to load a custom config (policy.yaml)
~/.agentjail/policy.yaml is a single YAML file the daemon reads alongside
the .rego rules. Sample files are in samples/configs/ — copy one as your
starting point:
cp samples/configs/policy-strict.yaml ~/.agentjail/policy.yaml
kill -HUP $(pgrep -f agentjail-daemon)
The Rego rules reference data.agentjail.config.* to read this YAML at
eval time — that's how MCP allowlists, network allow-hosts, and per-tool
restrictions plug in without writing more Rego.
policy-aws.yaml — AWS pack
The AWS pack template wires up per-account posture (ADR 0017), an AWS MCP server with a read-only per-tool allowlist, and a network allowlist for typical AWS endpoints. Copy it and enable the destructive-CLI library rule:
cp samples/configs/policy-aws.yaml ~/.agentjail/policy.yaml
agentjail policy enable no_aws_destructive
kill -HUP $(pgrep -f agentjail-daemon)
Then edit the aws.accounts map with your real account ids (find them with
aws sts get-caller-identity --profile <name>). The daemon resolves the
account from aws --profile <name> via ~/.aws/config; accounts not listed
fall back to aws.default_posture (fail-safe prod — delete denied).
Authoring tips
- Always use
candidate contains r if { ... }— notdecision = .... Since the resolver pattern was introduced,resolver.regois the ONLY file that declaresdecision. Your custom rules contribute to thecandidatepartial rule set, and the resolver picks the most restrictive one (deny > ask > allow). Usingdecision = ...in your file will cause aneval_conflict_error. - Always test before shipping. Drop your rule next to a
_test.regofile with at least 3 cases (deny path, allow path, edge case), thenopa test ~/.agentjail/rules/. - Use the
impactfield. It's what the user sees inagentjail logs. Make it a sentence ending in a verb phrase: "would leak AWS credentials", "would force-push to a protected branch". - Prefix your
rule_idwith your org or your username. e.g.myorg/no-yolo-deploys— keeps it from colliding with core rule IDs. - Stay in
package agentjailunless you specifically want your rule isolated — the daemon queriesdata.agentjail.decisionand rules in other packages are ignored. - Add the right imports. Each rule file needs at minimum:
import future.keywords.if import future.keywords.contains
See agentpolicy/README.md for the full rule-authoring reference.