Good
"Hard reset discards uncommitted changes in the working tree and index. Safer: git stash first, or git reset --soft to keep changes staged."
Says what happens, then offers a safer alternative the agent can suggest.
Press ← or → to navigate between chapters
Press S or / to search in the book
Press ? to show this help
Press Esc to hide this help
Every reason string in rules/*.toml is sent as permissionDecisionReason. The agent receives it, and Codex also displays deny reasons to the operator as hook feedback. Treat each one as a client-neutral help-menu entry, not a security disclaimer. The reasons are the docs.
Format
<verb-phrase of what the command does>. <risk / scope / reversibility note if non-obvious>.
First sentence: what the command does, in plain language. Second sentence: only if there's a non-obvious risk, scope, or reversibility point worth teaching. Procedural mutations like "Installing packages" stay one terse sentence.
Recovery
When a corrective path differs by client, keep the shared reason to the cause and attach semantic recovery actions to HookOutput. recovery.rs renders those actions only at serialization, using FILE_TOOL_SPECS as the capability source. That is where a confirmed source file becomes Claude Read, Gemini read_file, Antigravity view_file, or a conditional Codex shell example. Static TOML reasons and modern-CLI hints still use neutral prose because they are shared directly.
Examples
"Hard reset discards uncommitted changes in the working tree and index. Safer: git stash first, or git reset --soft to keep changes staged."
Says what happens, then offers a safer alternative the agent can suggest.
"Drops a stash permanently. Run git stash list first to confirm the index; cannot be undone."
Reversibility note plus a concrete pre-check command.
"git stash drop"
Tells the agent nothing it didn't already know from the command name.
"Port scanning. Only scan networks you own or have written authorization to test."
The reason teaches the agent about the operation; it doesn't gate access. Leave authorization to the operator.
Rules
| Rule | Why |
|---|---|
| Max 250 chars | Enforced by build.rs (MAX_REASON_CHARS). Build fails on overflow. Trim before adding. |
| No em-dashes | Periods separate clauses; ASCII-only quotes. Em-dashes are a style smell in agent-facing prose. |
| No authorization hedges | Don't write "verify you have permission" or "only do this on resources you own". The reason teaches; it doesn't gate. |
| Generic placeholders only | Use <file>, <path>, <host>, <user>, <region>, <resource>, <key>, <pid>. Never embed real hostnames, IPs, usernames, paths, or service names. Tests and reasons are public. |
| Client-neutral recovery | Keep shared reasons and hints free of client-only tool names. When wording depends on capabilities, attach a semantic RecoveryAction and let each serializer route or fold it through that client's supported channel. |
| Terse for procedural mutations | One sentence for routine ones like "Installing packages" or "Formatting files". Add a second sentence only when there's a non-obvious risk worth teaching. |
The style applies to source-level prompts too. Strings in src/router.rs, src/pipe_caps.rs, src/recovery.rs, src/security_reminders.rs, and src/hints.rs follow the same rules. If you add a hard-deny pattern, recovery action, or modern-CLI hint, write its prompt in this voice.