@fyso/awareness-framework 0.2.0 → 0.3.1
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 +4 -0
- package/docs/cli.md +40 -3
- package/docs/evaluation-loop.md +2 -0
- package/docs/lifecycle.md +4 -0
- package/docs/memory.md +20 -0
- package/docs/superpowers/plans/2026-06-19-local-memory-operations.md +1026 -0
- package/package.json +1 -1
- package/src/cli.js +459 -18
- package/src/memory-candidates.js +82 -0
- package/src/text.js +35 -0
- package/templates/agent-instructions.md +15 -6
- package/templates/cli-wrapper.md +1 -1
- package/templates/end-of-day-summary.md +8 -0
- package/templates/evaluation-note.md +4 -1
- package/templates/memory-long-term.md +15 -1
|
@@ -0,0 +1,1026 @@
|
|
|
1
|
+
# Local Memory Operations Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Add a small Cognee-inspired local memory operation model to Awareness: `remember`, `recall`, `forget`, and `improve`.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Keep Markdown files as human-readable projections and add an append-only local event log at `memory/events.jsonl` for auditability. Implement deterministic text recall across memory, worklog, evaluations, and memory events before considering embeddings, graph storage, or additional services.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Node.js ESM, built-in `fs`, `path`, `os`, current CLI parser in `src/cli.js`, Node test runner in `test/cli.test.js`, Markdown docs/templates.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- No graph database.
|
|
14
|
+
- No embeddings or vector store.
|
|
15
|
+
- No external services.
|
|
16
|
+
- No new runtime dependencies.
|
|
17
|
+
- Keep private operational state under `~/.agents`.
|
|
18
|
+
- Keep Markdown as the readable projection.
|
|
19
|
+
- Durable memory promotion remains explicit and evidence-backed.
|
|
20
|
+
- Forget means prune/revise, not destructive deletion.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## File Structure
|
|
25
|
+
|
|
26
|
+
- Modify `src/cli.js`: add top-level command routing, event-log helpers, `remember`, `recall`, `forget`, and `improve` command implementations.
|
|
27
|
+
- Modify `test/cli.test.js`: add focused CLI tests for events, remember, recall, forget, and improve.
|
|
28
|
+
- Modify `docs/cli.md`: document the new commands and event-log behavior.
|
|
29
|
+
- Modify `docs/memory.md`: explain event log plus Markdown projection model.
|
|
30
|
+
- Modify `README.md`: update quick start and private layout to mention `memory/events.jsonl` and memory operations.
|
|
31
|
+
- Modify `templates/agent-instructions.md`: instruct agents when to use remember, recall, forget, and improve.
|
|
32
|
+
- Modify `templates/memory-long-term.md`: describe event-backed projection and prune/revision behavior.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### Task 1: Add Top-Level Memory Operation Routing
|
|
37
|
+
|
|
38
|
+
**Files:**
|
|
39
|
+
- Modify: `src/cli.js`
|
|
40
|
+
- Test: `test/cli.test.js`
|
|
41
|
+
|
|
42
|
+
**Interfaces:**
|
|
43
|
+
- Consumes: existing `runCli(argv, options)`, `parseArgs(argv)`, `printHelp(ctx)`.
|
|
44
|
+
- Produces: top-level commands `remember`, `recall`, `forget`, and `improve`; positional tail support for `recall QUERY`.
|
|
45
|
+
|
|
46
|
+
- [ ] **Step 1: Write failing test for help output**
|
|
47
|
+
|
|
48
|
+
Add this test near the other CLI command tests in `test/cli.test.js`:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
test('help lists local memory operation commands', () => {
|
|
52
|
+
let stdout = '';
|
|
53
|
+
const code = runCli(['help'], {
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
AWARENESS_NOW: '2099-01-02T12:34:00.000Z',
|
|
57
|
+
},
|
|
58
|
+
stdout: { write: (chunk) => { stdout += chunk; } },
|
|
59
|
+
stderr: { write: () => {} },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
assert.equal(code, 0);
|
|
63
|
+
assert.match(stdout, /awareness remember --text TEXT --evidence TEXT/);
|
|
64
|
+
assert.match(stdout, /awareness recall QUERY/);
|
|
65
|
+
assert.match(stdout, /awareness forget --text TEXT --reason TEXT --evidence TEXT/);
|
|
66
|
+
assert.match(stdout, /awareness improve/);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
71
|
+
|
|
72
|
+
Run: `npm test -- --test-name-pattern "help lists local memory operation commands"`
|
|
73
|
+
|
|
74
|
+
Expected: FAIL because help output does not include these commands.
|
|
75
|
+
|
|
76
|
+
- [ ] **Step 3: Update positional parsing and command routing**
|
|
77
|
+
|
|
78
|
+
In `src/cli.js`, change the positional destructuring in `runCli` from:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const [command, subcommand] = parsed.positionals;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
to:
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
const [command, subcommand, ...positionRest] = parsed.positionals;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Add these cases to the command switch after the existing `memory` case:
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
case 'remember':
|
|
94
|
+
return rememberCommand(ctx, parsed.opts);
|
|
95
|
+
case 'recall':
|
|
96
|
+
return recallCommand(ctx, [subcommand, ...positionRest].filter(Boolean).join(' '), parsed.opts);
|
|
97
|
+
case 'forget':
|
|
98
|
+
return forgetCommand(ctx, parsed.opts);
|
|
99
|
+
case 'improve':
|
|
100
|
+
return improveCommand(ctx, parsed.opts);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Add these help lines after the `awareness memory promote ...` line in `printHelp(ctx)`:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
awareness remember --text TEXT --evidence TEXT [--home PATH]
|
|
107
|
+
awareness recall QUERY [--limit N] [--home PATH]
|
|
108
|
+
awareness forget --text TEXT --reason TEXT --evidence TEXT [--home PATH]
|
|
109
|
+
awareness improve [--force] [--min-count N] [--home PATH]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Add temporary command stubs below `memoryPromotionSection(kind)` so routing can compile:
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
function rememberCommand(ctx, opts) {
|
|
116
|
+
throw new Error('remember command is not implemented yet');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function recallCommand(ctx, query, opts) {
|
|
120
|
+
throw new Error('recall command is not implemented yet');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function forgetCommand(ctx, opts) {
|
|
124
|
+
throw new Error('forget command is not implemented yet');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function improveCommand(ctx, opts) {
|
|
128
|
+
throw new Error('improve command is not implemented yet');
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
133
|
+
|
|
134
|
+
Run: `npm test -- --test-name-pattern "help lists local memory operation commands"`
|
|
135
|
+
|
|
136
|
+
Expected: PASS.
|
|
137
|
+
|
|
138
|
+
- [ ] **Step 5: Run full tests**
|
|
139
|
+
|
|
140
|
+
Run: `npm test`
|
|
141
|
+
|
|
142
|
+
Expected: PASS for the existing suite plus the new help test.
|
|
143
|
+
|
|
144
|
+
- [ ] **Step 6: Commit**
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git add src/cli.js test/cli.test.js
|
|
148
|
+
git commit -m "Add memory operation command routing"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### Task 2: Add Append-Only Memory Event Log Helpers
|
|
154
|
+
|
|
155
|
+
**Files:**
|
|
156
|
+
- Modify: `src/cli.js`
|
|
157
|
+
- Test: `test/cli.test.js`
|
|
158
|
+
|
|
159
|
+
**Interfaces:**
|
|
160
|
+
- Consumes: `todayParts(ctx)`, `formatTimestamp(today)`, `ensureDir(dir)`.
|
|
161
|
+
- Produces: `memoryEventPath(home)`, `appendMemoryEvent(home, today, event)`, `readMemoryEvents(home)`.
|
|
162
|
+
|
|
163
|
+
- [ ] **Step 1: Write failing tests for event log writes from existing memory commands**
|
|
164
|
+
|
|
165
|
+
Add this test after `memory note and promote update long-term memory`:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
test('memory note and promote append auditable memory events', () => {
|
|
169
|
+
const home = tempHome();
|
|
170
|
+
run(['init'], home);
|
|
171
|
+
|
|
172
|
+
run([
|
|
173
|
+
'memory',
|
|
174
|
+
'note',
|
|
175
|
+
'--text', 'User wants local recall',
|
|
176
|
+
'--evidence', 'Planning discussion',
|
|
177
|
+
], home);
|
|
178
|
+
run([
|
|
179
|
+
'memory',
|
|
180
|
+
'promote',
|
|
181
|
+
'--kind', 'preference',
|
|
182
|
+
'--text', 'Prefer local-first memory operations',
|
|
183
|
+
'--evidence', 'User approved local event log design',
|
|
184
|
+
], home);
|
|
185
|
+
|
|
186
|
+
const events = fs.readFileSync(path.join(home, 'memory', 'events.jsonl'), 'utf8')
|
|
187
|
+
.trim()
|
|
188
|
+
.split('\n')
|
|
189
|
+
.map((line) => JSON.parse(line));
|
|
190
|
+
|
|
191
|
+
assert.equal(events[0].type, 'memory.candidate.created');
|
|
192
|
+
assert.equal(events[0].text, 'User wants local recall');
|
|
193
|
+
assert.equal(events[0].source, 'memory.note');
|
|
194
|
+
assert.equal(events[1].type, 'memory.promoted');
|
|
195
|
+
assert.equal(events[1].kind, 'preference');
|
|
196
|
+
assert.equal(events[1].text, 'Prefer local-first memory operations');
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
201
|
+
|
|
202
|
+
Run: `npm test -- --test-name-pattern "memory note and promote append auditable memory events"`
|
|
203
|
+
|
|
204
|
+
Expected: FAIL because `memory/events.jsonl` does not exist.
|
|
205
|
+
|
|
206
|
+
- [ ] **Step 3: Add event log helpers**
|
|
207
|
+
|
|
208
|
+
Add these helper functions near `longTermMemoryPath(home)`:
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
function memoryEventPath(home) {
|
|
212
|
+
return path.join(home, 'memory', 'events.jsonl');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function appendMemoryEvent(home, today, event) {
|
|
216
|
+
const file = memoryEventPath(home);
|
|
217
|
+
ensureDir(path.dirname(file));
|
|
218
|
+
fs.appendFileSync(file, `${JSON.stringify({
|
|
219
|
+
timestamp: formatTimestamp(today),
|
|
220
|
+
...event,
|
|
221
|
+
})}\n`);
|
|
222
|
+
return file;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function readMemoryEvents(home) {
|
|
226
|
+
const file = memoryEventPath(home);
|
|
227
|
+
if (!fs.existsSync(file)) return [];
|
|
228
|
+
return fs.readFileSync(file, 'utf8')
|
|
229
|
+
.split('\n')
|
|
230
|
+
.map((line) => line.trim())
|
|
231
|
+
.filter(Boolean)
|
|
232
|
+
.map((line) => JSON.parse(line));
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- [ ] **Step 4: Update candidate and promotion writers to append events**
|
|
237
|
+
|
|
238
|
+
Change `appendMemoryCandidate` signature from:
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
function appendMemoryCandidate(home, today, text, evidence) {
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
to:
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
function appendMemoryCandidate(home, today, text, evidence, source = 'memory.note') {
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
After `fs.writeFileSync(file, content);`, add:
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
appendMemoryEvent(home, today, {
|
|
254
|
+
type: 'memory.candidate.created',
|
|
255
|
+
source,
|
|
256
|
+
text,
|
|
257
|
+
evidence,
|
|
258
|
+
});
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
In `recordEvaluationMemoryCandidates(home, today)`, change:
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
return candidates.filter((candidate) => appendMemoryCandidate(home, today, candidate.text, candidate.evidence));
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
to:
|
|
268
|
+
|
|
269
|
+
```js
|
|
270
|
+
return candidates.filter((candidate) => appendMemoryCandidate(home, today, candidate.text, candidate.evidence, 'evaluation'));
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
In `memoryPromoteCommand`, after `fs.writeFileSync(file, content);`, add:
|
|
274
|
+
|
|
275
|
+
```js
|
|
276
|
+
appendMemoryEvent(home, today, {
|
|
277
|
+
type: 'memory.promoted',
|
|
278
|
+
kind,
|
|
279
|
+
section,
|
|
280
|
+
text,
|
|
281
|
+
evidence,
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- [ ] **Step 5: Run test to verify it passes**
|
|
286
|
+
|
|
287
|
+
Run: `npm test -- --test-name-pattern "memory note and promote append auditable memory events"`
|
|
288
|
+
|
|
289
|
+
Expected: PASS.
|
|
290
|
+
|
|
291
|
+
- [ ] **Step 6: Run full tests**
|
|
292
|
+
|
|
293
|
+
Run: `npm test`
|
|
294
|
+
|
|
295
|
+
Expected: PASS.
|
|
296
|
+
|
|
297
|
+
- [ ] **Step 7: Commit**
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
git add src/cli.js test/cli.test.js
|
|
301
|
+
git commit -m "Record auditable memory events"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### Task 3: Implement `awareness remember`
|
|
307
|
+
|
|
308
|
+
**Files:**
|
|
309
|
+
- Modify: `src/cli.js`
|
|
310
|
+
- Test: `test/cli.test.js`
|
|
311
|
+
|
|
312
|
+
**Interfaces:**
|
|
313
|
+
- Consumes: `appendMemoryCandidate(home, today, text, evidence, source)`, `agentsHome(ctx, opts)`, `ensurePrivateState(home, ctx)`.
|
|
314
|
+
- Produces: top-level `awareness remember --text TEXT --evidence TEXT`.
|
|
315
|
+
|
|
316
|
+
- [ ] **Step 1: Write failing test**
|
|
317
|
+
|
|
318
|
+
Add this test after the event-log test:
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
test('remember records a promotion candidate and event', () => {
|
|
322
|
+
const home = tempHome();
|
|
323
|
+
run(['init'], home);
|
|
324
|
+
|
|
325
|
+
const result = run([
|
|
326
|
+
'remember',
|
|
327
|
+
'--text', 'Prefer recall before repeating implementation work',
|
|
328
|
+
'--evidence', 'User asked for active memory operations',
|
|
329
|
+
], home);
|
|
330
|
+
|
|
331
|
+
assert.equal(result.code, 0);
|
|
332
|
+
assert.match(result.stdout, /Remembered candidate/);
|
|
333
|
+
|
|
334
|
+
const memory = fs.readFileSync(path.join(home, 'memory', 'long-term.md'), 'utf8');
|
|
335
|
+
assert.match(memory, /Prefer recall before repeating implementation work/);
|
|
336
|
+
|
|
337
|
+
const [event] = fs.readFileSync(path.join(home, 'memory', 'events.jsonl'), 'utf8')
|
|
338
|
+
.trim()
|
|
339
|
+
.split('\n')
|
|
340
|
+
.map((line) => JSON.parse(line));
|
|
341
|
+
assert.equal(event.type, 'memory.candidate.created');
|
|
342
|
+
assert.equal(event.source, 'remember');
|
|
343
|
+
});
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
347
|
+
|
|
348
|
+
Run: `npm test -- --test-name-pattern "remember records a promotion candidate and event"`
|
|
349
|
+
|
|
350
|
+
Expected: FAIL with `remember command is not implemented yet`.
|
|
351
|
+
|
|
352
|
+
- [ ] **Step 3: Implement remember command**
|
|
353
|
+
|
|
354
|
+
Replace the `rememberCommand` stub with:
|
|
355
|
+
|
|
356
|
+
```js
|
|
357
|
+
function rememberCommand(ctx, opts) {
|
|
358
|
+
const home = agentsHome(ctx, opts);
|
|
359
|
+
ensurePrivateState(home, ctx);
|
|
360
|
+
const text = required(opts, 'text');
|
|
361
|
+
const evidence = required(opts, 'evidence');
|
|
362
|
+
const today = todayParts(ctx);
|
|
363
|
+
const added = appendMemoryCandidate(home, today, text, evidence, 'remember');
|
|
364
|
+
out(ctx, added ? `Remembered candidate: ${text}` : `Memory candidate already exists: ${text}`);
|
|
365
|
+
return 0;
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
370
|
+
|
|
371
|
+
Run: `npm test -- --test-name-pattern "remember records a promotion candidate and event"`
|
|
372
|
+
|
|
373
|
+
Expected: PASS.
|
|
374
|
+
|
|
375
|
+
- [ ] **Step 5: Run full tests**
|
|
376
|
+
|
|
377
|
+
Run: `npm test`
|
|
378
|
+
|
|
379
|
+
Expected: PASS.
|
|
380
|
+
|
|
381
|
+
- [ ] **Step 6: Commit**
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
git add src/cli.js test/cli.test.js
|
|
385
|
+
git commit -m "Add remember command"
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
### Task 4: Implement Deterministic `awareness recall`
|
|
391
|
+
|
|
392
|
+
**Files:**
|
|
393
|
+
- Modify: `src/cli.js`
|
|
394
|
+
- Test: `test/cli.test.js`
|
|
395
|
+
|
|
396
|
+
**Interfaces:**
|
|
397
|
+
- Consumes: `longTermMemoryPath(home)`, `memoryEventPath(home)`, `path.join(home, 'worklog')`, `path.join(home, 'evaluations')`.
|
|
398
|
+
- Produces: `awareness recall QUERY [--limit N]` with deterministic text matching.
|
|
399
|
+
|
|
400
|
+
- [ ] **Step 1: Write failing recall test**
|
|
401
|
+
|
|
402
|
+
Add this test after the remember test:
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
test('recall searches memory, events, worklogs, and evaluations', () => {
|
|
406
|
+
const home = tempHome();
|
|
407
|
+
run(['init'], home);
|
|
408
|
+
run([
|
|
409
|
+
'remember',
|
|
410
|
+
'--text', 'Always run recall before implementing memory features',
|
|
411
|
+
'--evidence', 'Memory operations plan',
|
|
412
|
+
], home);
|
|
413
|
+
run([
|
|
414
|
+
'log',
|
|
415
|
+
'--task', 'PROJECT-123',
|
|
416
|
+
'--summary', 'Validated recall behavior',
|
|
417
|
+
'--changes', 'Recall should search worklog text.',
|
|
418
|
+
'--evidence', 'test/cli.test.js',
|
|
419
|
+
], home);
|
|
420
|
+
|
|
421
|
+
const result = run(['recall', 'recall behavior'], home);
|
|
422
|
+
|
|
423
|
+
assert.equal(result.code, 0);
|
|
424
|
+
assert.match(result.stdout, /Recall Results/);
|
|
425
|
+
assert.match(result.stdout, /memory\/long-term\.md/);
|
|
426
|
+
assert.match(result.stdout, /worklog\/2099-01-02\.md/);
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
431
|
+
|
|
432
|
+
Run: `npm test -- --test-name-pattern "recall searches memory"`
|
|
433
|
+
|
|
434
|
+
Expected: FAIL with `recall command is not implemented yet`.
|
|
435
|
+
|
|
436
|
+
- [ ] **Step 3: Add recall helpers**
|
|
437
|
+
|
|
438
|
+
Add these helpers near `readMemoryEvents(home)`:
|
|
439
|
+
|
|
440
|
+
```js
|
|
441
|
+
function collectRecallSources(home) {
|
|
442
|
+
return [
|
|
443
|
+
longTermMemoryPath(home),
|
|
444
|
+
memoryEventPath(home),
|
|
445
|
+
...markdownFiles(path.join(home, 'worklog')),
|
|
446
|
+
...markdownFiles(path.join(home, 'evaluations')),
|
|
447
|
+
].filter((file) => fs.existsSync(file));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function markdownFiles(dir) {
|
|
451
|
+
if (!fs.existsSync(dir)) return [];
|
|
452
|
+
return fs.readdirSync(dir)
|
|
453
|
+
.filter((name) => name.endsWith('.md'))
|
|
454
|
+
.sort()
|
|
455
|
+
.map((name) => path.join(dir, name));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function recallMatches(home, query, limit) {
|
|
459
|
+
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
460
|
+
const results = [];
|
|
461
|
+
for (const file of collectRecallSources(home)) {
|
|
462
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
463
|
+
const lines = content.split('\n');
|
|
464
|
+
lines.forEach((line, index) => {
|
|
465
|
+
const haystack = line.toLowerCase();
|
|
466
|
+
const score = terms.filter((term) => haystack.includes(term)).length;
|
|
467
|
+
if (score > 0) {
|
|
468
|
+
results.push({
|
|
469
|
+
file,
|
|
470
|
+
line: index + 1,
|
|
471
|
+
score,
|
|
472
|
+
text: line.trim(),
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
return results
|
|
478
|
+
.sort((left, right) => right.score - left.score || left.file.localeCompare(right.file) || left.line - right.line)
|
|
479
|
+
.slice(0, limit);
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
- [ ] **Step 4: Implement recall command**
|
|
484
|
+
|
|
485
|
+
Replace the `recallCommand` stub with:
|
|
486
|
+
|
|
487
|
+
```js
|
|
488
|
+
function recallCommand(ctx, query, opts) {
|
|
489
|
+
const home = agentsHome(ctx, opts);
|
|
490
|
+
ensurePrivateState(home, ctx);
|
|
491
|
+
const search = opts.query || query;
|
|
492
|
+
if (!search || search === true) {
|
|
493
|
+
throw new Error('Missing recall query. Use: awareness recall QUERY');
|
|
494
|
+
}
|
|
495
|
+
const limit = Number.parseInt(opts.limit || '10', 10);
|
|
496
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
497
|
+
throw new Error('Invalid --limit. Use an integer >= 1.');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const results = recallMatches(home, search, limit);
|
|
501
|
+
out(ctx, `Recall Results (${results.length})`);
|
|
502
|
+
if (!results.length) {
|
|
503
|
+
out(ctx, '- No matches.');
|
|
504
|
+
return 0;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
for (const result of results) {
|
|
508
|
+
out(ctx, `- ${displayPath(home, result.file)}:${result.line}: ${result.text}`);
|
|
509
|
+
}
|
|
510
|
+
return 0;
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
- [ ] **Step 5: Run recall test**
|
|
515
|
+
|
|
516
|
+
Run: `npm test -- --test-name-pattern "recall searches memory"`
|
|
517
|
+
|
|
518
|
+
Expected: PASS.
|
|
519
|
+
|
|
520
|
+
- [ ] **Step 6: Run full tests**
|
|
521
|
+
|
|
522
|
+
Run: `npm test`
|
|
523
|
+
|
|
524
|
+
Expected: PASS.
|
|
525
|
+
|
|
526
|
+
- [ ] **Step 7: Commit**
|
|
527
|
+
|
|
528
|
+
```bash
|
|
529
|
+
git add src/cli.js test/cli.test.js
|
|
530
|
+
git commit -m "Add deterministic recall command"
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
### Task 5: Implement Non-Destructive `awareness forget`
|
|
536
|
+
|
|
537
|
+
**Files:**
|
|
538
|
+
- Modify: `src/cli.js`
|
|
539
|
+
- Test: `test/cli.test.js`
|
|
540
|
+
|
|
541
|
+
**Interfaces:**
|
|
542
|
+
- Consumes: `appendToSection(content, section, addition)`, `replaceMetadata(content, key, value)`, `appendMemoryEvent(home, today, event)`.
|
|
543
|
+
- Produces: `awareness forget --text TEXT --reason TEXT --evidence TEXT`.
|
|
544
|
+
|
|
545
|
+
- [ ] **Step 1: Write failing forget test**
|
|
546
|
+
|
|
547
|
+
Add this test after the recall test:
|
|
548
|
+
|
|
549
|
+
```js
|
|
550
|
+
test('forget records a pruned memory without deleting history', () => {
|
|
551
|
+
const home = tempHome();
|
|
552
|
+
run(['init'], home);
|
|
553
|
+
run([
|
|
554
|
+
'remember',
|
|
555
|
+
'--text', 'Temporary memory to revise',
|
|
556
|
+
'--evidence', 'Initial observation',
|
|
557
|
+
], home);
|
|
558
|
+
|
|
559
|
+
const result = run([
|
|
560
|
+
'forget',
|
|
561
|
+
'--text', 'Temporary memory to revise',
|
|
562
|
+
'--reason', 'Superseded by explicit user correction',
|
|
563
|
+
'--evidence', 'User correction',
|
|
564
|
+
], home);
|
|
565
|
+
|
|
566
|
+
assert.equal(result.code, 0);
|
|
567
|
+
assert.match(result.stdout, /Memory pruned or revised/);
|
|
568
|
+
|
|
569
|
+
const memory = fs.readFileSync(path.join(home, 'memory', 'long-term.md'), 'utf8');
|
|
570
|
+
assert.match(memory, /## Pruned Or Revised/);
|
|
571
|
+
assert.match(memory, /Temporary memory to revise/);
|
|
572
|
+
assert.match(memory, /Superseded by explicit user correction/);
|
|
573
|
+
|
|
574
|
+
const events = fs.readFileSync(path.join(home, 'memory', 'events.jsonl'), 'utf8')
|
|
575
|
+
.trim()
|
|
576
|
+
.split('\n')
|
|
577
|
+
.map((line) => JSON.parse(line));
|
|
578
|
+
assert.equal(events.at(-1).type, 'memory.pruned');
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
583
|
+
|
|
584
|
+
Run: `npm test -- --test-name-pattern "forget records a pruned memory"`
|
|
585
|
+
|
|
586
|
+
Expected: FAIL with `forget command is not implemented yet`.
|
|
587
|
+
|
|
588
|
+
- [ ] **Step 3: Implement forget command**
|
|
589
|
+
|
|
590
|
+
Replace the `forgetCommand` stub with:
|
|
591
|
+
|
|
592
|
+
```js
|
|
593
|
+
function forgetCommand(ctx, opts) {
|
|
594
|
+
const home = agentsHome(ctx, opts);
|
|
595
|
+
ensurePrivateState(home, ctx);
|
|
596
|
+
const text = required(opts, 'text');
|
|
597
|
+
const reason = required(opts, 'reason');
|
|
598
|
+
const evidence = required(opts, 'evidence');
|
|
599
|
+
const today = todayParts(ctx);
|
|
600
|
+
const file = longTermMemoryPath(home);
|
|
601
|
+
let content = fs.readFileSync(file, 'utf8');
|
|
602
|
+
content = replaceMetadata(content, 'Updated', formatTimestamp(today));
|
|
603
|
+
content = appendToSection(content, 'Pruned Or Revised', `- ${today.date}: ${text} (reason: ${reason}; evidence: ${evidence})\n`);
|
|
604
|
+
fs.writeFileSync(file, content);
|
|
605
|
+
appendMemoryEvent(home, today, {
|
|
606
|
+
type: 'memory.pruned',
|
|
607
|
+
text,
|
|
608
|
+
reason,
|
|
609
|
+
evidence,
|
|
610
|
+
});
|
|
611
|
+
out(ctx, `Memory pruned or revised: ${text}`);
|
|
612
|
+
return 0;
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
- [ ] **Step 4: Run forget test**
|
|
617
|
+
|
|
618
|
+
Run: `npm test -- --test-name-pattern "forget records a pruned memory"`
|
|
619
|
+
|
|
620
|
+
Expected: PASS.
|
|
621
|
+
|
|
622
|
+
- [ ] **Step 5: Run full tests**
|
|
623
|
+
|
|
624
|
+
Run: `npm test`
|
|
625
|
+
|
|
626
|
+
Expected: PASS.
|
|
627
|
+
|
|
628
|
+
- [ ] **Step 6: Commit**
|
|
629
|
+
|
|
630
|
+
```bash
|
|
631
|
+
git add src/cli.js test/cli.test.js
|
|
632
|
+
git commit -m "Add non-destructive forget command"
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
### Task 6: Implement `awareness improve`
|
|
638
|
+
|
|
639
|
+
**Files:**
|
|
640
|
+
- Modify: `src/cli.js`
|
|
641
|
+
- Test: `test/cli.test.js`
|
|
642
|
+
|
|
643
|
+
**Interfaces:**
|
|
644
|
+
- Consumes: `buildEvaluation(home, today)`, `writeEvaluationIfMissing(home, today)`, `recordEvaluationMemoryCandidates(home, today)`, `repeatedMemoryCandidateSuggestions(content, minCount)`, `appendMemoryEvent(home, today, event)`.
|
|
645
|
+
- Produces: `awareness improve [--force] [--min-count N]`.
|
|
646
|
+
|
|
647
|
+
- [ ] **Step 1: Write failing improve test**
|
|
648
|
+
|
|
649
|
+
Add this test after the forget test:
|
|
650
|
+
|
|
651
|
+
```js
|
|
652
|
+
test('improve writes evaluation and surfaces repeated pattern suggestions', () => {
|
|
653
|
+
const home = tempHome();
|
|
654
|
+
run(['init'], home);
|
|
655
|
+
run([
|
|
656
|
+
'remember',
|
|
657
|
+
'--text', 'Improve traceability before handoff',
|
|
658
|
+
'--evidence', 'worklog/2099-01-01.md',
|
|
659
|
+
], home, { AWARENESS_NOW: '2099-01-01T12:34:00.000Z' });
|
|
660
|
+
run([
|
|
661
|
+
'remember',
|
|
662
|
+
'--text', 'Improve traceability before handoff',
|
|
663
|
+
'--evidence', 'worklog/2099-01-02.md',
|
|
664
|
+
], home);
|
|
665
|
+
|
|
666
|
+
const result = run(['improve'], home);
|
|
667
|
+
|
|
668
|
+
assert.equal(result.code, 0);
|
|
669
|
+
assert.match(result.stdout, /Evaluation:/);
|
|
670
|
+
assert.match(result.stdout, /Pattern suggestions: 1/);
|
|
671
|
+
assert.match(result.stdout, /Improve traceability before handoff/);
|
|
672
|
+
assert.equal(fs.existsSync(path.join(home, 'evaluations', '2099-01-02.md')), true);
|
|
673
|
+
|
|
674
|
+
const events = fs.readFileSync(path.join(home, 'memory', 'events.jsonl'), 'utf8')
|
|
675
|
+
.trim()
|
|
676
|
+
.split('\n')
|
|
677
|
+
.map((line) => JSON.parse(line));
|
|
678
|
+
assert.equal(events.at(-1).type, 'pattern.suggested');
|
|
679
|
+
});
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
683
|
+
|
|
684
|
+
Run: `npm test -- --test-name-pattern "improve writes evaluation"`
|
|
685
|
+
|
|
686
|
+
Expected: FAIL with `improve command is not implemented yet`.
|
|
687
|
+
|
|
688
|
+
- [ ] **Step 3: Implement improve command**
|
|
689
|
+
|
|
690
|
+
Replace the `improveCommand` stub with:
|
|
691
|
+
|
|
692
|
+
```js
|
|
693
|
+
function improveCommand(ctx, opts) {
|
|
694
|
+
const home = agentsHome(ctx, opts);
|
|
695
|
+
ensurePrivateState(home, ctx);
|
|
696
|
+
const today = todayParts(ctx);
|
|
697
|
+
const evaluationPath = path.join(home, 'evaluations', `${today.date}.md`);
|
|
698
|
+
const force = Boolean(opts.force);
|
|
699
|
+
|
|
700
|
+
let evaluation;
|
|
701
|
+
if (force && fs.existsSync(evaluationPath)) {
|
|
702
|
+
fs.writeFileSync(evaluationPath, buildEvaluation(home, today));
|
|
703
|
+
const candidates = recordEvaluationMemoryCandidates(home, today);
|
|
704
|
+
evaluation = { file: evaluationPath, status: 'rewritten', candidates };
|
|
705
|
+
} else {
|
|
706
|
+
evaluation = writeEvaluationIfMissing(home, today);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
appendMemoryEvent(home, today, {
|
|
710
|
+
type: 'evaluation.created',
|
|
711
|
+
file: evaluation.file,
|
|
712
|
+
status: evaluation.status,
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
const minCount = Number.parseInt(opts.minCount || '2', 10);
|
|
716
|
+
if (!Number.isInteger(minCount) || minCount < 2) {
|
|
717
|
+
throw new Error('Invalid --min-count. Use an integer >= 2.');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const content = fs.readFileSync(longTermMemoryPath(home), 'utf8');
|
|
721
|
+
const suggestions = repeatedMemoryCandidateSuggestions(content, minCount);
|
|
722
|
+
for (const suggestion of suggestions) {
|
|
723
|
+
appendMemoryEvent(home, today, {
|
|
724
|
+
type: 'pattern.suggested',
|
|
725
|
+
text: suggestion.text,
|
|
726
|
+
count: suggestion.count,
|
|
727
|
+
evidence: suggestion.evidence,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
out(ctx, `Evaluation: ${evaluation.status} (${evaluation.file})`);
|
|
732
|
+
out(ctx, `Memory candidates: ${evaluation.candidates ? evaluation.candidates.length : 'not changed'}`);
|
|
733
|
+
out(ctx, `Pattern suggestions: ${suggestions.length}`);
|
|
734
|
+
for (const suggestion of suggestions) {
|
|
735
|
+
out(ctx, `- ${suggestion.text} (${suggestion.count} observations)`);
|
|
736
|
+
out(ctx, ` Promote: awareness memory promote --kind pattern --text "${shellQuoteText(suggestion.text)}" --evidence "${shellQuoteText(suggestion.evidence)}"`);
|
|
737
|
+
}
|
|
738
|
+
return 0;
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
- [ ] **Step 4: Run improve test**
|
|
743
|
+
|
|
744
|
+
Run: `npm test -- --test-name-pattern "improve writes evaluation"`
|
|
745
|
+
|
|
746
|
+
Expected: PASS.
|
|
747
|
+
|
|
748
|
+
- [ ] **Step 5: Run full tests**
|
|
749
|
+
|
|
750
|
+
Run: `npm test`
|
|
751
|
+
|
|
752
|
+
Expected: PASS.
|
|
753
|
+
|
|
754
|
+
- [ ] **Step 6: Commit**
|
|
755
|
+
|
|
756
|
+
```bash
|
|
757
|
+
git add src/cli.js test/cli.test.js
|
|
758
|
+
git commit -m "Add improve command"
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
---
|
|
762
|
+
|
|
763
|
+
### Task 7: Update Docs, README, and Templates
|
|
764
|
+
|
|
765
|
+
**Files:**
|
|
766
|
+
- Modify: `docs/cli.md`
|
|
767
|
+
- Modify: `docs/memory.md`
|
|
768
|
+
- Modify: `README.md`
|
|
769
|
+
- Modify: `templates/agent-instructions.md`
|
|
770
|
+
- Modify: `templates/memory-long-term.md`
|
|
771
|
+
|
|
772
|
+
**Interfaces:**
|
|
773
|
+
- Consumes: command behavior from Tasks 1-6.
|
|
774
|
+
- Produces: user-facing guidance for remember, recall, forget, improve, and events.
|
|
775
|
+
|
|
776
|
+
- [ ] **Step 1: Write docs smoke test**
|
|
777
|
+
|
|
778
|
+
Add this test near existing init/help tests:
|
|
779
|
+
|
|
780
|
+
```js
|
|
781
|
+
test('documentation mentions local memory operations', () => {
|
|
782
|
+
const cliDocs = fs.readFileSync(path.join(repoRootForTests(), 'docs', 'cli.md'), 'utf8');
|
|
783
|
+
const memoryDocs = fs.readFileSync(path.join(repoRootForTests(), 'docs', 'memory.md'), 'utf8');
|
|
784
|
+
const agentTemplate = fs.readFileSync(path.join(repoRootForTests(), 'templates', 'agent-instructions.md'), 'utf8');
|
|
785
|
+
|
|
786
|
+
assert.match(cliDocs, /awareness remember/);
|
|
787
|
+
assert.match(cliDocs, /awareness recall/);
|
|
788
|
+
assert.match(cliDocs, /awareness forget/);
|
|
789
|
+
assert.match(cliDocs, /awareness improve/);
|
|
790
|
+
assert.match(memoryDocs, /memory\/events\.jsonl/);
|
|
791
|
+
assert.match(agentTemplate, /awareness recall/);
|
|
792
|
+
});
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
Add this helper near `tempHome()`:
|
|
796
|
+
|
|
797
|
+
```js
|
|
798
|
+
function repoRootForTests() {
|
|
799
|
+
return path.resolve(new URL('..', import.meta.url).pathname);
|
|
800
|
+
}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
- [ ] **Step 2: Run docs test to verify it fails**
|
|
804
|
+
|
|
805
|
+
Run: `npm test -- --test-name-pattern "documentation mentions local memory operations"`
|
|
806
|
+
|
|
807
|
+
Expected: FAIL because docs do not yet mention all four top-level operations.
|
|
808
|
+
|
|
809
|
+
- [ ] **Step 3: Update `docs/cli.md`**
|
|
810
|
+
|
|
811
|
+
In the `memory` section, add:
|
|
812
|
+
|
|
813
|
+
````markdown
|
|
814
|
+
### Local memory operations
|
|
815
|
+
|
|
816
|
+
These commands provide a small Cognee-inspired operation vocabulary without adding a graph database or vector store.
|
|
817
|
+
|
|
818
|
+
```bash
|
|
819
|
+
awareness remember --text "Prefer recall before repeating implementation work" --evidence "User request"
|
|
820
|
+
awareness recall "implementation work"
|
|
821
|
+
awareness forget --text "Old assumption" --reason "Superseded by user correction" --evidence "Correction message"
|
|
822
|
+
awareness improve
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
`remember` records a promotion candidate and appends `memory.candidate.created` to `memory/events.jsonl`.
|
|
826
|
+
`recall` performs deterministic local text search across memory, memory events, worklogs, and evaluations.
|
|
827
|
+
`forget` records a prune/revision entry and appends `memory.pruned`; it does not destructively delete historical evidence.
|
|
828
|
+
`improve` runs the evaluation/review loop and appends `evaluation.created` and `pattern.suggested` events when applicable.
|
|
829
|
+
````
|
|
830
|
+
|
|
831
|
+
- [ ] **Step 4: Update `docs/memory.md`**
|
|
832
|
+
|
|
833
|
+
Add a section after "Memory Layers":
|
|
834
|
+
|
|
835
|
+
````markdown
|
|
836
|
+
## Local Operation Model
|
|
837
|
+
|
|
838
|
+
Awareness uses a small local operation vocabulary:
|
|
839
|
+
|
|
840
|
+
- `remember`: capture an evidence-backed candidate.
|
|
841
|
+
- `recall`: search local memory, events, worklogs, and evaluations.
|
|
842
|
+
- `forget`: prune or revise stale memory without destructive deletion.
|
|
843
|
+
- `improve`: run evaluation plus memory review to surface repeated candidates.
|
|
844
|
+
|
|
845
|
+
The append-only event log lives at:
|
|
846
|
+
|
|
847
|
+
```text
|
|
848
|
+
~/.agents/memory/events.jsonl
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
Markdown files remain the readable projection. The event log is the auditable history of memory operations.
|
|
852
|
+
````
|
|
853
|
+
|
|
854
|
+
- [ ] **Step 5: Update README private layout and quick start**
|
|
855
|
+
|
|
856
|
+
In the README private layout under `memory/`, add:
|
|
857
|
+
|
|
858
|
+
```text
|
|
859
|
+
events.jsonl
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
In CLI Quick Start, add:
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
awareness remember --text "Useful local observation" --evidence "Source"
|
|
866
|
+
awareness recall "local observation"
|
|
867
|
+
awareness improve
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
- [ ] **Step 6: Update templates**
|
|
871
|
+
|
|
872
|
+
In `templates/agent-instructions.md`, add rules:
|
|
873
|
+
|
|
874
|
+
```markdown
|
|
875
|
+
- Use `awareness remember` for explicit observations that should enter memory review.
|
|
876
|
+
- Use `awareness recall QUERY` before repeating uncertain or previously solved work.
|
|
877
|
+
- Use `awareness forget --text TEXT --reason REASON --evidence EVIDENCE` when memory is stale, wrong, or superseded.
|
|
878
|
+
- Use `awareness improve` after material work or process friction to run evaluation plus memory review.
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
In `templates/memory-long-term.md`, add:
|
|
882
|
+
|
|
883
|
+
```markdown
|
|
884
|
+
## Event Log
|
|
885
|
+
|
|
886
|
+
- Append-only audit history: `memory/events.jsonl`
|
|
887
|
+
- Markdown sections are readable projections.
|
|
888
|
+
- Do not hand-edit event history.
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
- [ ] **Step 7: Run docs test**
|
|
892
|
+
|
|
893
|
+
Run: `npm test -- --test-name-pattern "documentation mentions local memory operations"`
|
|
894
|
+
|
|
895
|
+
Expected: PASS.
|
|
896
|
+
|
|
897
|
+
- [ ] **Step 8: Run full tests**
|
|
898
|
+
|
|
899
|
+
Run: `npm test`
|
|
900
|
+
|
|
901
|
+
Expected: PASS.
|
|
902
|
+
|
|
903
|
+
- [ ] **Step 9: Commit**
|
|
904
|
+
|
|
905
|
+
```bash
|
|
906
|
+
git add README.md docs/cli.md docs/memory.md templates/agent-instructions.md templates/memory-long-term.md test/cli.test.js
|
|
907
|
+
git commit -m "Document local memory operations"
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
---
|
|
911
|
+
|
|
912
|
+
### Task 8: Final Verification and PR
|
|
913
|
+
|
|
914
|
+
**Files:**
|
|
915
|
+
- No code files expected unless verification finds a defect.
|
|
916
|
+
|
|
917
|
+
**Interfaces:**
|
|
918
|
+
- Consumes: all commits from Tasks 1-7.
|
|
919
|
+
- Produces: a reviewable PR for the local memory operation model.
|
|
920
|
+
|
|
921
|
+
- [ ] **Step 1: Run full test suite**
|
|
922
|
+
|
|
923
|
+
Run: `npm test`
|
|
924
|
+
|
|
925
|
+
Expected: PASS, including tests for:
|
|
926
|
+
|
|
927
|
+
```text
|
|
928
|
+
help lists local memory operation commands
|
|
929
|
+
memory note and promote append auditable memory events
|
|
930
|
+
remember records a promotion candidate and event
|
|
931
|
+
recall searches memory, events, worklogs, and evaluations
|
|
932
|
+
forget records a pruned memory without deleting history
|
|
933
|
+
improve writes evaluation and surfaces repeated pattern suggestions
|
|
934
|
+
documentation mentions local memory operations
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
- [ ] **Step 2: Manually smoke-test the commands against a temp home**
|
|
938
|
+
|
|
939
|
+
Run:
|
|
940
|
+
|
|
941
|
+
```bash
|
|
942
|
+
tmp_home="$(mktemp -d)"
|
|
943
|
+
node bin/awareness.js init --home "$tmp_home"
|
|
944
|
+
node bin/awareness.js remember --home "$tmp_home" --text "Smoke memory operation" --evidence "Manual smoke test"
|
|
945
|
+
node bin/awareness.js recall --home "$tmp_home" "Smoke memory"
|
|
946
|
+
node bin/awareness.js improve --home "$tmp_home"
|
|
947
|
+
node bin/awareness.js forget --home "$tmp_home" --text "Smoke memory operation" --reason "Smoke test cleanup" --evidence "Manual smoke test"
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
Expected:
|
|
951
|
+
|
|
952
|
+
```text
|
|
953
|
+
remember prints "Remembered candidate"
|
|
954
|
+
recall prints at least one result from memory/long-term.md or memory/events.jsonl
|
|
955
|
+
improve prints evaluation and pattern suggestion counts
|
|
956
|
+
forget prints "Memory pruned or revised"
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
- [ ] **Step 3: Inspect event log from smoke test**
|
|
960
|
+
|
|
961
|
+
Run:
|
|
962
|
+
|
|
963
|
+
```bash
|
|
964
|
+
tail -n 20 "$tmp_home/memory/events.jsonl"
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
Expected: JSON lines include `memory.candidate.created`, `evaluation.created`, and `memory.pruned`.
|
|
968
|
+
|
|
969
|
+
- [ ] **Step 4: Check worktree**
|
|
970
|
+
|
|
971
|
+
Run: `git status -sb`
|
|
972
|
+
|
|
973
|
+
Expected: clean branch with commits ready to push.
|
|
974
|
+
|
|
975
|
+
- [ ] **Step 5: Open PR**
|
|
976
|
+
|
|
977
|
+
Run:
|
|
978
|
+
|
|
979
|
+
```bash
|
|
980
|
+
git push -u origin codex/local-memory-operations
|
|
981
|
+
gh pr create --draft --base main --head codex/local-memory-operations --title "[codex] Add local memory operations" --body-file /private/tmp/local-memory-operations-pr.md
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
Use this PR body:
|
|
985
|
+
|
|
986
|
+
```markdown
|
|
987
|
+
## Summary
|
|
988
|
+
|
|
989
|
+
Adds a small local-first memory operation model inspired by Cognee without adding graph, vector, or service dependencies.
|
|
990
|
+
|
|
991
|
+
- Adds `remember`, `recall`, `forget`, and `improve`.
|
|
992
|
+
- Adds append-only `memory/events.jsonl` for auditable memory operations.
|
|
993
|
+
- Keeps Markdown files as human-readable projections.
|
|
994
|
+
- Documents how agents should use the new operations.
|
|
995
|
+
|
|
996
|
+
## Validation
|
|
997
|
+
|
|
998
|
+
- `npm test`
|
|
999
|
+
- Manual temp-home smoke test for remember/recall/improve/forget
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
- [ ] **Step 6: Request review before merge**
|
|
1003
|
+
|
|
1004
|
+
After PR creation, report:
|
|
1005
|
+
|
|
1006
|
+
```text
|
|
1007
|
+
PR URL
|
|
1008
|
+
branch name
|
|
1009
|
+
commit list
|
|
1010
|
+
test result
|
|
1011
|
+
manual smoke result
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
Do not merge until the user explicitly approves.
|
|
1015
|
+
|
|
1016
|
+
---
|
|
1017
|
+
|
|
1018
|
+
## Self-Review
|
|
1019
|
+
|
|
1020
|
+
**Spec coverage:** The plan covers the approved design: operation vocabulary, append-only event log, Markdown projections, deterministic recall, non-destructive forget, improve as evaluation plus memory review, docs/templates, tests, and PR flow.
|
|
1021
|
+
|
|
1022
|
+
**Placeholder scan:** The plan contains no `TBD`, `TODO`, or unspecified implementation steps. Each code-changing step includes concrete code snippets and exact file paths.
|
|
1023
|
+
|
|
1024
|
+
**Type consistency:** Function names are consistent across tasks: `appendMemoryEvent`, `readMemoryEvents`, `memoryEventPath`, `rememberCommand`, `recallCommand`, `forgetCommand`, `improveCommand`, `collectRecallSources`, `recallMatches`.
|
|
1025
|
+
|
|
1026
|
+
**Scope check:** The plan avoids graph storage, embeddings, external services, new dependencies, and UI changes.
|