3.2 How pi-shepherd Works: A Rule-Driven Hook System
Shepherd is the “nervous system” of pi-atelier — it doesn’t provide tools or commands directly, but connects all other extensions through event hooks.
Architecture Overview
pi event bus
│
├─ before_provider_request ← Shepherd injects ephemeral hints here
│
├─ tool_call ← Shepherd intercepts/rewrites tool calls
│ │
│ ▼
│ Tool executes
│ │
│ ▼
├─ tool_result ← Shepherd checks results, triggers follow-up actions
│
├─ agent_end ← Shepherd triggers wrap-up actions
│
└─ session_shutdown ← Shepherd cleans up ephemeral state
Core Concepts
Rule
Each rule is a JSON object that defines “when to trigger, under what conditions, and what action to take”:
Rule = Hook timing(hook) + Match conditions(conditions/pattern) + Action(action) + Prompt(reason)
Action Types in Detail
| Action | Injection Method | User Visible | Typical Use Case |
|---|---|---|---|
notify | Injects into AI context | ✅ Yes | Remind AI to run tests, lint |
steer | Silent injection | ❌ No | Guide AI to consult documentation |
rewrite | Modifies tool parameters | ✅ Yes | Auto-prepend prefix to commands |
block | Prevents execution | ✅ Yes | Block dangerous operations |
State Tracking
Shepherd maintains internal state counters for tool calls:
"state": { "countKind": "errors", "gte": 5 }
This means “trigger when cumulative errors ≥ 5 times.” countKind supports:
"errors": Counts when a tool returns an error"calls": Counts when a tool is called
message_end Hook
message_end is a special hook timing: it triggers after the AI finishes its reply, matching the AI’s output text rather than tool parameters. This lets Shepherd “listen” to what the AI says and inject corrections when it spots problems.
AI reply completed
│
▼
┌──────────────────────────────────────┐
│ Shepherd message_end hook │
│ Regex match on AI reply text │
└──────┬───────────────────────────────┘
│
Matched?
├── Yes → steer: silently inject correction (next turn)
└── No → no-op
Difference from tool_call/tool_result:
| Dimension | tool_call / tool_result | message_end |
|---|---|---|
| Match target | Tool parameters (commands, file paths) | AI’s reply text |
conditions[].field | path or text (tool params) | text (AI reply) |
| Typical actions | block/notify/rewrite/steer | Usually steer only |
| Typical use | Block dangerous commands, post-edit reminders | Intercept wrong guesses, guide corrections |
Cross-Extension Communication
Shepherd receives “hints” from other extensions via the pi.events event bus:
Other extension emits hint → pi.events.emit("ephemeral:hint") → Shepherd collects
│
At before_provider_request → Shepherd injects collected hints into AI context
This mechanism allows extensions to collaborate without direct dependencies on each other.
Rule Loading Flow
1. Load rules.json inside the extension package (global default rules)
│
▼
2. Scan project directory for .pi/shepherd-rules-*.json (project rules)
│
▼
3. Rules stack and take effect (project rules override global rules with the same name)
Rule file changes take effect immediately — no action needed.
Editing Rules with shepherd_rules
The shepherd_rules tool provides safe rule editing with built-in validation:
# List all rules (global + project merged)
shepherd_rules(action="list")
# Add a global rule
shepherd_rules(action="add", rule={...})
# Add a project-level rule
shepherd_rules(action="add", scope="project", rule={...})
# Update rule #2 in global rules
shepherd_rules(action="update", index=2, changes={"action": "block"})
# Delete rule #0 in project rules
shepherd_rules(action="delete", scope="project", index=0)
scope parameter:
global(default): Operate on~/.pi/agent/extensions/shepherd/rules.jsonproject: Operate on<cwd>/.pi/extensions/shepherd-rules.jsonlistwithoutscope: Returns merged view from both levels
Safety features:
- Validates required fields and regex patterns before writing
- Reads back after write to verify
- Auto-restore from backup on failure
- Same-signature rules (tool + hook + pattern/check + action) auto-overwrite instead of appending
Configuration
Shepherd supports three-layer config merging (defaults → global settings → project settings). Override in .pi/settings.json as needed.
📖 For complete configuration parameters, see pi-shepherd README.
Next Up
Now that you understand how Shepherd guards AI behavior, the next section covers how Context Manager controls information quality.