|
| 1 | +# BeforeAgent Event Guide: Subagent Governance with RuleZ |
| 2 | + |
| 3 | +How to use BeforeAgent, AfterAgent, and PreToolUse events to govern subagent behavior across AI coding platforms. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Event Scoping: PreToolUse vs BeforeAgent |
| 8 | + |
| 9 | +Understanding when each event fires is critical to writing effective subagent policies. |
| 10 | + |
| 11 | +### PreToolUse |
| 12 | + |
| 13 | +`PreToolUse` fires **before each individual tool call** (Bash, Write, Read, Edit, Glob, Grep, etc.) -- whether in the main conversation or inside a subagent. This is the most common event for policy enforcement because it covers every tool invocation regardless of where it originates. |
| 14 | + |
| 15 | +- Fires once per tool call |
| 16 | +- Fires in both parent conversations and subagents |
| 17 | +- Receives the tool name and tool input as context |
| 18 | +- Can block, allow, or inject context per-call |
| 19 | + |
| 20 | +### BeforeAgent |
| 21 | + |
| 22 | +`BeforeAgent` fires **once** when a subagent is about to be spawned, before the Agent tool runs. It fires in the **parent context**, not the child. Use this to: |
| 23 | + |
| 24 | +- **Inject policy context** that the subagent will see when it starts |
| 25 | +- **Block certain agent tasks entirely** before any tools execute |
| 26 | +- **Audit which agent tasks are being started** by logging the spawn event |
| 27 | + |
| 28 | +Key distinction: `BeforeAgent` does not fire again for individual tool calls within the subagent. Once the subagent starts, tool-level governance is handled by `PreToolUse` and `PostToolUse`. |
| 29 | + |
| 30 | +### AfterAgent |
| 31 | + |
| 32 | +`AfterAgent` fires **once** when a subagent completes (or is terminated). Use this for: |
| 33 | + |
| 34 | +- Post-completion audit logging |
| 35 | +- Summarizing what the subagent did |
| 36 | +- Triggering follow-up actions |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## When to Use Each Event |
| 41 | + |
| 42 | +| Use Case | Event | Why | |
| 43 | +|----------|-------|-----| |
| 44 | +| Block dangerous commands | `PreToolUse` | Fires for every tool, catches commands in subagents too | |
| 45 | +| Inject coding standards | `PreToolUse` | Context needed per-tool-call | |
| 46 | +| Restrict which agents can run | `BeforeAgent` | Only fires when an agent spawns | |
| 47 | +| Audit agent activity | `AfterAgent` | Fires after agent completes | |
| 48 | +| Block agents from certain tasks | `BeforeAgent` | Pre-empt before tools run | |
| 49 | +| Restrict file writes to certain paths | `PreToolUse` | Evaluates each Write/Edit individually | |
| 50 | +| Inject one-time context for a task | `BeforeAgent` | Fires once at spawn, avoids repeated injection | |
| 51 | +| Log tool-level detail inside agents | `PreToolUse` + `PostToolUse` | Captures every operation | |
| 52 | + |
| 53 | +--- |
| 54 | + |
| 55 | +## Examples |
| 56 | + |
| 57 | +### Example 1: Block Subagents from Modifying Production Files |
| 58 | + |
| 59 | +Use `BeforeAgent` to prevent subagents from starting if their task description mentions production deployments, and use `PreToolUse` as a safety net to block writes to production paths. |
| 60 | + |
| 61 | +```yaml |
| 62 | +hooks: |
| 63 | + # Gate at agent spawn -- block tasks that target production |
| 64 | + - name: block-production-agents |
| 65 | + matchers: |
| 66 | + operations: [BeforeAgent] |
| 67 | + conditions: |
| 68 | + - field: tool_input.task |
| 69 | + pattern: "(?i)(deploy|production|prod environment)" |
| 70 | + actions: |
| 71 | + block: "Subagent tasks targeting production are not permitted. Use the deployment pipeline instead." |
| 72 | + |
| 73 | + # Safety net -- block writes to production paths from any context |
| 74 | + - name: block-production-writes |
| 75 | + matchers: |
| 76 | + operations: [PreToolUse] |
| 77 | + tools: [Write, Edit, Bash] |
| 78 | + conditions: |
| 79 | + - field: tool_input.file_path |
| 80 | + pattern: "^/opt/production/|^/srv/prod/" |
| 81 | + actions: |
| 82 | + block: "Direct modifications to production paths are not allowed." |
| 83 | +``` |
| 84 | +
|
| 85 | +**What happens**: If a subagent is spawned with a task like "deploy the new version to production", the `BeforeAgent` hook blocks it before any tools run. If a subagent with a different task description somehow tries to write to a production path, the `PreToolUse` hook catches it. |
| 86 | + |
| 87 | +### Example 2: Inject Subagent-Specific Context |
| 88 | + |
| 89 | +Use `BeforeAgent` with an inject action to give a subagent specialized policy context when it starts. |
| 90 | + |
| 91 | +```yaml |
| 92 | +hooks: |
| 93 | + # Inject security review context when a review agent spawns |
| 94 | + - name: security-review-context |
| 95 | + matchers: |
| 96 | + operations: [BeforeAgent] |
| 97 | + conditions: |
| 98 | + - field: tool_input.task |
| 99 | + pattern: "(?i)(security|vulnerability|audit|CVE)" |
| 100 | + actions: |
| 101 | + inject: | |
| 102 | + ## Security Review Policy |
| 103 | +
|
| 104 | + When performing security reviews: |
| 105 | + - Check all user inputs for injection vulnerabilities (SQL, XSS, command injection) |
| 106 | + - Verify authentication and authorization on every endpoint |
| 107 | + - Flag any hardcoded credentials, API keys, or secrets |
| 108 | + - Ensure cryptographic operations use current best practices |
| 109 | + - Report findings in SARIF format when possible |
| 110 | + - Do NOT modify code -- this is a read-only review |
| 111 | +
|
| 112 | + # Enforce read-only for security review subagents |
| 113 | + - name: security-review-readonly |
| 114 | + matchers: |
| 115 | + operations: [PreToolUse] |
| 116 | + tools: [Write, Edit] |
| 117 | + conditions: |
| 118 | + - field: agent_context |
| 119 | + pattern: "(?i)security review" |
| 120 | + actions: |
| 121 | + block: "Security review agents operate in read-only mode." |
| 122 | +``` |
| 123 | + |
| 124 | +**What happens**: When a subagent is spawned with a security-related task, `BeforeAgent` injects the security review policy as context. The `PreToolUse` hook then enforces read-only access for the duration of the subagent. |
| 125 | + |
| 126 | +### Example 3: Audit All Agent Spawns |
| 127 | + |
| 128 | +Use `AfterAgent` with a script to log every subagent lifecycle event for compliance auditing. |
| 129 | + |
| 130 | +```yaml |
| 131 | +hooks: |
| 132 | + # Log when any subagent starts |
| 133 | + - name: audit-agent-start |
| 134 | + matchers: |
| 135 | + operations: [BeforeAgent] |
| 136 | + actions: |
| 137 | + run: | |
| 138 | + #!/bin/bash |
| 139 | + TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) |
| 140 | + TASK=$(echo "$HOOK_INPUT" | jq -r '.tool_input.task // "unknown"') |
| 141 | + echo "{\"event\":\"agent_start\",\"task\":\"$TASK\",\"timestamp\":\"$TIMESTAMP\"}" \ |
| 142 | + >> ~/.claude/logs/agent-audit.jsonl |
| 143 | + echo '{"continue": true}' |
| 144 | +
|
| 145 | + # Log when any subagent completes |
| 146 | + - name: audit-agent-end |
| 147 | + matchers: |
| 148 | + operations: [AfterAgent] |
| 149 | + actions: |
| 150 | + run: | |
| 151 | + #!/bin/bash |
| 152 | + TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) |
| 153 | + TASK=$(echo "$HOOK_INPUT" | jq -r '.tool_input.task // "unknown"') |
| 154 | + TOOL_COUNT=$(echo "$HOOK_INPUT" | jq -r '.extra.tool_count // 0') |
| 155 | + echo "{\"event\":\"agent_end\",\"task\":\"$TASK\",\"tools_used\":$TOOL_COUNT,\"timestamp\":\"$TIMESTAMP\"}" \ |
| 156 | + >> ~/.claude/logs/agent-audit.jsonl |
| 157 | + echo '{"continue": true}' |
| 158 | +``` |
| 159 | + |
| 160 | +**What happens**: Every subagent spawn and completion is recorded to `~/.claude/logs/agent-audit.jsonl` with timestamps and task descriptions. This creates a compliance-ready audit trail of all agent activity. |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## Platform Support |
| 165 | + |
| 166 | +Not all platforms support agent lifecycle events. Choose your hook strategy based on the platforms you target. |
| 167 | + |
| 168 | +| Platform | BeforeAgent | AfterAgent | Notes | |
| 169 | +|----------|-------------|------------|-------| |
| 170 | +| **Claude Code** | Yes | Yes | Native support via `SubagentStart`/`SubagentStop` aliases | |
| 171 | +| **Gemini CLI** | Yes (dual-fire) | Yes | `BeforeAgent` also fires `UserPromptSubmit` -- see [dual-fire events](../mastering-hooks/references/platform-adapters.md) | |
| 172 | +| **GitHub Copilot** | No | No | Use `PreToolUse` for tool-level governance instead | |
| 173 | +| **OpenCode** | No | No | Use `PreToolUse` for tool-level governance instead | |
| 174 | +| **Codex CLI** | No hooks | No hooks | No hook support at all | |
| 175 | + |
| 176 | +### Cross-Platform Strategy |
| 177 | + |
| 178 | +If you need subagent governance across platforms: |
| 179 | + |
| 180 | +1. **Always include `PreToolUse` rules** -- these work on every platform that supports hooks and catch tool calls inside subagents. |
| 181 | +2. **Add `BeforeAgent`/`AfterAgent` rules as enhancements** -- these provide cleaner agent-level control on Claude Code and Gemini CLI. |
| 182 | +3. **Use `rulez debug`** to verify behavior on each platform before deploying. |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +## Resolving Issue #107: Hooks Not Firing in Subagents |
| 187 | + |
| 188 | +If your hooks work in the main conversation but not in subagents, the most common causes are: |
| 189 | + |
| 190 | +1. **Wrong event type**: Use `PreToolUse` to catch tool calls inside subagents. `BeforeAgent` only fires once when the agent starts -- it does not fire for individual tool calls within the subagent. |
| 191 | +2. **Scope mismatch**: Project-local hooks may not apply if the subagent changes working directory. Use `rulez install --global` for universal coverage. |
| 192 | +3. **Missing registration**: The subagent runs a fresh process -- ensure RuleZ is registered in global settings, not just project settings. |
| 193 | +4. **Platform limitation**: `BeforeAgent`/`AfterAgent` are only available on Claude Code and Gemini CLI. On other platforms, rely on `PreToolUse` exclusively. |
| 194 | + |
| 195 | +### Diagnostic Steps |
| 196 | + |
| 197 | +```bash |
| 198 | +# Verify RuleZ is registered globally |
| 199 | +cat ~/.claude/settings.json | grep -A10 hooks |
| 200 | +
|
| 201 | +# Test that your rule matches the expected event |
| 202 | +rulez debug PreToolUse --tool Write --path src/main.rs -v |
| 203 | +
|
| 204 | +# Check BeforeAgent event specifically |
| 205 | +rulez debug BeforeAgent -v |
| 206 | +
|
| 207 | +# Review audit logs for hook activity |
| 208 | +rulez logs --event BeforeAgent --last 10 |
| 209 | +``` |
| 210 | + |
| 211 | +### See Also |
| 212 | + |
| 213 | +- [Agent Inline Hooks Reference](../mastering-hooks/references/agent-inline-hooks.md) -- ephemeral hooks scoped to individual subagents |
| 214 | +- [Troubleshooting Guide](../mastering-hooks/references/troubleshooting-guide.md) -- general hook debugging procedures |
| 215 | +- [Platform Adapters Reference](../mastering-hooks/references/platform-adapters.md) -- cross-platform event mapping details |
0 commit comments