pi-shepherd 0.1.1 → 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.
Files changed (58) hide show
  1. package/README.en.md +206 -83
  2. package/README.md +209 -88
  3. package/index.ts +262 -229
  4. package/package.json +60 -58
  5. package/rules.json +197 -218
  6. package/shepherd/compaction.ts +76 -0
  7. package/shepherd/conditions.ts +98 -0
  8. package/shepherd/ephemeral.ts +55 -52
  9. package/shepherd/git.ts +64 -0
  10. package/shepherd/index.ts +14 -0
  11. package/shepherd/line-count.ts +86 -86
  12. package/shepherd/message-end.ts +120 -0
  13. package/shepherd/rules-editor.ts +250 -135
  14. package/shepherd/rules-tool-helpers.ts +119 -0
  15. package/shepherd/rules-tool-list.ts +124 -0
  16. package/shepherd/rules-tool.ts +182 -99
  17. package/shepherd/rules-validate.ts +89 -44
  18. package/shepherd/rules.ts +366 -283
  19. package/shepherd/tool-event-types.ts +27 -14
  20. package/shepherd/tool-hooks.ts +165 -176
  21. package/shepherd/worktree-check.ts +130 -130
  22. package/tsconfig.json +21 -14
  23. package/node_modules/@pi-atelier/shared-utils/README.en.md +0 -182
  24. package/node_modules/@pi-atelier/shared-utils/README.md +0 -182
  25. package/node_modules/@pi-atelier/shared-utils/package.json +0 -51
  26. package/node_modules/@pi-atelier/shared-utils/src/__tests__/agents.test.ts +0 -120
  27. package/node_modules/@pi-atelier/shared-utils/src/__tests__/ephemeral.test.ts +0 -100
  28. package/node_modules/@pi-atelier/shared-utils/src/__tests__/file-lock.test.ts +0 -152
  29. package/node_modules/@pi-atelier/shared-utils/src/__tests__/filter-match.test.ts +0 -187
  30. package/node_modules/@pi-atelier/shared-utils/src/__tests__/memory-parser.test.ts +0 -170
  31. package/node_modules/@pi-atelier/shared-utils/src/__tests__/paths.test.ts +0 -126
  32. package/node_modules/@pi-atelier/shared-utils/src/__tests__/project-config-edge.test.ts +0 -138
  33. package/node_modules/@pi-atelier/shared-utils/src/__tests__/project-config.test.ts +0 -257
  34. package/node_modules/@pi-atelier/shared-utils/src/__tests__/project-tools-mcp.test.ts +0 -189
  35. package/node_modules/@pi-atelier/shared-utils/src/__tests__/project-tools.test.ts +0 -204
  36. package/node_modules/@pi-atelier/shared-utils/src/__tests__/settings-backup-advanced.test.ts +0 -269
  37. package/node_modules/@pi-atelier/shared-utils/src/__tests__/settings-backup-array.test.ts +0 -267
  38. package/node_modules/@pi-atelier/shared-utils/src/__tests__/settings-backup.test.ts +0 -520
  39. package/node_modules/@pi-atelier/shared-utils/src/__tests__/settings-read.test.ts +0 -116
  40. package/node_modules/@pi-atelier/shared-utils/src/__tests__/settings-write.test.ts +0 -119
  41. package/node_modules/@pi-atelier/shared-utils/src/__tests__/tool-output.test.ts +0 -145
  42. package/node_modules/@pi-atelier/shared-utils/src/agents.ts +0 -39
  43. package/node_modules/@pi-atelier/shared-utils/src/ephemeral.ts +0 -42
  44. package/node_modules/@pi-atelier/shared-utils/src/file-lock.ts +0 -62
  45. package/node_modules/@pi-atelier/shared-utils/src/filter-match.ts +0 -100
  46. package/node_modules/@pi-atelier/shared-utils/src/index.ts +0 -71
  47. package/node_modules/@pi-atelier/shared-utils/src/memory-parser.ts +0 -96
  48. package/node_modules/@pi-atelier/shared-utils/src/paths.ts +0 -23
  49. package/node_modules/@pi-atelier/shared-utils/src/project-config.ts +0 -241
  50. package/node_modules/@pi-atelier/shared-utils/src/project-tools.ts +0 -191
  51. package/node_modules/@pi-atelier/shared-utils/src/settings-array.ts +0 -73
  52. package/node_modules/@pi-atelier/shared-utils/src/settings-backup-rollback.ts +0 -104
  53. package/node_modules/@pi-atelier/shared-utils/src/settings-backup-utils.ts +0 -75
  54. package/node_modules/@pi-atelier/shared-utils/src/settings-backup.ts +0 -172
  55. package/node_modules/@pi-atelier/shared-utils/src/settings.ts +0 -104
  56. package/node_modules/@pi-atelier/shared-utils/src/tool-output.ts +0 -149
  57. package/node_modules/@pi-atelier/shared-utils/tsconfig.json +0 -9
  58. package/node_modules/@pi-atelier/shared-utils/vitest.config.ts +0 -24
package/README.en.md CHANGED
@@ -1,17 +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
- Line count guard and behavior rules extension for [pi-coding-agent](https://github.com/earendil-works/pi-coding-agent) — rule-driven hooks for tool calls, agent end, and session events.
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
- ## What It Does
11
+ ## What Problem Does It Solve
8
12
 
9
- AI agents can go off the rails — generate too much code, forget to commit, ignore coding standards, or produce outputs that are too large. pi-shepherd acts as a **guardrail system** that monitors and enforces behavioral rules:
13
+ AI coding assistants tend to drift during long sessions:
10
14
 
11
- - **Tool call interception** — Inspect and modify tool calls before execution (e.g., enforce line limits)
12
- - **Tool result inspection** — Check tool results after execution (e.g., flag overly large outputs)
13
- - **Agent end hooks** — Enforce commit/message rules when the agent finishes
14
- - **Session lifecycle** — Reset state between sessions
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
19
+
20
+ pi-shepherd provides a **configurable rules engine** that automatically intervenes at these key points, turning best practices into automated guardrails.
15
21
 
16
22
  ## Installation
17
23
 
@@ -19,116 +25,233 @@ AI agents can go off the rails — generate too much code, forget to commit, ign
19
25
  pi install git:github.com/catlain/pi-shepherd
20
26
  ```
21
27
 
22
- ## How It Works
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
23
43
 
24
- pi-shepherd uses a **rules engine** that evaluates configurable patterns against tool calls and results:
44
+ 4 actions available when a rule matches:
25
45
 
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 |
52
+
53
+ ### Condition Matching
54
+
55
+ **Single condition** (simple cases):
56
+ ```json
57
+ { "pattern": "\\bcat\\b", "flags": "" }
58
+ ```
59
+
60
+ **Multiple conditions** (precise control):
61
+ ```json
62
+ {
63
+ "conditions": [
64
+ { "field": "path", "pattern": "\\.ts$" },
65
+ { "field": "text", "pattern": "\\n [\\S ]" }
66
+ ]
67
+ }
26
68
  ```
27
- Tool Call → Rules Engine → Pass/Block/Modify
28
- Tool Result → Rules Engine → Pass/Flag/Truncate
29
- Agent End → Rules Engine → Enforce (commit, summarize, etc.)
69
+
70
+ Multiple `conditions` are **AND** by default (all must match). Use `conditionLogic: "or"` for OR.
71
+
72
+ **Built-in conditions** (no regex needed):
73
+
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":
84
+
85
+ ```json
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
+ }
30
93
  ```
31
94
 
32
- ### Rules Format
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).
33
101
 
34
- Rules are defined in `rules.json` (or the `shepherd` section of settings):
102
+ ## Rule Format
103
+
104
+ Complete rule fields:
35
105
 
36
106
  ```json
37
- [
38
- {
39
- "name": "block-grep-for-code-graph",
40
- "pattern": "^grep\\s+.*\\b[A-Z][a-zA-Z]+\\(",
41
- "type": "tool_call",
42
- "action": "block",
43
- "message": "Use code-graph search_symbols instead of grep for symbol names"
44
- },
45
- {
46
- "name": "warn-large-edit",
47
- "pattern": "edit",
48
- "type": "tool_result",
49
- "maxLines": 500,
50
- "action": "warn",
51
- "message": "Edit result is large, consider breaking into smaller changes"
52
- }
53
- ]
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
+ }
54
124
  ```
55
125
 
56
- ### Rule Types
126
+ **Required fields**: `comment`, `reason`
57
127
 
58
- | Type | When Evaluated | Actions |
59
- |------|---------------|---------|
60
- | `tool_call` | Before tool execution | `pass`, `block`, `modify` |
61
- | `tool_result` | After tool execution | `pass`, `warn`, `truncate` |
62
- | `agent_end` | When agent finishes | `enforce` |
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
63
134
 
64
- ## Built-in Rules
135
+ ## Rule Locations
65
136
 
66
- pi-shepherd ships with default rules for common anti-patterns:
137
+ **Global rules**: `~/.pi/agent/extensions/shepherd/rules.json` (applies to all projects)
67
138
 
68
- - Redirect `grep` to `code-graph` for symbol searches
69
- - Warn on overly large tool results
70
- - Enforce git commit on agent end
71
- - 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)
72
141
 
73
- ## Configuration
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
74
165
 
75
166
  ```json
76
167
  {
77
- "shepherd": {
78
- "enabled": true,
79
- "rulesDir": "~/.pi/agent/shepherd-rules"
80
- }
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"
81
174
  }
82
175
  ```
83
176
 
84
- ## Use Cases
177
+ ### 2. Check git status before session ends
85
178
 
86
- | Scenario | Rule Type | Action |
87
- |----------|-----------|--------|
88
- | **Enforce coding standards** | `tool_call` | Block tools that don't follow conventions |
89
- | **Prevent context bloat** | `tool_result` | Truncate large results |
90
- | **Git discipline** | `agent_end` | Force commit at session end |
91
- | **Redirect to better tools** | `tool_call` | Block grep, suggest code-graph |
92
- | **Custom team rules** | All types | Project-specific guardrails |
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
+ ```
93
192
 
94
- ## Best Practices
193
+ ### 3. Redirect grep to code-graph for code search
95
194
 
96
- ### ✅ Recommended
97
- - Start with built-in rules, then add project-specific ones
98
- - Use `warn` before `block` — give the agent a chance to learn
99
- - Keep rule patterns simple and specific — regex is evaluated on every tool call
100
- - Put project rules in `.pi/shepherd-rules/` for version control
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
+ ```
101
206
 
102
- ### ❌ Not Recommended
103
- - Don't use overly broad patterns — they'll match too many calls and slow things down
104
- - Don't create contradictory rules (block + allow the same pattern)
105
- - Don't rely on shepherd for security — it's a guide, not a sandbox
207
+ ### 4. Block attribution guessing in AI responses
106
208
 
107
- ## Limitations
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
108
220
 
109
- | Limitation | Detail |
110
- |------------|--------|
111
- | Regex only | Patterns use regex, not semantic understanding |
112
- | No async rules | Rules must evaluate synchronously |
113
- | Agent can bypass | Determined agents can ignore warnings |
114
- | No persistence | Rule state resets between sessions |
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
+ ```
115
231
 
116
232
  ## Architecture
117
233
 
118
234
  ```
119
235
  pi-shepherd/
120
- ├── index.ts # Entry: register hooks + rules engine
121
- ├── rules-engine.ts # Pattern matching + action dispatch
122
- ├── rules/ # Built-in rule definitions
123
- │ ├── grep.ts # Redirect grep → code-graph
124
- │ ├── line-limit.ts # Warn on large outputs
125
- │ └── agent-end.ts # Enforce git commit
126
- ├── types.ts # Rule type definitions
127
- └── package.json
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
128
251
  ```
129
252
 
130
253
  **Dependencies**:
131
- - `@pi-atelier/shared-utils` (bundled) — settings management
254
+ - `@pi-atelier/shared-utils` — Config API, tool output formatting
132
255
  - `@earendil-works/pi-coding-agent` — ExtensionAPI (peer)
133
256
 
134
257
  ## License