Write policies
Write a policy on the fly
Make a policy while you work: ask your agent to run the policy-init skill, scaffold one with a single chock new, or fill the templates in the browser. A recorded run writes a guard and feeds it an agent's hook event.
A policy can start as one sentence in the middle of a task. There are three ways to turn it into a folder chock enforces. The recorded run below writes a guard against one shell command and shows the hook refusing it.
Three ways
- Ask your agent.
chock initinstalls thepolicy-initskill at.agents/skills/policy-init/. Ask your agent to use it, in your own words: for example, "use the policy-init skill: never let the agent run terraform destroy". This page quotes its procedure below. Its default target is<repo_root>/generated/. Name.agents/policies/<id>/instead, the folderchock synccompiles. Read what it wrote, then runchock check --repo .andchock sync --repo .yourself. - One command.
chock new policy <id> --kind <kind>writes a tested template. Edit it, then eval and sync it. The run below does this for a guard, whose script is the engine's guard template. - In the browser. The policy author asks a few questions, fills the same templates, and writes a setup script you download, read and run yourself. It builds a plugin. The site compiles nothing.
A guard in one sitting, recorded
A real run, recorded by python -m sitegen.writedoc with the engine at the pinned commit. The steps of data/write-policy.yaml ran in order, offline, in one fresh git repository at /work/demo, made with git init -b main and a git user name and email set, with HOME at /home/demo. Those paths stand for the throwaway folders the run used, and <time> stands for a timestamp. Output is stdout and stderr together.
Step 1, exit code 0. Set up chock in the repository. The skills it installs include policy-init.
$ chock init .
Installed pre-commit dispatcher to /work/demo/.git/hooks/pre-commit
No git-pre-commit.sh policies found; pre-commit dispatcher unchanged
Installed pre-merge-commit dispatcher to /work/demo/.git/hooks/pre-merge-commit
No git-pre-commit.sh policies found; pre-merge-commit dispatcher unchanged
Installed pre-push dispatcher to /work/demo/.git/hooks/pre-push
No git-pre-push.sh policies found; pre-push dispatcher unchanged
Installed commit-msg dispatcher to /work/demo/.git/hooks/commit-msg
No git-commit-msg.sh policies found; commit-msg dispatcher unchanged
Registered SessionStart arm hook in .claude/settings.json
INDEX.md: ~257 tokens (chars/4, max 2000)
INDEX.md: ~257 tokens (chars/4, max 2000)
Implementation registered at /work/demo/.git/hooks/pre-commit.d/99-chock-validate
[PASS] All checks passed.
Initialized Chock in /work/demo
Agents: AGENTS.md + claude, copilot, gemini
Skills: eval, optimize, policy-init, validate (refresh with `chock install-skills .`)
Policies: none. This repo enforces nothing yet.
1. copy a policy folder from https://github.com/open-coder-ai/chock-catalog (base/<id>/) into .agents/policies/<id>/
2. chock sync --repo .
Verify anytime with: chock check --only verify
Step 2, exit code 0. Scaffold a guard from the tested guard template: a script that checks a shell command before the agent runs it.
$ chock new policy no-tf-destroy --kind guard
INDEX.md: ~285 tokens (chars/4, max 2000)
Created policy 'my-no-tf-destroy' at /work/demo/.agents
Next: python -m chock sync --repo .
python -m chock check --repo .
Step 3, exit code 0. The three files it wrote: the manifest, the eval suite and the guard's script. In the script, BLOCK and ASK are the patterns of the commands it refuses, or asks about first. Edit both.
$ git status --short --untracked-files=all .agents/policies/my-no-tf-destroy
?? .agents/policies/my-no-tf-destroy/evals/suite.yaml
?? .agents/policies/my-no-tf-destroy/implementations/my-no-tf-destroy.py
?? .agents/policies/my-no-tf-destroy/manifest.yaml
Step 4, exit code 0. Replay its four eval cases against the script.
$ chock eval my-no-tf-destroy
my-no-tf-destroy [deterministic]
PASS tc-001 authored my-no-tf-destroy: this command is refused. Run it yourself after re…
PASS tc-002 authored my-no-tf-destroy: this command is refused. Run it yourself after re…
PASS tc-003 authored my-no-tf-destroy: this command needs a person's yes first.
PASS tc-004 authored guard exit 0
score 1.00
1 policies: 4 pass
Step 5, exit code 0. Compile it and register it with the agents chock wires in this repository. The last lines say how each agent enforces it.
$ chock sync --repo .
Installed pre-commit dispatcher to /work/demo/.git/hooks/pre-commit
No git-pre-commit.sh policies found; pre-commit dispatcher unchanged
Installed pre-merge-commit dispatcher to /work/demo/.git/hooks/pre-merge-commit
No git-pre-commit.sh policies found; pre-merge-commit dispatcher unchanged
Installed pre-push dispatcher to /work/demo/.git/hooks/pre-push
No git-pre-push.sh policies found; pre-push dispatcher unchanged
Installed commit-msg dispatcher to /work/demo/.git/hooks/commit-msg
No git-commit-msg.sh policies found; commit-msg dispatcher unchanged
Registered 1 PreToolUse/Stop hook(s) in .claude/settings.json
claude_code: pre-tool: block+rewrite, best-effort, fail mode open (agentseam basis live-run, recorded 2026-09-07)
claude_code: Untested: chock has not witnessed its hooks run in this client; the wiring follows agentseam's record. What you see there is wanted as evidence: open-coder-ai/agentseam issues labelled 'evidence wanted'.
Registered 1 hook entr(y/ies) in .gemini/settings.json
gemini_cli: pre-tool: block+rewrite, best-effort, fail mode open (agentseam basis vendor-source, recorded 2026-08-28)
gemini_cli: Untested: chock has not witnessed its hooks run in this client; the wiring follows agentseam's record. What you see there is wanted as evidence: open-coder-ai/agentseam issues labelled 'evidence wanted'.
Registered 1 agent hook(s) in .github/hooks/chock.json
vscode_copilot: pre-tool: block+rewrite, best-effort, fail mode open (agentseam basis live-run-partial, recorded 2026-09-28)
INDEX.md: ~285 tokens (chars/4, max 2000)
Recompiled 1 policies
my-no-tf-destroy:
claude: best-effort (live-run)
copilot: best-effort (live-run-partial)
gemini: best-effort (vendor-source)
Step 6, exit code 0. Feed the hook the event Claude Code sends before a Bash tool call running terraform destroy. The command is the one chock sync wrote for the Bash tool in .claude/settings.json, without the git alias around it that first checks the launcher exists. The guard refuses: the hook prints the reason and a deny decision.
$ printf '%s' '{"hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": {"command": "terraform destroy"}}' | sh .chock/bin/launch.sh .chock/bin/claude_code.py --guard .agents/policies/my-no-tf-destroy/implementations/my-no-tf-destroy.py
my-no-tf-destroy: this command is refused. Run it yourself after review.
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Blocked by chock policy: my-no-tf-destroy: my-no-tf-destroy: this command is refused. Run it yourself after review."}}
Step 7, exit code 0. The same event for terraform plan prints nothing, so the call goes ahead.
$ printf '%s' '{"hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": {"command": "terraform plan"}}' | sh .chock/bin/launch.sh .chock/bin/claude_code.py --guard .agents/policies/my-no-tf-destroy/implementations/my-no-tf-destroy.py
Step 8, exit code 0. The decision log counts the refusal.
$ chock gate-log
policy surface events allow block ask warn last block
my-no-tf-destroy pre-tool-use 1 0 1 0 0 <time>
Allowed tool calls: 1 (each counted once, never toward a policy)
From the engine docs: src/chock/packs/_skills/policy-init/SKILL.md
Procedure
- classify(request) using
references/taxonomy.md; present user_facing_class: hook, rule, skill (single-purpose capability), subagent, multi-agent workflow / orchestrator. Map user selection to internal_class: hook → hook, rule → rule, skill → skill, subagent → subagent, multi-agent workflow / orchestrator → workflow skill. announce(internal_class, enforcement, deterministic_parts → script placement, reason, effects). For multi-agent workflow / orchestrator, default the display name toOrchestrator / <Pattern Name>; invoked skills retain regular names. determinism_scan: split deterministic_parts from judgment_parts; route mechanical parts to a code/hybrid skill with a committed script, never bury them in prose inside an NL skill. if stakes ∈ {security, compliance}: enforce ∈ {verify, block}. if any effect ∈ {writes_external, irreversible}: enforce ∈ {verify, block} AND add approval wiring.
- interview(
references/interview.md, target); default target:<repo_root>/generated/; never generate inside the invoking framework's own.agents/orsubagents/folders; skip answered questions.
- if code referenced: mine 3–5 call sites into
examples/; convert prompts perreferences/authoring-techniques.md§D; setsecurity.processes_external_content: truewhen the skill processes external/repo/user content.
- draft evals FIRST: trigger + negative_trigger; add adversarial case for stakes or processes_external_content; add behavior case for non-none effects (enforce ≥ verify + approval).
- generate using
assets/templates/; construct paths with OS separators (never concatenate raw strings). Scaffold the full folder structure perreferences/scaffold-layout.md; placeholder files are required during scaffolding and must be marked with<!-- SCAFFOLD: replace or delete before review -->. Multi-agent workflows also followreferences/multi-agent-scaffold.md; advanced patterns (failure handling, checkpoint/resume, dry-run, rollback) inreferences/orchestration-patterns.md. Agentic skills apply token/context/memory optimization perreferences/agentic-optimization.md.- set status: draft, trust_tier: sandbox; body = activation surface; depth →
references/ - default SKILL.md
## Rulesstarts with a YAGNI rule: confirmed requirements only, delete unused
- set status: draft, trust_tier: sandbox; body = activation surface; depth →
- wire: install hooks for block gates, add ambient lines for rules, optional AGENTS.md fallback section; comment
compiled by chock.
- clean temporaries; verify only deliverable + wiring remain.
- self-check: run
chock check --repo <repo_root>andnpx skills-ref validate <folder>; fix failures.
- hand off: report folder, wiring, smoke test, promotion via PR; suggest
validateafter edits.
Next
- The step-by-step page for a commit-time policy: Your own policy.
- Every field: Manifest reference, Evals reference.
- What a hook can and cannot see: What Chock doesn't stop.
Built from engine 5a4b6287a46e and catalog 1e60d211c1bb.