Skip to content

Commit 4bd7e0b

Browse files
feat: v2.2 — Subagent Hooks, DX, Performance & Enterprise (#113)
* feat: v2.2 milestone — Subagent Hooks, DX, Performance & Enterprise Phase 29: Subagent hook patterns documentation for mastering-hooks skill Phase 30: `rulez test` batch command for running YAML test scenarios Phase 31: Performance optimization (cold-start benchmark baseline) Phase 32: BeforeAgent event guide + Issue #107 documentation Phase 33: External logging backends (OTLP, Datadog, Splunk via curl) Phase 34: Config diff view component for rulez-ui Phase 35: Event schema and config schema documentation Phase 36: `rulez lint` rule quality analysis command (9 checks) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove invalid tabSize from DiffEditor options IDiffEditorConstructionOptions does not support tabSize directly. Removes unused editorTabSize import. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9f4c838 commit 4bd7e0b

File tree

17 files changed

+2822
-65
lines changed

17 files changed

+2822
-65
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = ["rulez-ui/src-tauri"]
1616
resolver = "2"
1717

1818
[workspace.package]
19-
version = "2.1.0"
19+
version = "2.2.0"
2020
authors = ["Rick Hightower <rick@spillwave.com>"]
2121
license = "MIT OR Apache-2.0"
2222
edition = "2024"

docs/before-agent-guide.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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

Comments
 (0)