@yemi33/minions 0.1.2401 → 0.1.2403
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/dashboard/js/refresh.js +38 -8
- package/dashboard.js +272 -130
- package/docs/README.md +1 -1
- package/docs/named-agents.md +16 -9
- package/docs/team-memory.md +455 -137
- package/engine/queries.js +67 -68
- package/engine/tools-inventory.js +104 -0
- package/package.json +1 -1
package/docs/team-memory.md
CHANGED
|
@@ -1,164 +1,482 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
Minions
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### 1. `pinned.md` — human-flagged critical context
|
|
51
|
-
|
|
52
|
-
`pinned.md` lives at the Minions root (`MINIONS_DIR/pinned.md`). It holds notes the human teammate has explicitly pinned through the dashboard — short, high-signal rules and warnings that **must** be visible to every agent on every dispatch.
|
|
53
|
-
|
|
54
|
-
The engine injects the file verbatim into the prompt under a "Pinned Context (CRITICAL — READ FIRST)" heading and caps it at 4 KB to protect the prompt budget.
|
|
55
|
-
|
|
56
|
-
Typical contents include credential constraints (e.g., shared `gh` auth means PR self-approval is blocked), workflow policies (e.g., merging policy, TDD requirement), and active setup state. If pinned context contradicts a playbook instruction, pinned context wins for the duration of the dispatch.
|
|
57
|
-
|
|
58
|
-
### 2. `knowledge/` — categorized KB entries (sweep-write-only)
|
|
59
|
-
|
|
60
|
-
`knowledge/` is the long-form team knowledge base. Files are grouped by category:
|
|
61
|
-
|
|
62
|
-
- `knowledge/architecture/` — design decisions, system overviews
|
|
63
|
-
- `knowledge/conventions/` — coding patterns, repo norms, standards
|
|
64
|
-
- `knowledge/project-notes/` — per-project context and observations
|
|
65
|
-
- `knowledge/build-reports/` — CI/build investigation results
|
|
66
|
-
- `knowledge/reviews/` — PR review findings and rationale
|
|
67
|
-
- `knowledge/agents/<agentId>.md` — per-agent personal memory (curated by the sweep)
|
|
68
|
-
|
|
69
|
-
Filenames follow the `YYYY-MM-DD-<agent>-<slug>.md` convention so chronological sorting just works.
|
|
70
|
-
|
|
71
|
-
Agents read `knowledge/` directly with grep/glob/view. They **do not** write to it. See [Sweep-write-only constraint](#sweep-write-only-constraint) below.
|
|
72
|
-
|
|
73
|
-
**Full-body copies vs. condensed stubs.** When `engine/consolidation.js#classifyToKnowledgeBase` promotes an inbox note into `knowledge/`, it only copies the full body when the note is routed to `conventions/` or its content carries a reusable-knowledge section header (`## Patterns`, `## Conventions`, `## Gotchas`, `## Dependencies`, `## Best Practices`, etc.). Narrowly-scoped, one-off notes (a single PR review, a task status update) instead get a deterministic, LLM-free condensed stub — title + first-paragraph abstract + a link back to the archived inbox note — to avoid duplicating disk usage and prompt-token cost on every future dispatch. Every promoted entry's frontmatter gains a `reusable: true|false` field so this can be audited (issue #604).
|
|
74
|
-
|
|
75
|
-
### 3. `notes.md` — consolidated team notes
|
|
76
|
-
|
|
77
|
-
`notes.md` is the rolling team notebook. The consolidation sweep periodically merges high-signal findings from the inbox into dated `### YYYY-MM-DD` sections at the top of `notes.md`, with links back to the underlying KB entries.
|
|
78
|
-
|
|
79
|
-
In legacy and shadow modes, the engine injects `notes.md` under a "Team Notes (MUST READ)" heading. When active retrieval returns evidence, the bounded `Relevant Memory` pack replaces this broad appendix. When the file exceeds `ENGINE_DEFAULTS.maxNotesPromptBytes`, the legacy path keeps the most recent 10 sections, truncates the body, and appends a footer noting how many older sections live on disk.
|
|
80
|
-
|
|
81
|
-
### 4. `notes/inbox/` — fresh agent findings
|
|
82
|
-
|
|
83
|
-
`notes/inbox/` holds the freshest, un-consolidated learnings. Every agent writes exactly one inbox file at the end of a successful task to a path the playbook supplies (`notes/inbox/<agent>-<work-item-id>-<date>-<time>.md`). The file always begins with a YAML frontmatter block (`id`, `agent`, `date`) so the consolidation sweep can track it.
|
|
84
|
-
|
|
85
|
-
Inbox notes are the canonical place to record:
|
|
86
|
-
|
|
87
|
-
- New patterns or conventions discovered while implementing.
|
|
88
|
-
- Gotchas, warnings, or repro recipes for future agents.
|
|
89
|
-
- File-and-line citations supporting any claims.
|
|
90
|
-
|
|
91
|
-
The consolidation sweep is what eventually promotes inbox notes into `knowledge/` and `notes.md`. Until then, agents should grep the inbox themselves for very recent findings on adjacent work.
|
|
92
|
-
|
|
93
|
-
#### Failure-path exception
|
|
94
|
-
|
|
95
|
-
Inbox writes are **success artifacts only**. If a task fails, is blocked, is cancelled, or ends partial, the agent must **not** create an inbox note. When `memoryEpisodicCapture` is enabled, lifecycle records a compact structured outcome for successful, partial, and failed dispatches; it never stores transcripts or chain-of-thought and skips nonce-mismatched or injection-flagged reports.
|
|
1
|
+
# Minions Memory System
|
|
2
|
+
|
|
3
|
+
Minions long-term memory is a hybrid system:
|
|
4
|
+
|
|
5
|
+
- Markdown files preserve operator-readable context, the inbox workflow, and the
|
|
6
|
+
legacy prompt path.
|
|
7
|
+
- SQLite records provide scoped lifecycle state, FTS5 search, deterministic
|
|
8
|
+
task-aware retrieval, and retrieval telemetry.
|
|
9
|
+
|
|
10
|
+
Neither layer replaces the other. Active retrieval reads structured records from
|
|
11
|
+
SQLite; pinned context and the legacy fallback still read Markdown directly.
|
|
12
|
+
This document covers knowledge memory, not the engine/dashboard process-memory
|
|
13
|
+
diagnostics described in [diagnostics-memory.md](diagnostics-memory.md).
|
|
14
|
+
|
|
15
|
+
## End-to-end data flow
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Human Quick Note / agent finding / engine note
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
notes/inbox/*.md
|
|
22
|
+
|
|
|
23
|
+
engine tick: consolidateInbox() (threshold-gated)
|
|
24
|
+
|
|
|
25
|
+
+------------+-------------+----------------+
|
|
26
|
+
| | |
|
|
27
|
+
v v v
|
|
28
|
+
notes.md knowledge/<category>/ knowledge/agents/
|
|
29
|
+
team digest readable KB entry <agent>.md
|
|
30
|
+
| | |
|
|
31
|
+
+--------------------------+----------------+
|
|
32
|
+
|
|
|
33
|
+
v
|
|
34
|
+
memory_records + FTS5
|
|
35
|
+
(semantic SQL records)
|
|
36
|
+
|
|
37
|
+
Human pinned note ------------------------------> pinned.md
|
|
38
|
+
Human direct KB authoring ---------> knowledge/ + memory_records
|
|
39
|
+
Dispatch completion (opt-in) -------------------> memory_records
|
|
40
|
+
(episodic record)
|
|
41
|
+
|
|
42
|
+
At the next dispatch:
|
|
43
|
+
|
|
44
|
+
pinned.md
|
|
45
|
+
+
|
|
46
|
+
active retrieval: task query -> scoped FTS5 -> rerank -> bounded Relevant Memory
|
|
47
|
+
OR
|
|
48
|
+
legacy fallback: bounded notes.md + bounded knowledge/agents/<agent>.md
|
|
49
|
+
```
|
|
96
50
|
|
|
97
|
-
|
|
51
|
+
The playbook also tells agents to inspect `knowledge/` and `notes/inbox/` on
|
|
52
|
+
disk. Those directories are not injected wholesale into every prompt.
|
|
53
|
+
|
|
54
|
+
## Storage and authority
|
|
55
|
+
|
|
56
|
+
There is no single store that is authoritative for every kind of memory.
|
|
57
|
+
Authority is divided by responsibility:
|
|
58
|
+
|
|
59
|
+
| Store | Authoritative for | Notes |
|
|
60
|
+
|-------|-------------------|-------|
|
|
61
|
+
| `engine/state.db` tables `memory_records` and `memory_retrieval_runs` | Structured record bodies and metadata used by active retrieval; record lifecycle (`active`, `superseded`, `retracted`, `expired`); retrieval telemetry | `memory_records_fts` is a derived external-content FTS5 index maintained by SQLite triggers. |
|
|
62
|
+
| `pinned.md` | Operator-authored pinned context | Read directly for every rendered agent prompt. It is not a structured-memory pin. |
|
|
63
|
+
| `notes/inbox/*.md` | Pending human, agent, and engine-authored findings awaiting consolidation | Successful agent tasks write one note to the assigned path; failures do not. |
|
|
64
|
+
| `notes.md` | Operator-readable team digest and legacy team-notes prompt input | Consolidation appends here under a file lock. |
|
|
65
|
+
| `knowledge/<category>/*.md` | Curated, browsable knowledge-base content | Written by engine-managed consolidation/sweep paths and explicit human dashboard actions. Agents must not edit it directly. |
|
|
66
|
+
| `knowledge/agents/<agentId>.md` | Legacy per-agent notebook | Written only by the consolidation pipeline; never by the agent itself. |
|
|
67
|
+
| `notes/archive/` and `knowledge/_swept/` | Recovery copies and retired source artifacts | Retention differs by subsystem; see [kb-sweep.md](kb-sweep.md). |
|
|
68
|
+
| `config.json` | Feature and engine settings | Intentionally file-backed configuration, not memory content. |
|
|
69
|
+
|
|
70
|
+
SQLite is the sole authority for runtime state generally; see
|
|
71
|
+
[design-state-storage.md](design-state-storage.md). The Markdown paths above
|
|
72
|
+
remain intentionally file-backed documents and coordination artifacts.
|
|
73
|
+
|
|
74
|
+
### Synchronization is directional, not a two-way mirror
|
|
75
|
+
|
|
76
|
+
The normal ingestion paths often write both layers, but they are not one
|
|
77
|
+
cross-store transaction:
|
|
78
|
+
|
|
79
|
+
- Migration 017 performed a one-time backfill from existing knowledge files,
|
|
80
|
+
team-note sections, and per-agent sections into SQL.
|
|
81
|
+
- Inbox consolidation writes knowledge and per-agent files and then upserts
|
|
82
|
+
corresponding semantic records.
|
|
83
|
+
- `POST /api/knowledge` writes both the knowledge file and a human-trusted SQL
|
|
84
|
+
record.
|
|
85
|
+
- Episodic capture writes SQL only.
|
|
86
|
+
- Pinned context writes `pinned.md` only.
|
|
87
|
+
|
|
88
|
+
Direct filesystem edits, `POST /api/notes-save`, manual inbox **Persist** or
|
|
89
|
+
**Promote to KB**, and KB sweep rewrites/moves do not perform a general SQL
|
|
90
|
+
reindex. File pruning also does not expire an already-created structured
|
|
91
|
+
record. Consequently, Markdown and SQL can diverge; active retrieval follows
|
|
92
|
+
SQL, while the legacy path follows the files. There is currently no full
|
|
93
|
+
reindex API or CLI command. The SQL layer also has no scheduled record expiry;
|
|
94
|
+
the `expired` status exists, but the KB sweep's file TTL does not apply it.
|
|
95
|
+
|
|
96
|
+
## Inputs
|
|
97
|
+
|
|
98
|
+
### Human inputs
|
|
99
|
+
|
|
100
|
+
Humans can add memory through the dashboard or its localhost API:
|
|
101
|
+
|
|
102
|
+
- **Quick Notes** calls `POST /api/notes`, creating a Markdown file in
|
|
103
|
+
`notes/inbox/` for normal consolidation.
|
|
104
|
+
- **Pinned Notes** calls `POST /api/pinned` (plus `/remove` and `/update`) and
|
|
105
|
+
edits `pinned.md`.
|
|
106
|
+
- **New Knowledge Base Entry** calls `POST /api/knowledge`, writing a category
|
|
107
|
+
file and a global, human-trusted semantic record.
|
|
108
|
+
- Inbox actions can persist an item into `notes.md` or promote it directly to a
|
|
109
|
+
knowledge category.
|
|
110
|
+
- Feedback actions and several engine/operator workflows also create inbox
|
|
111
|
+
notes, so not every inbox file originates from the Quick Notes form.
|
|
112
|
+
|
|
113
|
+
### Agent inputs
|
|
114
|
+
|
|
115
|
+
An agent records durable findings in exactly one assigned
|
|
116
|
+
`notes/inbox/<agent>-<work-item>-<timestamp>.md` file after a successful task.
|
|
117
|
+
The required YAML `agent:` field is the preferred author identity; the filename
|
|
118
|
+
prefix is a fallback. An optional `project:` frontmatter value makes the
|
|
119
|
+
knowledge SQL record project-scoped.
|
|
120
|
+
|
|
121
|
+
Agents read but never delete, move, or overwrite `knowledge/`, including their
|
|
122
|
+
own `knowledge/agents/<agentId>.md`. Corrections go through a new inbox note so
|
|
123
|
+
the pipeline can preserve provenance and reconcile the old material.
|
|
124
|
+
|
|
125
|
+
### Completion outcomes
|
|
126
|
+
|
|
127
|
+
When `engine.memoryEpisodicCapture` is enabled, post-completion lifecycle writes
|
|
128
|
+
a compact SQL episode for successful, partial, and failed dispatches. This path
|
|
129
|
+
is independent of the agent's success-only inbox note.
|
|
130
|
+
|
|
131
|
+
## Inbox consolidation
|
|
132
|
+
|
|
133
|
+
`engine.js` calls `consolidateInbox(config)` on every tick. Consolidation starts
|
|
134
|
+
when the number of eligible Markdown files reaches
|
|
135
|
+
`engine.inboxConsolidateThreshold` (default `5`). It excludes inbox items pinned
|
|
136
|
+
against consolidation and files already in the in-flight set.
|
|
137
|
+
|
|
138
|
+
Before the normal pipeline, a content-hash circuit breaker checks each note's
|
|
139
|
+
first 200 characters plus its full length. If one hash represents more than 80%
|
|
140
|
+
of the eligible batch, consolidation skips the LLM and all `notes.md`, KB/SQL,
|
|
141
|
+
and personal-memory writes, then archives the entire batch, including any
|
|
142
|
+
minority notes. This means a note from a duplicate-heavy batch may exist only
|
|
143
|
+
under `notes/archive/`.
|
|
144
|
+
|
|
145
|
+
The normal pipeline is:
|
|
146
|
+
|
|
147
|
+
1. Read the eligible inbox files and the current `notes.md`.
|
|
148
|
+
2. Ask the configured direct LLM (Haiku, one turn) for a concise deduplicated
|
|
149
|
+
digest. Each inbox body is fenced as untrusted input in the consolidation
|
|
150
|
+
prompt.
|
|
151
|
+
3. If the runtime is unavailable, output is malformed, the call fails, or the
|
|
152
|
+
three-minute deadline is exceeded, use the deterministic regex fallback.
|
|
153
|
+
4. Append the digest to `notes.md` under its file lock. If the existing file is
|
|
154
|
+
present but unreadable, defer the whole batch rather than risk clobbering it.
|
|
155
|
+
5. Classify every source note into a knowledge category. Reusable notes retain
|
|
156
|
+
their full body; narrow one-off notes become a short stub linked to the
|
|
157
|
+
archived original.
|
|
158
|
+
6. Upsert a global or project-scoped semantic record for the KB representation.
|
|
159
|
+
7. Route eligible notes into the configured author's personal file and upsert an
|
|
160
|
+
agent-scoped semantic record.
|
|
161
|
+
8. Archive processed inbox files. If an eligible personal-memory write fails,
|
|
162
|
+
leave that source note in the inbox so a later tick can retry it.
|
|
163
|
+
|
|
164
|
+
`notes.md` is kept near 50,000 JavaScript code units by trimming at section
|
|
165
|
+
boundaries and appending removed sections to
|
|
166
|
+
`notes/archive/notes-overflow.md`. If the overflow archive cannot be written,
|
|
167
|
+
the engine leaves the oversized file intact rather than lose content.
|
|
168
|
+
|
|
169
|
+
### Per-agent memory
|
|
170
|
+
|
|
171
|
+
Personal files use dated `### YYYY-MM-DD: <title>` sections. Routing requires:
|
|
172
|
+
|
|
173
|
+
- a valid agent id from frontmatter or the filename;
|
|
174
|
+
- a matching key in `config.agents`;
|
|
175
|
+
- a non-empty body; and
|
|
176
|
+
- a non-`temp-*` agent.
|
|
177
|
+
|
|
178
|
+
Each appended inbox body is fenced on disk with source provenance. Canonical
|
|
179
|
+
sectioned files are pruned oldest-first to at most
|
|
180
|
+
`engine.agentMemoryMaxEntries` (default `300`) and a 25,000-byte UTF-8 budget.
|
|
181
|
+
The newest section is retained even if it alone exceeds the byte target.
|
|
182
|
+
|
|
183
|
+
For correction-shaped notes, the conditional reconciliation pass can ask Haiku to
|
|
184
|
+
rewrite stale facts before appending. Failures fall back to a plain append. A
|
|
185
|
+
separate default-off summary pass can fold older sections into a fenced
|
|
186
|
+
`Earlier learnings summary`; it rechecks the file after the LLM call so a
|
|
187
|
+
concurrent append cannot be overwritten.
|
|
188
|
+
|
|
189
|
+
The heavier KB sweep is a separate process. `engine.autoConsolidateMemory`
|
|
190
|
+
controls its four-hour automatic cadence; it does not control inbox-to-notes
|
|
191
|
+
consolidation. See [kb-sweep.md](kb-sweep.md) for deduplication, TTL, rewrite,
|
|
192
|
+
and archive behavior.
|
|
193
|
+
|
|
194
|
+
## Structured records and FTS5 retrieval
|
|
195
|
+
|
|
196
|
+
Migration `017-agent-memory.js` created:
|
|
197
|
+
|
|
198
|
+
- `memory_records`, including content, type, scope, trust, confidence,
|
|
199
|
+
importance, provenance, validity, and supersession fields;
|
|
200
|
+
- the external-content `memory_records_fts` table over title, body, tags, and
|
|
201
|
+
source path, with insert/update/delete triggers; and
|
|
202
|
+
- `memory_retrieval_runs`, capped by the store to the newest 5,000 runs.
|
|
203
|
+
|
|
204
|
+
Supported record values are:
|
|
205
|
+
|
|
206
|
+
| Dimension | Values |
|
|
207
|
+
|-----------|--------|
|
|
208
|
+
| Type | `semantic`, `episodic`, `procedural` |
|
|
209
|
+
| Scope | `global`, `project:<key>`, `agent:<key>` |
|
|
210
|
+
| Trust | `human`, `system`, `agent`, `external` |
|
|
211
|
+
| Status | `active`, `superseded`, `retracted`, `expired` |
|
|
212
|
+
|
|
213
|
+
Built-in file ingestion creates semantic records. Completion capture creates
|
|
214
|
+
episodic records. The schema supports procedural records, but recall excludes
|
|
215
|
+
procedural content unless its trust is `human` or `system`.
|
|
216
|
+
|
|
217
|
+
Record ids are deterministic from source type, source reference, and content
|
|
218
|
+
hash. Re-upserting identical content is idempotent. New content for the same
|
|
219
|
+
source type/reference automatically supersedes the previous active row unless
|
|
220
|
+
the caller supplies an explicit supersession.
|
|
221
|
+
|
|
222
|
+
### Query construction and selection
|
|
223
|
+
|
|
224
|
+
`engine/memory-retrieval.js` builds a task query from the work-item title,
|
|
225
|
+
description, work type, failure class, source plan, references, PR title, and PR
|
|
226
|
+
branch. The SQL store:
|
|
227
|
+
|
|
228
|
+
1. tokenizes at most 32 unique non-stop-word terms;
|
|
229
|
+
2. issues an OR query against FTS5;
|
|
230
|
+
3. limits dispatch recall to active records in global, current-project, and
|
|
231
|
+
assigned-agent scopes; and
|
|
232
|
+
4. rejects agent/external procedural records.
|
|
233
|
+
|
|
234
|
+
FTS5 lexical rank supplies the initial order. A deterministic reranker then
|
|
235
|
+
boosts matching project/agent scope, human/system trust, task-mentioned source
|
|
236
|
+
paths, recency, importance, and confidence. Results are deduplicated by content
|
|
237
|
+
hash, then packed in rank order.
|
|
238
|
+
|
|
239
|
+
Every packed record includes:
|
|
240
|
+
|
|
241
|
+
- record id;
|
|
242
|
+
- type and scope;
|
|
243
|
+
- effective date; and
|
|
244
|
+
- `sourcePath` or `sourceRef`.
|
|
245
|
+
|
|
246
|
+
That provenance is visible both in the `Relevant Memory` appendix and the
|
|
247
|
+
dashboard's structured-memory search.
|
|
248
|
+
|
|
249
|
+
## Prompt assembly and fallback
|
|
250
|
+
|
|
251
|
+
`engine/playbook.js` renders the requested playbook, adds shared rules, then
|
|
252
|
+
appends memory context in this order:
|
|
253
|
+
|
|
254
|
+
1. **Pinned Context**, when `pinned.md` is non-empty.
|
|
255
|
+
2. Either **Relevant Memory** or the legacy pair:
|
|
256
|
+
- **Team Notes** from `notes.md`;
|
|
257
|
+
- **Personal Memory** from `knowledge/agents/<agentId>.md`.
|
|
258
|
+
3. Later non-memory appendices such as propagated project instructions.
|
|
259
|
+
|
|
260
|
+
Pinned context is independent of retrieval and remains present in every mode.
|
|
98
261
|
|
|
99
|
-
|
|
262
|
+
| Mode | Prompt behavior |
|
|
263
|
+
|------|-----------------|
|
|
264
|
+
| `memoryRetrieval` off | Pinned context plus legacy team/personal memory. No retrieval telemetry. |
|
|
265
|
+
| Flag on, `memoryRetrievalShadowMode: true` | Compute retrieval and store telemetry, but inject the legacy team/personal memory. |
|
|
266
|
+
| Flag on, shadow off, non-empty result | Inject pinned context plus `Relevant Memory`; suppress broad team/personal appendices. |
|
|
267
|
+
| Flag on, shadow off, empty query/no matches | Fall back to legacy team/personal memory. |
|
|
268
|
+
| Retrieval or telemetry write throws | Log a warning and fall back to legacy team/personal memory. |
|
|
100
269
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
270
|
+
Missing legacy files are skipped without failing dispatch.
|
|
271
|
+
|
|
272
|
+
### Bounds
|
|
273
|
+
|
|
274
|
+
| Content | Default bound | Enforcement |
|
|
275
|
+
|---------|---------------|-------------|
|
|
276
|
+
| Pinned input | 4,096 JavaScript UTF-16 code units, then a truncation notice | `String.length`/`slice`, despite the historical "4 KB" comment. |
|
|
277
|
+
| Retrieved pack | 8,192 UTF-8 bytes (`memoryRetrievalMaxBytes`) | Clamped to 1,024-65,536 bytes; includes record blocks and separators, but not the outer heading/fence. |
|
|
278
|
+
| Selected records | 8 (`memoryRetrievalTopK`) | Clamped to 1-30. |
|
|
279
|
+
| FTS candidate pool | 50 (`memoryRetrievalCandidateLimit`) | Dashboard accepts 5-200; the store hard-caps at 200. |
|
|
280
|
+
| Legacy team notes | 8,192 UTF-8 bytes (`ENGINE_DEFAULTS.maxNotesPromptBytes`) | Prefer the newest ten sections, then UTF-8-safe truncation and an older-entry footer. |
|
|
281
|
+
| Legacy personal memory | 8,192 UTF-8 bytes | Prefer the newest ten sections, then UTF-8-safe truncation. |
|
|
282
|
+
| Any untrusted fence body | 65,536 UTF-8 bytes (`ENGINE_DEFAULTS.untrustedFenceMaxBytes`) | UTF-8-safe truncation inside the fence with a remaining-byte marker. |
|
|
283
|
+
|
|
284
|
+
The configured retrieval budget controls selected record text, not all Markdown
|
|
285
|
+
or XML-like wrapper overhead added to the final prompt.
|
|
105
286
|
|
|
106
|
-
|
|
287
|
+
## Security and trust boundaries
|
|
107
288
|
|
|
108
|
-
|
|
109
|
-
|
|
289
|
+
Memory content is evidence, not a new instruction channel. Before prompt
|
|
290
|
+
insertion, pinned context, retrieved records, team notes, and personal memory
|
|
291
|
+
are wrapped with `engine/untrusted-fence.js`:
|
|
110
292
|
|
|
111
|
-
|
|
293
|
+
```text
|
|
294
|
+
<UNTRUSTED-INPUT source="kind:provenance">...</UNTRUSTED-INPUT>
|
|
295
|
+
```
|
|
112
296
|
|
|
113
|
-
|
|
297
|
+
The wrapper sanitizes the source attribute, escapes attempted closing tags, and
|
|
298
|
+
truncates by UTF-8 bytes. The consolidation LLM receives separately fenced
|
|
299
|
+
inbox bodies plus an explicit instruction to summarize rather than execute
|
|
300
|
+
their contents.
|
|
301
|
+
|
|
302
|
+
Additional defenses are:
|
|
303
|
+
|
|
304
|
+
- agent- or external-trusted procedural records are ineligible for recall;
|
|
305
|
+
- active retrieval includes record provenance and tells the agent to verify
|
|
306
|
+
claims against live code;
|
|
307
|
+
- a completion report flagged with
|
|
308
|
+
`failure_class: "injection-flagged"` is not captured as an episode; and
|
|
309
|
+
- nonce-mismatched completion reports never reach episodic capture.
|
|
310
|
+
|
|
311
|
+
`task_description` is deliberately not fenced because it is the instruction
|
|
312
|
+
being executed, not recalled evidence. For the broader threat model and the
|
|
313
|
+
required policy for new splice sites, see [security.md](security.md).
|
|
314
|
+
|
|
315
|
+
## Episodic capture
|
|
316
|
+
|
|
317
|
+
`captureTaskMemoryEpisode()` runs after completion status and nonce validation.
|
|
318
|
+
When enabled, it records:
|
|
319
|
+
|
|
320
|
+
- outcome, work item/type, agent, and project;
|
|
321
|
+
- PR reference and failure class;
|
|
322
|
+
- bounded affected-file and test lists; and
|
|
323
|
+
- a bounded result summary.
|
|
324
|
+
|
|
325
|
+
Secret-shaped values are redacted, and lists and strings are capped before
|
|
326
|
+
storage. The preferred summary comes from parsed runtime output or the structured
|
|
327
|
+
completion report. If neither supplies one and stdout has no `"type":` marker,
|
|
328
|
+
lifecycle falls back to raw stdout; that value is redacted and truncated to
|
|
329
|
+
4,000 characters, but transcript- or tool-log-like text is not filtered out.
|
|
330
|
+
Project scope is preferred, then agent scope, then global scope. Records use
|
|
331
|
+
system trust, with higher importance for failed and partial outcomes.
|
|
332
|
+
|
|
333
|
+
Capture is best-effort: a write failure is logged but does not change the task's
|
|
334
|
+
completion result.
|
|
335
|
+
|
|
336
|
+
## Configuration and feature flags
|
|
337
|
+
|
|
338
|
+
| Key | Default | Purpose |
|
|
339
|
+
|-----|---------|---------|
|
|
340
|
+
| `features.memoryRetrieval` | `true` | Enables structured retrieval. Feature resolution is environment override, then `config.features`, then registry default. |
|
|
341
|
+
| `engine.memoryRetrievalShadowMode` | `false` | Measure retrieval without replacing legacy prompt memory. |
|
|
342
|
+
| `engine.memoryRetrievalTopK` | `8` | Maximum selected records. |
|
|
343
|
+
| `engine.memoryRetrievalMaxBytes` | `8192` | UTF-8 byte budget for selected record blocks. |
|
|
344
|
+
| `engine.memoryRetrievalCandidateLimit` | `50` | FTS5 candidates before reranking. |
|
|
345
|
+
| `engine.memoryEpisodicCapture` | `false` | Store compact completion episodes. |
|
|
346
|
+
| `engine.inboxConsolidateThreshold` | `5` | Eligible inbox files required before consolidation starts. |
|
|
347
|
+
| `engine.autoConsolidateMemory` | `false` | Automatically run the separate KB sweep every four hours. |
|
|
348
|
+
| `engine.agentMemoryMaxEntries` | `300` | Non-summary section window in a personal file. |
|
|
349
|
+
| `engine.agentMemorySummaryEnabled` | `false` | Enable LLM compression of older personal sections. |
|
|
350
|
+
| `engine.agentMemorySummaryThreshold` | `30` | Oldest-section batch size for a summary. |
|
|
351
|
+
| `engine.agentMemorySummaryDays` | `30` | Age trigger for summary eligibility. |
|
|
352
|
+
|
|
353
|
+
The feature flag is exposed by the generic Dashboard **Settings > Features**
|
|
354
|
+
surface. Settings also exposes shadow mode, episodic capture, retrieval bounds,
|
|
355
|
+
the inbox threshold, and automatic KB sweep. The personal-file window and
|
|
356
|
+
summary keys are configuration-only today.
|
|
357
|
+
|
|
358
|
+
The environment override for the feature is
|
|
359
|
+
`MINIONS_FEATURE_MEMORYRETRIEVAL=1|0`.
|
|
360
|
+
|
|
361
|
+
## Dashboard and API surfaces
|
|
362
|
+
|
|
363
|
+
The classic Dashboard **Inbox** page combines Quick Notes, Team Notes,
|
|
364
|
+
Knowledge Base, the manual KB sweep, and **Memory search**; pinned context is
|
|
365
|
+
managed from the Home page. Structured search operates across all scopes and can
|
|
366
|
+
inspect each lifecycle status.
|
|
367
|
+
|
|
368
|
+
| Method | Path | Role |
|
|
369
|
+
|--------|------|------|
|
|
370
|
+
| `POST` | `/api/notes` | Create an inbox note for consolidation. |
|
|
371
|
+
| `GET` / `POST` | `/api/pinned` | Read or add pinned context. |
|
|
372
|
+
| `POST` | `/api/pinned/update` | Replace a pinned entry. |
|
|
373
|
+
| `POST` | `/api/pinned/remove` | Remove a pinned entry. |
|
|
374
|
+
| `GET` | `/api/knowledge` | List readable knowledge entries. |
|
|
375
|
+
| `POST` | `/api/knowledge` | Create a human-authored KB file and SQL record. |
|
|
376
|
+
| `GET` | `/api/knowledge/<category>/<file>` | Read one KB file. |
|
|
377
|
+
| `POST` | `/api/knowledge/sweep` | Start the asynchronous KB sweep. |
|
|
378
|
+
| `GET` | `/api/knowledge/sweep/status` | Poll sweep status. |
|
|
379
|
+
| `GET` | `/api/memory-records/search?q=...&status=active&limit=20` | Search structured records with provenance. |
|
|
380
|
+
| `POST` | `/api/memory-records/<id>/action` | Apply `pin`, `retract`, or `restore`. |
|
|
381
|
+
| `POST` | `/api/inbox/persist` | Copy an inbox excerpt into `notes.md`, then archive the source. |
|
|
382
|
+
| `POST` | `/api/inbox/promote-kb` | Move an inbox item into a selected KB category. |
|
|
383
|
+
|
|
384
|
+
A structured-record `pin` is not the same as a pinned note. It changes that SQL
|
|
385
|
+
row to human trust, importance `1`, confidence of at least `0.9`, and active
|
|
386
|
+
status. It does not write `pinned.md`, bypass lexical matching, or guarantee
|
|
387
|
+
selection within the top-K/budget.
|
|
388
|
+
|
|
389
|
+
## Operations and troubleshooting
|
|
390
|
+
|
|
391
|
+
### Inspect the active surfaces
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
curl http://localhost:7331/api/pinned
|
|
395
|
+
curl http://localhost:7331/api/knowledge
|
|
396
|
+
curl "http://localhost:7331/api/memory-records/search?q=worktree&status=active&limit=20"
|
|
397
|
+
```
|
|
114
398
|
|
|
115
|
-
|
|
399
|
+
Use `GET /api/routes` to confirm the live route catalog.
|
|
116
400
|
|
|
117
|
-
|
|
118
|
-
- Agents work in parallel. Letting any agent rewrite `knowledge/` entries makes consolidation non-deterministic and makes blame attribution impossible.
|
|
119
|
-
- Knowledge base entries are referenced by date-stamped path. Rewriting an entry breaks every existing link.
|
|
401
|
+
### Expected legacy fallback
|
|
120
402
|
|
|
121
|
-
|
|
403
|
+
Seeing **Team Notes** and **Personal Memory** instead of **Relevant Memory** is
|
|
404
|
+
expected when the feature is off, shadow mode is on, the task query has no
|
|
405
|
+
indexable terms, FTS5 finds no eligible rows, or retrieval/telemetry throws.
|
|
406
|
+
Check engine logs for `Memory retrieval failed ...; using legacy memory`.
|
|
122
407
|
|
|
123
|
-
|
|
408
|
+
### A note remains in the inbox
|
|
124
409
|
|
|
125
|
-
|
|
410
|
+
Check:
|
|
126
411
|
|
|
127
|
-
The
|
|
412
|
+
1. The eligible file count has reached `engine.inboxConsolidateThreshold`.
|
|
413
|
+
2. The note is not pinned against consolidation.
|
|
414
|
+
3. A prior consolidation is not still in flight.
|
|
415
|
+
4. `notes.md` and its lock are writable.
|
|
416
|
+
5. For a configured agent, the personal-memory write did not fail and defer
|
|
417
|
+
archiving.
|
|
128
418
|
|
|
129
|
-
|
|
419
|
+
An LLM failure alone should not strand the batch; the regex fallback handles it.
|
|
130
420
|
|
|
131
|
-
|
|
421
|
+
### Personal memory is missing
|
|
132
422
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
| `agentMemorySummaryThreshold` | `30` | When the summary pass fires, fold this many oldest entries into one summary section. |
|
|
139
|
-
| `agentMemorySummaryDays` | `30` | Age trigger: if the oldest entry is older than this, fold even when under the entry cap. |
|
|
423
|
+
Confirm that `agent:` exactly matches a configured `config.agents` key, or that
|
|
424
|
+
the filename starts with that id. `temp-*`, unknown, invalid, and empty authors
|
|
425
|
+
are intentionally skipped. Also remember that successful active retrieval
|
|
426
|
+
suppresses the broad personal-file appendix; the relevant agent-scoped record
|
|
427
|
+
may instead appear inside **Relevant Memory**.
|
|
140
428
|
|
|
141
|
-
|
|
429
|
+
### Search misses known Markdown
|
|
142
430
|
|
|
143
|
-
|
|
431
|
+
Structured search is lexical FTS5, not semantic embeddings. It ignores common
|
|
432
|
+
task stop words, searches only the requested lifecycle status, and dispatch
|
|
433
|
+
retrieval uses exact project/agent scope keys. More importantly, out-of-band
|
|
434
|
+
file edits and file-only mutation paths are not automatically reindexed. Compare
|
|
435
|
+
the record's `sourcePath`/`sourceRef` with the current file before trusting it.
|
|
144
436
|
|
|
145
|
-
|
|
437
|
+
Do not repair divergence by editing `engine/state.db` directly. Use the supported
|
|
438
|
+
dashboard/API ingestion paths or fix the originating writer so provenance and
|
|
439
|
+
events remain intact.
|
|
146
440
|
|
|
147
|
-
|
|
441
|
+
## Agent read and write rules
|
|
148
442
|
|
|
149
|
-
|
|
443
|
+
The shared playbook's on-disk lookup order remains:
|
|
150
444
|
|
|
151
|
-
```
|
|
152
|
-
1. pinned.md
|
|
153
|
-
2. knowledge/
|
|
154
|
-
3. notes.md
|
|
155
|
-
4. notes/inbox/
|
|
445
|
+
```text
|
|
446
|
+
1. pinned.md - critical operator context; read first
|
|
447
|
+
2. knowledge/ - categorized KB; read, never write
|
|
448
|
+
3. notes.md - consolidated team digest
|
|
449
|
+
4. notes/inbox/ - newest unconsolidated findings
|
|
450
|
+
5. related live output and prior work-item summaries
|
|
451
|
+
6. external research
|
|
156
452
|
```
|
|
157
453
|
|
|
158
|
-
|
|
454
|
+
This lookup discipline complements prompt retrieval; it does not mean all four
|
|
455
|
+
Markdown tiers are automatically copied into the prompt.
|
|
456
|
+
|
|
457
|
+
## Implementation map
|
|
458
|
+
|
|
459
|
+
- [`engine/consolidation.js`](../engine/consolidation.js) - inbox digest,
|
|
460
|
+
classification, personal routing, pruning, reconciliation, and summary.
|
|
461
|
+
- [`engine/db/migrations/017-agent-memory.js`](../engine/db/migrations/017-agent-memory.js)
|
|
462
|
+
- schema and one-time Markdown backfill.
|
|
463
|
+
- [`engine/memory-store.js`](../engine/memory-store.js) - record validation,
|
|
464
|
+
lifecycle, FTS5 query, and telemetry persistence.
|
|
465
|
+
- [`engine/memory-retrieval.js`](../engine/memory-retrieval.js) - task query,
|
|
466
|
+
reranking, deduplication, provenance formatting, and byte packing.
|
|
467
|
+
- [`engine/playbook.js`](../engine/playbook.js) - pinned/retrieved/legacy prompt
|
|
468
|
+
assembly and fallback.
|
|
469
|
+
- [`engine/lifecycle.js`](../engine/lifecycle.js) - episodic completion capture.
|
|
470
|
+
- [`engine/untrusted-fence.js`](../engine/untrusted-fence.js) - provenance fence
|
|
471
|
+
and UTF-8-safe truncation.
|
|
472
|
+
- [`dashboard.js`](../dashboard.js) and
|
|
473
|
+
[`dashboard/js/memory-search.js`](../dashboard/js/memory-search.js) -
|
|
474
|
+
operator APIs and UI.
|
|
159
475
|
|
|
160
476
|
## See also
|
|
161
477
|
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
478
|
+
- [kb-sweep.md](kb-sweep.md) - curation and retention of readable KB files.
|
|
479
|
+
- [named-agents.md](named-agents.md) - agent configuration and routing.
|
|
480
|
+
- [security.md](security.md) - trust boundaries and prompt-injection policy.
|
|
481
|
+
- [self-improvement.md](self-improvement.md) - memory within the broader
|
|
482
|
+
feedback loop.
|