pi-shepherd 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +205 -84
- package/README.md +207 -88
- package/index.ts +262 -229
- package/package.json +60 -55
- package/rules.json +196 -33
- package/shepherd/compaction.ts +76 -0
- package/shepherd/conditions.ts +98 -0
- package/shepherd/ephemeral.ts +55 -52
- package/shepherd/git.ts +64 -0
- package/shepherd/index.ts +13 -0
- package/shepherd/line-count.ts +86 -86
- package/shepherd/message-end.ts +120 -0
- package/shepherd/rules-editor.ts +250 -215
- package/shepherd/rules-tool-helpers.ts +119 -120
- package/shepherd/rules-tool-list.ts +124 -126
- package/shepherd/rules-tool.ts +182 -142
- package/shepherd/rules-validate.ts +89 -44
- package/shepherd/rules.ts +366 -295
- package/shepherd/tool-event-types.ts +27 -14
- package/shepherd/tool-hooks.ts +165 -177
- package/shepherd/worktree-check.ts +130 -130
- package/tsconfig.json +21 -14
package/README.en.md
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
[中文文档](README.md) | English
|
|
1
|
+
[中文文档](README.md) | [English](#)
|
|
2
|
+
|
|
3
|
+
> 📖 **[pi-atelier Guide](https://catlain.github.io/pi-atelier/)** — Learn the pi-atelier ecosystem from scratch
|
|
2
4
|
|
|
3
5
|
# pi-shepherd
|
|
4
6
|
|
|
5
|
-
[
|
|
7
|
+
[Repository](https://github.com/catlain/pi-shepherd) | [npm](https://www.npmjs.com/package/pi-shepherd)
|
|
8
|
+
|
|
9
|
+
A **rule-driven behavior guardian** for [pi-coding-agent](https://github.com/earendil-works/pi-coding-agent) — automatically intercepts, notifies, or rewrites operations at key points in the AI workflow: tool calls, AI responses, and session lifecycle events.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
## What Problem Does It Solve
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
AI coding assistants tend to drift during long sessions:
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
- **Tool misuse**: Using grep for symbol searches (should use code-graph), using bash cat to read files (should use read)
|
|
16
|
+
- **Forgot to wrap up**: Not running tests after edits, not committing git, not updating docs
|
|
17
|
+
- **Coding standard violations**: Using spaces in TypeScript (should use tabs), using tabs in Python (should use spaces)
|
|
18
|
+
- **Repeating mistakes**: Same error recurring without checking existing pitfall records
|
|
12
19
|
|
|
13
|
-
- **
|
|
14
|
-
- **Tool result inspection** — Check tool results after execution (e.g., flag overly large outputs)
|
|
15
|
-
- **Agent end hooks** — Enforce commit/message rules when the agent finishes
|
|
16
|
-
- **Session lifecycle** — Reset state between sessions
|
|
20
|
+
pi-shepherd provides a **configurable rules engine** that automatically intervenes at these key points, turning best practices into automated guardrails.
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
19
23
|
|
|
@@ -21,116 +25,233 @@ AI agents can go off the rails — generate too much code, forget to commit, ign
|
|
|
21
25
|
pi install git:github.com/catlain/pi-shepherd
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
##
|
|
28
|
+
## Core Concepts
|
|
29
|
+
|
|
30
|
+
### Hooks
|
|
31
|
+
|
|
32
|
+
Shepherd inserts hooks at 6 key points in the AI workflow:
|
|
33
|
+
|
|
34
|
+
| Hook | When | Typical Use |
|
|
35
|
+
|------|------|-------------|
|
|
36
|
+
| `tool_call` | Before tool execution | Block inappropriate calls, rewrite commands |
|
|
37
|
+
| `tool_result` | After tool execution | Check results, trigger follow-up actions |
|
|
38
|
+
| `agent_end` | When AI voluntarily stops | Remind to commit git, update memory |
|
|
39
|
+
| `message_end` | After each AI response | Detect problematic patterns in responses |
|
|
40
|
+
| `session_shutdown` | When session shuts down | Resource cleanup |
|
|
41
|
+
|
|
42
|
+
### Actions
|
|
43
|
+
|
|
44
|
+
4 actions available when a rule matches:
|
|
25
45
|
|
|
26
|
-
|
|
46
|
+
| Action | Effect |
|
|
47
|
+
|--------|--------|
|
|
48
|
+
| `block` | Prevent tool execution, return reason |
|
|
49
|
+
| `notify` | Show reminder, AI can choose to ignore |
|
|
50
|
+
| `steer` | Inject into next turn, forcing AI to respond |
|
|
51
|
+
| `rewrite` | Rewrite tool parameters then continue |
|
|
27
52
|
|
|
53
|
+
### Condition Matching
|
|
54
|
+
|
|
55
|
+
**Single condition** (simple cases):
|
|
56
|
+
```json
|
|
57
|
+
{ "pattern": "\\bcat\\b", "flags": "" }
|
|
28
58
|
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
59
|
+
|
|
60
|
+
**Multiple conditions** (precise control):
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"conditions": [
|
|
64
|
+
{ "field": "path", "pattern": "\\.ts$" },
|
|
65
|
+
{ "field": "text", "pattern": "\\n [\\S ]" }
|
|
66
|
+
]
|
|
67
|
+
}
|
|
32
68
|
```
|
|
33
69
|
|
|
34
|
-
|
|
70
|
+
Multiple `conditions` are **AND** by default (all must match). Use `conditionLogic: "or"` for OR.
|
|
71
|
+
|
|
72
|
+
**Built-in conditions** (no regex needed):
|
|
35
73
|
|
|
36
|
-
|
|
74
|
+
| builtin | Checks |
|
|
75
|
+
|---------|--------|
|
|
76
|
+
| `git_dirty` | Has uncommitted changes in tracked files |
|
|
77
|
+
| `git_untracked` | Has untracked files |
|
|
78
|
+
| `has_edits` | edit/write was called this turn |
|
|
79
|
+
| `always` | Always matches |
|
|
80
|
+
|
|
81
|
+
### Stateful Rules
|
|
82
|
+
|
|
83
|
+
Track tool call statistics via the `state` field for patterns like "remind after N errors":
|
|
37
84
|
|
|
38
85
|
```json
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
86
|
+
{
|
|
87
|
+
"comment": "Remind to check memory after repeated errors",
|
|
88
|
+
"hook": "tool_result",
|
|
89
|
+
"action": "steer",
|
|
90
|
+
"state": { "countKind": "errors", "gte": 5 },
|
|
91
|
+
"reason": "Tool keeps failing — check memory files for known pitfalls"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Three counting modes:
|
|
96
|
+
- `calls`: Tool invocation count
|
|
97
|
+
- `errors`: Consecutive error count
|
|
98
|
+
- `chars`: Tool result character count
|
|
99
|
+
|
|
100
|
+
Use `resetOn` to reset counters when a specific tool succeeds (e.g., clear error count after tests pass).
|
|
101
|
+
|
|
102
|
+
## Rule Format
|
|
103
|
+
|
|
104
|
+
Complete rule fields:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"comment": "Rule description (required, also serves as unique ID)",
|
|
109
|
+
"hook": "tool_call",
|
|
110
|
+
"tool": "bash",
|
|
111
|
+
"action": "block",
|
|
112
|
+
"reason": "Message shown to AI",
|
|
113
|
+
"pattern": "\\bcat\\b",
|
|
114
|
+
"conditions": [{ "field": "path", "pattern": "\\.ts$" }],
|
|
115
|
+
"conditionLogic": "and",
|
|
116
|
+
"enabled": true,
|
|
117
|
+
"state": { "countKind": "errors", "gte": 3 },
|
|
118
|
+
"resetOn": ["bash"],
|
|
119
|
+
"subagent": false,
|
|
120
|
+
"requiresTools": ["code_graph_semantic_code_search"],
|
|
121
|
+
"requireSuccess": true,
|
|
122
|
+
"stopReason": ["stop"]
|
|
123
|
+
}
|
|
56
124
|
```
|
|
57
125
|
|
|
58
|
-
|
|
126
|
+
**Required fields**: `comment`, `reason`
|
|
59
127
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
128
|
+
**Optional fields**:
|
|
129
|
+
- `enabled`: `false` to disable (default `true`, can be omitted)
|
|
130
|
+
- `subagent`: `false` to skip in subagent sessions
|
|
131
|
+
- `requiresTools`: Only trigger when all listed tools are available
|
|
132
|
+
- `requireSuccess`: `true` to skip `isError` tool_results
|
|
133
|
+
- `stopReason`: For `agent_end` only, limit to specific end reasons
|
|
65
134
|
|
|
66
|
-
##
|
|
135
|
+
## Rule Locations
|
|
67
136
|
|
|
68
|
-
pi
|
|
137
|
+
**Global rules**: `~/.pi/agent/extensions/shepherd/rules.json` (applies to all projects)
|
|
69
138
|
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
- Enforce git commit on agent end
|
|
73
|
-
- Block redundant file reads
|
|
139
|
+
**Project rules**: `{cwd}/.pi/extensions/shepherd-rules.json` (current project only)
|
|
140
|
+
Or `{cwd}/.pi/extensions/shepherd-rules-*.json` (multiple files)
|
|
74
141
|
|
|
75
|
-
|
|
142
|
+
Project and global rules are merged. Project rules can supplement or override global rules.
|
|
143
|
+
|
|
144
|
+
## Managing Rules
|
|
145
|
+
|
|
146
|
+
Use the `shepherd_rules` tool for safe editing (auto-validates, backs up, and verifies):
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
# List all rules
|
|
150
|
+
shepherd_rules(action: "list")
|
|
151
|
+
|
|
152
|
+
# Add a rule
|
|
153
|
+
shepherd_rules(action: "add", rule: { comment: "...", hook: "...", ... })
|
|
154
|
+
|
|
155
|
+
# Update a rule
|
|
156
|
+
shepherd_rules(action: "update", index: 2, changes: { enabled: false })
|
|
157
|
+
|
|
158
|
+
# Delete a rule
|
|
159
|
+
shepherd_rules(action: "delete", index: 3)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Practical Examples
|
|
163
|
+
|
|
164
|
+
### 1. Auto-run tests after editing Python
|
|
76
165
|
|
|
77
166
|
```json
|
|
78
167
|
{
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
168
|
+
"comment": "Run tests after Python edit",
|
|
169
|
+
"hook": "tool_result",
|
|
170
|
+
"tool": "edit",
|
|
171
|
+
"action": "notify",
|
|
172
|
+
"conditions": [{ "field": "path", "pattern": "\\.py$" }],
|
|
173
|
+
"reason": "Python file edited — please run ruff check and unit tests"
|
|
83
174
|
}
|
|
84
175
|
```
|
|
85
176
|
|
|
86
|
-
|
|
177
|
+
### 2. Check git status before session ends
|
|
87
178
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"comment": "Check git before session end",
|
|
182
|
+
"hook": "agent_end",
|
|
183
|
+
"action": "notify",
|
|
184
|
+
"conditions": [
|
|
185
|
+
{ "builtin": "git_dirty" },
|
|
186
|
+
{ "builtin": "git_untracked" }
|
|
187
|
+
],
|
|
188
|
+
"conditionLogic": "or",
|
|
189
|
+
"reason": "Git has uncommitted changes — please confirm if commit + push is needed"
|
|
190
|
+
}
|
|
191
|
+
```
|
|
95
192
|
|
|
96
|
-
|
|
193
|
+
### 3. Redirect grep to code-graph for code search
|
|
97
194
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"comment": "Recommend code-graph over grep",
|
|
198
|
+
"hook": "tool_result",
|
|
199
|
+
"tool": "grep",
|
|
200
|
+
"action": "notify",
|
|
201
|
+
"pattern": ".",
|
|
202
|
+
"reason": "Use code-graph for code search: semantic_code_search (fuzzy), get_ast_node (exact), find_references (refs)",
|
|
203
|
+
"requiresTools": ["code_graph_semantic_code_search"]
|
|
204
|
+
}
|
|
205
|
+
```
|
|
103
206
|
|
|
104
|
-
###
|
|
105
|
-
- Don't use overly broad patterns — they'll match too many calls and slow things down
|
|
106
|
-
- Don't create contradictory rules (block + allow the same pattern)
|
|
107
|
-
- Don't rely on shepherd for security — it's a guide, not a sandbox
|
|
207
|
+
### 4. Block attribution guessing in AI responses
|
|
108
208
|
|
|
109
|
-
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"comment": "Block attribution guessing",
|
|
212
|
+
"hook": "message_end",
|
|
213
|
+
"action": "steer",
|
|
214
|
+
"pattern": "(probably|might be|guess|likely).*(jiti|cache|toolchain)",
|
|
215
|
+
"reason": "Don't guess root causes — check your code logic first, search for best practices, verify before concluding"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 5. Block direct settings.json editing
|
|
110
220
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"comment": "Block direct settings.json editing",
|
|
224
|
+
"hook": "tool_call",
|
|
225
|
+
"tool": "edit|write",
|
|
226
|
+
"action": "block",
|
|
227
|
+
"conditions": [{ "field": "path", "pattern": "settings\\.json$" }],
|
|
228
|
+
"reason": "Directly editing settings.json caused config loss before — use settings_patch tool instead"
|
|
229
|
+
}
|
|
230
|
+
```
|
|
117
231
|
|
|
118
232
|
## Architecture
|
|
119
233
|
|
|
120
234
|
```
|
|
121
235
|
pi-shepherd/
|
|
122
|
-
├── index.ts
|
|
123
|
-
├──
|
|
124
|
-
├── rules
|
|
125
|
-
│ ├──
|
|
126
|
-
│ ├──
|
|
127
|
-
│
|
|
128
|
-
├──
|
|
129
|
-
|
|
236
|
+
├── index.ts # Entry: register all hooks
|
|
237
|
+
├── shepherd/
|
|
238
|
+
│ ├── rules.ts # Rule types + load/compile/match
|
|
239
|
+
│ ├── conditions.ts # Condition types + builtin matching
|
|
240
|
+
│ ├── state-tracker.ts # Stateful rule state tracker
|
|
241
|
+
│ ├── tool-hooks.ts # tool_call / tool_result hook handlers
|
|
242
|
+
│ ├── message-end.ts # message_end hook handler
|
|
243
|
+
│ ├── rules-tool.ts # shepherd_rules tool registration
|
|
244
|
+
│ ├── rules-editor.ts # Safe rule file editing (backup+validate)
|
|
245
|
+
│ ├── rules-validate.ts # Rule format validation
|
|
246
|
+
│ ├── ephemeral.ts # Warning buffer (pushWarning)
|
|
247
|
+
│ ├── git.ts # Git status check utilities
|
|
248
|
+
│ └── worktree-check.ts # Worktree environment detection
|
|
249
|
+
├── rules.json # Default global rules
|
|
250
|
+
└── tests/ # Tests
|
|
130
251
|
```
|
|
131
252
|
|
|
132
253
|
**Dependencies**:
|
|
133
|
-
- `@pi-atelier/shared-utils`
|
|
254
|
+
- `@pi-atelier/shared-utils` — Config API, tool output formatting
|
|
134
255
|
- `@earendil-works/pi-coding-agent` — ExtensionAPI (peer)
|
|
135
256
|
|
|
136
257
|
## License
|