@askjo/pi-reflect 1.0.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/LICENSE +21 -0
- package/README.md +167 -0
- package/SETUP.md +168 -0
- package/extensions/index.ts +441 -0
- package/extensions/reflect.ts +996 -0
- package/logo-dark.png +0 -0
- package/logo.png +0 -0
- package/package.json +46 -0
- package/tests/apply-edits.test.ts +348 -0
- package/tests/command-source.test.ts +54 -0
- package/tests/config-and-history.test.ts +175 -0
- package/tests/helpers-and-utils.test.ts +174 -0
- package/tests/helpers.ts +84 -0
- package/tests/prompt-building.test.ts +85 -0
- package/tests/realistic-edits.test.ts +227 -0
- package/tests/run-reflection.test.ts +337 -0
- package/tests/session-extraction.test.ts +484 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pradeep Elankumaran
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="logo-dark.png" width="300">
|
|
4
|
+
<img src="logo.png" alt="pi-reflect" width="300">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
# pi-reflect
|
|
9
|
+
|
|
10
|
+
Iterative self-improvement for [pi](https://github.com/badlogic/pi-mono) coding agents.
|
|
11
|
+
|
|
12
|
+
Define a target — how your agent should behave, what it should remember, who it should be — and reflect iterates toward it. Each run reads recent conversations and reference material, compares the agent's actual behavior against the target, and makes surgical edits to close the gap.
|
|
13
|
+
|
|
14
|
+
**define the target → reflect reads evidence → edits the file → the agent gets closer.**
|
|
15
|
+
|
|
16
|
+
Works on any markdown file: behavioral rules (`AGENTS.md`), long-term memory (`MEMORY.md`), personality (`SOUL.md`), or anything else.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pi install git:github.com/jo-inc/pi-reflect
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires pi with an LLM API key configured. Each run makes one LLM call (~$0.05–0.15 with Sonnet).
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
/reflect ./AGENTS.md # run reflection on a file
|
|
30
|
+
/reflect # use saved default target
|
|
31
|
+
/reflect-config # show configured targets
|
|
32
|
+
/reflect-history # show recent runs
|
|
33
|
+
/reflect-stats # correction rate trend + rule recidivism
|
|
34
|
+
/reflect-backfill # bootstrap stats for all historical sessions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
First run asks if you want to save the target. After that, just `/reflect`.
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
|
|
41
|
+
1. Collects evidence: conversation transcripts, daily logs, reference files — from any combination of sources
|
|
42
|
+
2. Sends the evidence + the target file + a prompt describing the desired end state to an LLM
|
|
43
|
+
3. The LLM identifies gaps between actual behavior and the target, proposes surgical edits
|
|
44
|
+
4. Edits are applied with safety checks: backs up the original, skips ambiguous matches, rejects suspiciously large deletions, auto-commits to git if the target is in a repo
|
|
45
|
+
|
|
46
|
+
Every edit is versioned — reflect auto-commits to git after applying changes, so you get a full history of how each file evolved. `git log AGENTS.md` shows every correction the agent absorbed. `git diff HEAD~5 SOUL.md` shows how the personality sharpened over the last 5 runs.
|
|
47
|
+
|
|
48
|
+
Over time, the file converges: corrections get absorbed as rules, memory accumulates durable facts, personality sharpens from generic to specific. The agent stops needing the same corrections.
|
|
49
|
+
|
|
50
|
+
## Data sources
|
|
51
|
+
|
|
52
|
+
Each target has two input channels — `transcripts` (what happened) and `context` (reference material). Both accept an array of sources:
|
|
53
|
+
|
|
54
|
+
| Type | Description | Example |
|
|
55
|
+
|------|-------------|---------|
|
|
56
|
+
| `files` | Glob patterns or file paths, pruned by date and size | Daily logs, notes, other markdown files |
|
|
57
|
+
| `command` | Shell command, stdout captured | API calls, database queries, custom scripts |
|
|
58
|
+
| `url` | HTTP GET, response body captured | REST endpoints, health checks |
|
|
59
|
+
|
|
60
|
+
All sources support `{lookbackDays}` interpolation and per-source `maxBytes` caps. File sources are automatically pruned to only include files within the `lookbackDays` window (matched by date in filename).
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"targets": [{
|
|
65
|
+
"path": "/data/me/MEMORY.md",
|
|
66
|
+
"model": "anthropic/claude-sonnet-4-5",
|
|
67
|
+
"lookbackDays": 1,
|
|
68
|
+
"transcripts": [
|
|
69
|
+
{ "type": "command", "label": "conversations", "command": "curl -s http://localhost:3001/conversation/recent?days={lookbackDays}", "maxBytes": 400000 }
|
|
70
|
+
],
|
|
71
|
+
"context": [
|
|
72
|
+
{ "type": "files", "label": "daily logs", "paths": ["/data/me/daily/*.md"], "maxBytes": 50000 },
|
|
73
|
+
{ "type": "files", "label": "notes", "paths": ["/data/me/notes/*.md"], "maxBytes": 50000 }
|
|
74
|
+
],
|
|
75
|
+
"prompt": "..."
|
|
76
|
+
}]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For the common case of local pi sessions, just use `transcriptSource`:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{ "transcriptSource": { "type": "pi-sessions" } }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Prompts define the target
|
|
87
|
+
|
|
88
|
+
Each target has an optional `prompt` field that tells reflect *what to optimize for*. The same engine drives very different behaviors depending on the prompt:
|
|
89
|
+
|
|
90
|
+
| Target | Prompt goal | What reflect does |
|
|
91
|
+
|--------|------------|-------------------|
|
|
92
|
+
| `AGENTS.md` | Behavioral correctness | Strengthens violated rules, adds rules for recurring patterns |
|
|
93
|
+
| `MEMORY.md` | Factual completeness | Extracts durable facts from conversations, removes stale entries |
|
|
94
|
+
| `SOUL.md` | Identity convergence | Sharpens personality from generic to specific based on interaction patterns |
|
|
95
|
+
|
|
96
|
+
Prompts use `{fileName}`, `{targetContent}`, `{transcripts}`, and `{context}` as placeholders:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"prompt": "You are evolving an AI identity file ({fileName})...\n\n## Current\n{targetContent}\n\n## Conversations\n{transcripts}\n\n## Reference\n{context}"
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If no prompt is set, the default targets behavioral corrections (the original use case).
|
|
105
|
+
|
|
106
|
+
## Impact Metrics
|
|
107
|
+
|
|
108
|
+
`/reflect-stats` tracks whether reflection is working:
|
|
109
|
+
|
|
110
|
+
- **Correction Rate** — `corrections / sessions` per run, plotted over time. Trending down = the agent is converging.
|
|
111
|
+
|
|
112
|
+
- **Rule Recidivism** — which sections get edited repeatedly. A rule strengthened 3+ times isn't sticking. Sections edited once and never again are resolved.
|
|
113
|
+
|
|
114
|
+
`/reflect-backfill` bootstraps stats from historical sessions (dry-run, no file edits).
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
`~/.pi/agent/reflect.json`:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"targets": [{
|
|
123
|
+
"path": "/path/to/AGENTS.md",
|
|
124
|
+
"model": "anthropic/claude-sonnet-4-5",
|
|
125
|
+
"lookbackDays": 1,
|
|
126
|
+
"maxSessionBytes": 614400,
|
|
127
|
+
"backupDir": "~/.pi/agent/reflect-backups",
|
|
128
|
+
"transcriptSource": { "type": "pi-sessions" }
|
|
129
|
+
}]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| Field | Default | Description |
|
|
134
|
+
|-------|---------|-------------|
|
|
135
|
+
| `path` | *(required)* | Target markdown file to iterate on |
|
|
136
|
+
| `model` | *(required)* | LLM to use (e.g. `anthropic/claude-sonnet-4-5`) |
|
|
137
|
+
| `lookbackDays` | `1` | How far back to look for evidence |
|
|
138
|
+
| `maxSessionBytes` | `614400` | Max transcript bytes per run |
|
|
139
|
+
| `transcripts` | — | Array of `ContextSource` for transcript data |
|
|
140
|
+
| `transcriptSource` | `pi-sessions` | Legacy single source (use `transcripts` for multiple) |
|
|
141
|
+
| `context` | — | Array of `ContextSource` for reference material |
|
|
142
|
+
| `prompt` | *(default)* | Custom prompt with `{fileName}`, `{targetContent}`, `{transcripts}`, `{context}` |
|
|
143
|
+
| `backupDir` | `~/.pi/agent/reflect-backups` | Where to store pre-edit backups |
|
|
144
|
+
|
|
145
|
+
## Related
|
|
146
|
+
|
|
147
|
+
- **[pi-mem](https://github.com/jo-inc/pi-mem)** — Memory system for pi agents. Manages MEMORY.md, daily logs, notes, and scratchpad with context injection and keyword search. Pairs naturally with pi-reflect.
|
|
148
|
+
|
|
149
|
+
## Scheduling
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
pi -p --no-session "/reflect /path/to/AGENTS.md"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Works with cron, launchd, or any scheduler. Ask your pi to set it up for you — there's a [setup guide for agents](SETUP.md).
|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
git clone https://github.com/jo-inc/pi-reflect && cd pi-reflect
|
|
161
|
+
npm install && npm test # 137 tests
|
|
162
|
+
pi -e ./extensions/index.ts # test locally without installing
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|
package/SETUP.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# pi-reflect Setup Guide
|
|
2
|
+
|
|
3
|
+
This guide is for you, the coding agent. When a user asks you to "set up reflect", "schedule reflect daily", or "configure pi-reflect", follow these instructions.
|
|
4
|
+
|
|
5
|
+
## Step 1: Install
|
|
6
|
+
|
|
7
|
+
Run this command:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi install git:github.com/jo-inc/pi-reflect
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then reload extensions:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/reload
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Step 2: Find the target file
|
|
20
|
+
|
|
21
|
+
The user wants to reflect on a behavioral markdown file — usually `AGENTS.md`, `CLAUDE.md`, `RULES.md`, or similar. Check the current project root and `~/.pi/agent/` for candidates:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ls AGENTS.md CLAUDE.md RULES.md .cursorrules .github/copilot-instructions.md 2>/dev/null
|
|
25
|
+
ls ~/.pi/agent/AGENTS.md 2>/dev/null
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If nothing exists, ask the user which file they want to improve. If they don't have one yet, suggest creating an `AGENTS.md` in their project root with a few starter rules.
|
|
29
|
+
|
|
30
|
+
## Step 3: Test it
|
|
31
|
+
|
|
32
|
+
Run reflect once to verify it works:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
/reflect /absolute/path/to/AGENTS.md
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It will ask if the user wants to save the target. Say yes. This creates `~/.pi/agent/reflect.json`.
|
|
39
|
+
|
|
40
|
+
## Step 4: Schedule daily runs (optional)
|
|
41
|
+
|
|
42
|
+
If the user wants automatic daily reflection, set up a scheduler. Reflect runs headless via:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pi -p --no-session "/reflect"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This uses the saved target from step 3.
|
|
49
|
+
|
|
50
|
+
### macOS (launchd)
|
|
51
|
+
|
|
52
|
+
Find the pi binary path:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
which pi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Write the plist — replace `/path/to/pi` with the actual path:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cat > ~/Library/LaunchAgents/com.pi.reflect.plist << 'EOF'
|
|
62
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
63
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
64
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
65
|
+
<plist version="1.0">
|
|
66
|
+
<dict>
|
|
67
|
+
<key>Label</key>
|
|
68
|
+
<string>com.pi.reflect</string>
|
|
69
|
+
<key>ProgramArguments</key>
|
|
70
|
+
<array>
|
|
71
|
+
<string>PI_PATH</string>
|
|
72
|
+
<string>-p</string>
|
|
73
|
+
<string>--no-session</string>
|
|
74
|
+
<string>/reflect</string>
|
|
75
|
+
</array>
|
|
76
|
+
<key>StartCalendarInterval</key>
|
|
77
|
+
<dict>
|
|
78
|
+
<key>Hour</key>
|
|
79
|
+
<integer>8</integer>
|
|
80
|
+
<key>Minute</key>
|
|
81
|
+
<integer>0</integer>
|
|
82
|
+
</dict>
|
|
83
|
+
<key>StandardOutPath</key>
|
|
84
|
+
<string>/tmp/pi-reflect.log</string>
|
|
85
|
+
<key>StandardErrorPath</key>
|
|
86
|
+
<string>/tmp/pi-reflect.log</string>
|
|
87
|
+
<key>EnvironmentVariables</key>
|
|
88
|
+
<dict>
|
|
89
|
+
<key>PATH</key>
|
|
90
|
+
<string>/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin</string>
|
|
91
|
+
<key>HOME</key>
|
|
92
|
+
<string>HOME_DIR</string>
|
|
93
|
+
</dict>
|
|
94
|
+
</dict>
|
|
95
|
+
</plist>
|
|
96
|
+
EOF
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Replace `PI_PATH` and `HOME_DIR` with the actual values using sed:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
PI_BINARY=$(which pi)
|
|
103
|
+
sed -i '' "s|PI_PATH|$PI_BINARY|g" ~/Library/LaunchAgents/com.pi.reflect.plist
|
|
104
|
+
sed -i '' "s|HOME_DIR|$HOME|g" ~/Library/LaunchAgents/com.pi.reflect.plist
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Load it:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
launchctl load ~/Library/LaunchAgents/com.pi.reflect.plist
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Linux (cron)
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
PI_BINARY=$(which pi)
|
|
117
|
+
(crontab -l 2>/dev/null; echo "0 8 * * * $PI_BINARY -p --no-session \"/reflect\" >> /tmp/pi-reflect.log 2>&1") | crontab -
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Step 5: Verify scheduling
|
|
121
|
+
|
|
122
|
+
For macOS:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
launchctl list | grep pi.reflect
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
For Linux:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
crontab -l | grep reflect
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Tell the user: reflect is configured. It will run daily at 8am, analyze yesterday's sessions, and update their file. Backups are in `~/.pi/agent/reflect-backups/`. They can check results with `/reflect-history` or `cat /tmp/pi-reflect.log`.
|
|
135
|
+
|
|
136
|
+
## Configuration reference
|
|
137
|
+
|
|
138
|
+
`~/.pi/agent/reflect.json`:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"targets": [{
|
|
143
|
+
"path": "/absolute/path/to/AGENTS.md",
|
|
144
|
+
"model": "anthropic/claude-sonnet-4-5",
|
|
145
|
+
"lookbackDays": 1,
|
|
146
|
+
"maxSessionBytes": 614400,
|
|
147
|
+
"backupDir": "~/.pi/agent/reflect-backups",
|
|
148
|
+
"transcriptSource": { "type": "pi-sessions" }
|
|
149
|
+
}]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- **path**: Absolute path to the target file.
|
|
154
|
+
- **model**: Any `provider/model-id` the user has an API key for in pi. Default: `anthropic/claude-sonnet-4-5`.
|
|
155
|
+
- **lookbackDays**: How many days of sessions to analyze. Default: `1`.
|
|
156
|
+
- **maxSessionBytes**: Context budget for transcripts. Default: `614400` (~600KB).
|
|
157
|
+
- **backupDir**: Where backups go before edits. Default: `~/.pi/agent/reflect-backups`.
|
|
158
|
+
- **transcriptSource**: `{ "type": "pi-sessions" }` reads pi's session JSONL files. `{ "type": "command", "command": "script {lookbackDays}" }` runs a custom command instead.
|
|
159
|
+
|
|
160
|
+
Multiple targets are supported — add more objects to the `targets` array.
|
|
161
|
+
|
|
162
|
+
## Troubleshooting
|
|
163
|
+
|
|
164
|
+
- **"No API key for model"**: The user needs to configure an API key for the model in pi. Run `/model` to check available models.
|
|
165
|
+
- **"No substantive sessions found"**: No sessions with 3+ exchanges found in the lookback period. Try increasing `lookbackDays`.
|
|
166
|
+
- **"Target file too small"**: The file must be at least 100 bytes. It needs some existing rules for reflect to work with.
|
|
167
|
+
- **Edits skipped**: Reflect logs the reason for each skip (ambiguous match, text not found, already exists). This is a safety feature, not a bug.
|
|
168
|
+
- **launchd not running**: Check `launchctl list | grep pi.reflect`. If missing, `launchctl load` the plist. Check `/tmp/pi-reflect.log` for errors. Common issue: PATH doesn't include the directory where `pi` and `node` are installed.
|