pi-brain 0.1.4 → 0.1.6
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.md +3 -1
- package/package.json +1 -1
- package/skills/brain/SKILL.md +22 -0
- package/skills/brain/templates/agents-md.md +12 -0
- package/src/index.ts +25 -29
- package/src/memory-commit.ts +9 -2
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
Versioned memory for the [pi coding agent](https://github.com/badlogic/pi-mono). Agents commit decisions and reasoning to a `.memory/` directory, preserving context across sessions, compactions, and model switches.
|
|
8
8
|
|
|
9
|
+
Credit: This project is my implementation for Pi of this paper [Git Context Controller: Manage the Context of LLM-based Agents like Git](https://arxiv.org/html/2508.00031v1)
|
|
10
|
+
|
|
9
11
|
## Getting Started
|
|
10
12
|
|
|
11
13
|
```bash
|
|
@@ -14,7 +16,7 @@ pi install npm:pi-brain
|
|
|
14
16
|
|
|
15
17
|
Open pi in any project and say "initialize Brain" (or run `/skill:brain`). The agent creates `.memory/` and starts remembering.
|
|
16
18
|
|
|
17
|
-
That's it. The agent decides when to commit, branch, and merge — you don't need to manage anything.
|
|
19
|
+
That's it. The agent decides when to commit, branch, and merge — you don't **need** to manage anything. However, you can always prompt the agent to remember something specific if you'd like.
|
|
18
20
|
|
|
19
21
|
## How It Works
|
|
20
22
|
|
package/package.json
CHANGED
package/skills/brain/SKILL.md
CHANGED
|
@@ -76,6 +76,28 @@ For deep retrieval, use `read` directly:
|
|
|
76
76
|
A subagent handles commit distillation — it reads your `log.md` and prior commits,
|
|
77
77
|
then produces the structured commit entry. You just provide a good `summary` string.
|
|
78
78
|
|
|
79
|
+
## After Every Commit
|
|
80
|
+
|
|
81
|
+
**Re-read `.memory/main.md` and rewrite stale sections.** The roadmap is the first
|
|
82
|
+
thing a new session reads — if it's stale, every future session starts with a wrong
|
|
83
|
+
picture. This means genuine review, not mechanical edits.
|
|
84
|
+
|
|
85
|
+
After `memory_commit` returns:
|
|
86
|
+
|
|
87
|
+
1. Read `.memory/main.md` in full.
|
|
88
|
+
2. Rewrite the **Current State** section to describe what is true _right now_ — remove
|
|
89
|
+
historical context that has migrated to Key Decisions or Milestones.
|
|
90
|
+
3. Add any new entries to **Key Decisions Made**.
|
|
91
|
+
4. Move completed items in **Milestones** and add new planned ones.
|
|
92
|
+
5. Remove or rewrite anything a new reader would find misleading.
|
|
93
|
+
|
|
94
|
+
The goal is curation, not accumulation. A reader of Current State should understand
|
|
95
|
+
the project as it exists today without wading through history.
|
|
96
|
+
|
|
97
|
+
For trivial commits that don't change the project's state, decisions, or milestones
|
|
98
|
+
(e.g., minor refactors, typo fixes), you can pass `update_roadmap: false` to skip
|
|
99
|
+
the reminder. Most commits should update the roadmap.
|
|
100
|
+
|
|
79
101
|
## When to Branch
|
|
80
102
|
|
|
81
103
|
- You want to explore an alternative approach without contaminating current thinking
|
|
@@ -40,6 +40,17 @@ Each commit in `commits.md` has three blocks:
|
|
|
40
40
|
|
|
41
41
|
The latest commit always contains a self-contained summary of the full branch history.
|
|
42
42
|
|
|
43
|
+
## When to Commit
|
|
44
|
+
|
|
45
|
+
Call `memory_commit` when one of these is true:
|
|
46
|
+
|
|
47
|
+
- You reached a stable decision or understanding worth preserving.
|
|
48
|
+
- You finished an exploration branch with a clear conclusion.
|
|
49
|
+
- You are about to change direction significantly.
|
|
50
|
+
- You completed meaningful progress and are about to end the session.
|
|
51
|
+
- The extension warns that `log.md` is getting large.
|
|
52
|
+
- You are about to claim the task is complete or hand off to another agent.
|
|
53
|
+
|
|
43
54
|
## Conventions
|
|
44
55
|
|
|
45
56
|
- **Agent-driven**: You decide when to commit, branch, and merge
|
|
@@ -47,3 +58,4 @@ The latest commit always contains a self-contained summary of the full branch hi
|
|
|
47
58
|
- **Rolling summaries**: Each commit re-synthesizes all prior progress
|
|
48
59
|
- **No direct log.md writes**: The extension maintains log.md automatically
|
|
49
60
|
- **Status is automatic**: Memory status is injected at session start and appended to tool results (compact/truncated when large; use `read .memory/main.md` for full roadmap)
|
|
61
|
+
- **Keep main.md current**: After every commit, re-read `.memory/main.md` in full and rewrite stale sections. Current State should describe what is true _right now_ — remove historical context that belongs in Key Decisions or Milestones. The goal is curation, not accumulation. For trivial commits that don't change project state, pass `update_roadmap: false` to skip the reminder.
|
package/src/index.ts
CHANGED
|
@@ -101,7 +101,7 @@ function resolveSkillPath(): string {
|
|
|
101
101
|
export default function activate(pi: ExtensionAPI) {
|
|
102
102
|
let state: MemoryState | null = null;
|
|
103
103
|
let branchManager: BranchManager | null = null;
|
|
104
|
-
let
|
|
104
|
+
let frozenStatusSnapshot: string | null = null;
|
|
105
105
|
|
|
106
106
|
function tryLoad(ctx: ExtensionContext): boolean {
|
|
107
107
|
if (isMemoryReady(state, branchManager)) {
|
|
@@ -127,12 +127,10 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
127
127
|
description:
|
|
128
128
|
"Manage memory branches. Actions: create (new branch), switch (change active branch), merge (synthesize branch into current).",
|
|
129
129
|
parameters: Type.Object({
|
|
130
|
-
action: Type.
|
|
131
|
-
[
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
),
|
|
130
|
+
action: Type.String({
|
|
131
|
+
enum: ["create", "switch", "merge"],
|
|
132
|
+
description: 'Action to perform: "create", "switch", or "merge"',
|
|
133
|
+
}),
|
|
136
134
|
name: Type.Optional(
|
|
137
135
|
Type.String({ description: "Branch name (required for create)" })
|
|
138
136
|
),
|
|
@@ -180,7 +178,12 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
180
178
|
description: "Checkpoint a milestone in agent memory.",
|
|
181
179
|
parameters: Type.Object({
|
|
182
180
|
summary: Type.String({ description: "Short summary of this checkpoint" }),
|
|
183
|
-
update_roadmap: Type.Optional(
|
|
181
|
+
update_roadmap: Type.Optional(
|
|
182
|
+
Type.Boolean({
|
|
183
|
+
description:
|
|
184
|
+
"Update .memory/main.md after commit. Defaults to true — set false to skip for trivial commits.",
|
|
185
|
+
})
|
|
186
|
+
),
|
|
184
187
|
}),
|
|
185
188
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
186
189
|
if (
|
|
@@ -214,7 +217,8 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
214
217
|
commitContent,
|
|
215
218
|
state,
|
|
216
219
|
branchManager,
|
|
217
|
-
ctx.cwd
|
|
220
|
+
ctx.cwd,
|
|
221
|
+
params.update_roadmap
|
|
218
222
|
);
|
|
219
223
|
|
|
220
224
|
setBrainFooterStatus(ctx, state, branchManager);
|
|
@@ -226,7 +230,7 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
226
230
|
state = new MemoryState(ctx.cwd);
|
|
227
231
|
state.load();
|
|
228
232
|
branchManager = new BranchManager(ctx.cwd);
|
|
229
|
-
|
|
233
|
+
frozenStatusSnapshot = null;
|
|
230
234
|
|
|
231
235
|
if (!state.isInitialized) {
|
|
232
236
|
setBrainFooterStatus(ctx, state, branchManager);
|
|
@@ -249,7 +253,7 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
249
253
|
});
|
|
250
254
|
|
|
251
255
|
pi.on("session_switch", (_event, ctx) => {
|
|
252
|
-
|
|
256
|
+
frozenStatusSnapshot = null;
|
|
253
257
|
|
|
254
258
|
state = new MemoryState(ctx.cwd);
|
|
255
259
|
state.load();
|
|
@@ -262,11 +266,7 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
262
266
|
setBrainFooterStatus(ctx, state, branchManager);
|
|
263
267
|
});
|
|
264
268
|
|
|
265
|
-
pi.on("before_agent_start", (
|
|
266
|
-
if (statusInjected) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
269
|
+
pi.on("before_agent_start", (event: BeforeAgentStartEvent, ctx) => {
|
|
270
270
|
if (
|
|
271
271
|
!tryLoad(ctx) ||
|
|
272
272
|
!isMemoryReady(state, branchManager) ||
|
|
@@ -275,25 +275,21 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
if (frozenStatusSnapshot === null) {
|
|
279
|
+
frozenStatusSnapshot = buildStatusView(state, branchManager, ctx.cwd, {
|
|
280
|
+
compact: true,
|
|
281
|
+
roadmapCharLimit: BEFORE_AGENT_START_ROADMAP_CHAR_LIMIT,
|
|
282
|
+
branchLimit: BEFORE_AGENT_START_BRANCH_LIMIT,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
279
285
|
|
|
280
|
-
const status = buildStatusView(state, branchManager, ctx.cwd, {
|
|
281
|
-
compact: true,
|
|
282
|
-
roadmapCharLimit: BEFORE_AGENT_START_ROADMAP_CHAR_LIMIT,
|
|
283
|
-
branchLimit: BEFORE_AGENT_START_BRANCH_LIMIT,
|
|
284
|
-
});
|
|
285
286
|
return {
|
|
286
|
-
|
|
287
|
-
customType: "brain-status",
|
|
288
|
-
content: status,
|
|
289
|
-
display: true,
|
|
290
|
-
details: {},
|
|
291
|
-
},
|
|
287
|
+
systemPrompt: `${event.systemPrompt}\n\n${frozenStatusSnapshot}`,
|
|
292
288
|
};
|
|
293
289
|
});
|
|
294
290
|
|
|
295
291
|
pi.on("session_compact", () => {
|
|
296
|
-
|
|
292
|
+
frozenStatusSnapshot = null;
|
|
297
293
|
});
|
|
298
294
|
|
|
299
295
|
pi.on("resources_discover", () => ({
|
package/src/memory-commit.ts
CHANGED
|
@@ -34,7 +34,8 @@ export function finalizeMemoryCommit(
|
|
|
34
34
|
commitContent: string,
|
|
35
35
|
state: MemoryState,
|
|
36
36
|
branches: BranchManager,
|
|
37
|
-
projectDir: string
|
|
37
|
+
projectDir: string,
|
|
38
|
+
updateRoadmap?: boolean
|
|
38
39
|
): string {
|
|
39
40
|
const branch = state.activeBranch;
|
|
40
41
|
const hash = generateHash();
|
|
@@ -60,5 +61,11 @@ export function finalizeMemoryCommit(
|
|
|
60
61
|
const status = buildStatusView(state, branches, projectDir, {
|
|
61
62
|
compact: true,
|
|
62
63
|
});
|
|
63
|
-
|
|
64
|
+
|
|
65
|
+
const roadmapReminder =
|
|
66
|
+
updateRoadmap === false
|
|
67
|
+
? ""
|
|
68
|
+
: "\n\n**Action required:** Re-read `.memory/main.md` in full and rewrite stale sections. Current State should describe what is true right now — curate, don't just append.";
|
|
69
|
+
|
|
70
|
+
return `${resultText}\n\n${status}${roadmapReminder}`;
|
|
64
71
|
}
|