Keyboard shortcuts

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

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

ActionInjection MethodUser VisibleTypical Use Case
notifyInjects into AI context✅ YesRemind AI to run tests, lint
steerSilent injection❌ NoGuide AI to consult documentation
rewriteModifies tool parameters✅ YesAuto-prepend prefix to commands
blockPrevents execution✅ YesBlock 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:

Dimensiontool_call / tool_resultmessage_end
Match targetTool parameters (commands, file paths)AI’s reply text
conditions[].fieldpath or text (tool params)text (AI reply)
Typical actionsblock/notify/rewrite/steerUsually steer only
Typical useBlock dangerous commands, post-edit remindersIntercept 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.json
  • project: Operate on <cwd>/.pi/extensions/shepherd-rules.json
  • list without scope: 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.

中文