@fingerskier/augment 0.5.0 → 0.5.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/docs/FEATURES.md CHANGED
@@ -1,758 +1,771 @@
1
- # Augment Features
2
-
3
- Augment is a local RAG memory system for coding agents.
4
-
5
- ## Memory Folder
6
-
7
- - The memory folder is a normal directory.
8
- - Only one memory root is configured per local system.
9
- - Memory file paths are relative to this root.
10
-
11
- ## Memories
12
-
13
- - Memories are text files in the memory folder.
14
- - Files are markdown with YAML frontmatter.
15
- - Canonical organization:
16
-
17
- ```txt
18
- org/repo/kind/name.md
19
- .generic/kind/name.md
20
- ```
21
-
22
- - Supported kinds:
23
- - `ISSUE`
24
- - `ARCH`
25
- - `TODO`
26
- - `SPEC`
27
- - `WORK`
28
-
29
- Memory files are the canonical source of truth. Numeric memory IDs are local
30
- database IDs only and are not written to memory files. Relative paths are the
31
- durable cross-system identity.
32
-
33
- Example:
34
-
35
- ```md
36
- ---
37
- kind: ARCH
38
- project: fingerskier/augment
39
- name: search-contract
40
- tags: [mcp, search, ranking]
41
- links:
42
- - to: fingerskier/augment/SPEC/local-daemon.md
43
- type: RELATED
44
- created_at: 2026-06-29T00:00:00Z
45
- updated_at: 2026-06-29T00:00:00Z
46
- ---
47
-
48
- Body text.
49
- ```
50
-
51
- Generic memories are ordinary memory files of any supported kind under the
52
- reserved `.generic/` directory; glean output is restricted to durable SPEC or
53
- ARCH records. The path is authoritative: `.generic/SPEC/retries.md` is generic
54
- even if externally edited frontmatter says otherwise. Normal CRUD and an
55
- explicit `project_name: ".generic"` work, but project inference never selects the
56
- reserved pseudo-project and routine current-project search does not boost it as
57
- an exact project match. Generic memories still participate in normal global
58
- search alongside current- and foreign-project memories.
59
-
60
- ## Database
61
-
62
- - A shared local daemon watches memory files and maintains a rebuildable libsql
63
- index.
64
- - The database includes metadata, body text, embeddings, gzip density score, and
65
- derived link rows.
66
- - `Xenova/bge-small-en-v1.5` via `@huggingface/transformers` provides 384D
67
- embeddings. The model revision is recorded as a tripwire constant
68
- (`PINNED_MODEL_REVISION`) for reproducibility.
69
- - Indexing is incremental: an external edit reindexes only the changed file, a
70
- full rebuild skips unchanged files by mtime, and the daemon's own writes are
71
- indexed inline (no watcher round-trip).
72
- - The database file is rebuildable and should not be synced as canonical state.
73
-
74
- Tables:
75
-
76
- - `projects` — `id`, `name`, `org`, `repo`, `source`, `created_at`, `updated_at`.
77
- - `memories` — `id`, `project_id`, `kind`, `name`, `relative_path`,
78
- `content_hash`, `frontmatter_hash`, `size`, `density`, `mtime`, `tags_json`,
79
- `links_json`, `body`, `created_at`, `updated_at`.
80
- - `memory_embeddings` — `memory_id`, `model_id`, `model_version`, `dimensions`,
81
- `vector_json`, `embedded_hash`, `embedded_at`.
82
- - `links` — `id`, `from_memory_id`, `to_memory_id`, `type`, `created_at`
83
- (unique on `from` + `to` + `type`).
84
-
85
- Links are written to the source memory's frontmatter using target relative paths.
86
- The daemon rebuilds local `links` rows from those declarations. A mutation
87
- (`upsert`/`link`/`unlink`) repairs only the touched memory's link subgraph, so
88
- link IDs survive *unrelated* mutations within a daemon run — but the touched
89
- memory's own outbound link IDs are reassigned each time, and all IDs churn on a
90
- full index rebuild. Relative paths remain the durable identity.
91
-
92
- ## Daemon
93
-
94
- - `augment-daemon` is shared by all local MCP servers for one memory root.
95
- - The daemon owns file watching, embedding, and database writes.
96
- - It exposes a localhost HTTP control endpoint.
97
- - It binds to `127.0.0.1`, uses a dynamic port by default, writes a discovery
98
- file, and serves all routes without auth (loopback-only; no token required).
99
- - It starts serving immediately and builds the initial index in the background
100
- (a cold corpus no longer blocks hooks or clients on the port);
101
- `GET /index/status` reports `{ ok, ready, error? }`.
102
- - Besides memory/link CRUD it serves `/health`, `/index/rebuild`, and the
103
- dashboard UI.
104
- - Memories can be deleted via the dashboard or `DELETE /memories/:id` (the file
105
- and DB row are removed and inbound frontmatter links in other memories are
106
- scrubbed). Ordinary delete is deliberately **not** exposed as an MCP tool;
107
- `decoction_cleanup` is the narrowly scoped, explicitly approved exception.
108
-
109
- ## Git auto-commit
110
-
111
- When the memory root is itself a git repository, the daemon auto-commits
112
- augment's own writes so the corpus carries its own version history — no manual
113
- snapshotting required.
114
-
115
- - **Enabled by default**; disable with `AUGMENT_GIT_AUTOCOMMIT=0` (also `false`,
116
- `no`, `off`).
117
- - **Daemon-side and debounced.** Only augment's own mutations (upsert, delete,
118
- link, unlink) schedule a commit; a burst of writes coalesces into one snapshot
119
- commit. External/editor/Dropbox edits are *not* committed.
120
- - **Markdown only.** It stages `*.md` (`git add -A -- '*.md'`), so a nested state
121
- dir or unrelated files are never swept in, and every memory mutation — including
122
- deletes and link scrubs — is captured.
123
- - **Root-repo only.** It engages only when the memory root is the git worktree
124
- root, never when it merely sits inside a larger project repo.
125
- - **Never pushes, always fails open.** Commits stay local; any git failure is
126
- logged once and swallowed so a snapshot can never break a write. A fresh
127
- `git init` with no configured identity still commits (a fallback
128
- `Augment <augment@localhost>` identity is used only when none is set).
129
- - The check runs **once at daemon startup**, so enabling the flag or `git init`-ing
130
- the memory root takes effect on the next daemon restart.
131
-
132
- ## Dashboard
133
-
134
- A daemon-served single-page web UI for browsing and editing memories as a graph:
135
-
136
- - Project graph drills into a per-project memory subgraph (nodes colored by
137
- kind, edges labeled by link type).
138
- - Ad hoc semantic search, memory create/edit/delete, link create/delete.
139
- - Launched via `augment dashboard [--no-open]`; loopback-only; honors
140
- `AUGMENT_DAEMON_PORT`.
141
- - Fully self-contained assets (Cytoscape bundled from `node_modules`; no CDN).
142
-
143
- ## CLI
144
-
145
- Run without a clone via `npx -y @fingerskier/augment <command>`:
146
-
147
- - `status` — print the resolved config (default command; `config` is an alias).
148
- - `install <codex|claude|all>` — wire agent integrations (see
149
- [Agent Integration Installer](#agent-integration-installer)).
150
- - `dashboard [--no-open]` — start the daemon and open the web UI.
151
- - `recall "<query>" [--project <org/repo>] [--cwd <dir>] [--limit N]
152
- [--max-chars N] [--min-score X]` — print the same context-injection text the
153
- hooks use. No match prints the explicit abstention message ("No memory met
154
- the relevance threshold …"); output is empty only on failure (daemon down,
155
- blank query).
156
- - `hook <session-start|user-prompt-submit|pre-tool-use|stop>` — run a lifecycle
157
- hook over stdin JSON. Host-wired by `install`; rarely called directly.
158
- - `help` — full usage.
159
-
160
- ## Pi Package
161
-
162
- The npm package is also a first-class Pi package (`keywords: ["pi-package"]` and
163
- a `pi` manifest in `package.json`). `pi install npm:@fingerskier/augment` loads:
164
-
165
- - `dist/pi/extension.js` — a Pi extension that registers namespaced
166
- `augment_*` tools and slash commands.
167
- - `integrations/pi/skills/augment-context/SKILL.md`,
168
- `integrations/pi/skills/augment-decoction/SKILL.md`, and
169
- `integrations/pi/skills/augment-dream/SKILL.md` — Pi-specific workflow guidance
170
- using the `augment_*` tool names.
171
-
172
- The Pi extension does not replace built-ins such as `read`; MCP `read` is exposed
173
- as `augment_read_memory`. It lazily connects to the shared daemon from tools and
174
- session events (no background resources start in the extension factory), warms
175
- `init_project` on `session_start`, injects recalled task context on
176
- `before_agent_start`, and reminds or follows up after non-trivial turns to
177
- persist durable work.
178
-
179
- Pi tools:
180
-
181
- - `augment_init_project`, `augment_list_projects`
182
- - `augment_search`, `augment_project_context`, `augment_read_memory`
183
- - `augment_upsert`, `augment_link`, `augment_list_links`, `augment_unlink`
184
- - `augment_decoction_glean`, `augment_decoction_cleanup`
185
- - `augment_sleep_candidates`, `augment_sleep_propose`, `augment_sleep_proposals`,
186
- `augment_sleep_apply`, `augment_sleep_reject`
187
- - `augment_dream_propose`, `augment_dream_proposals`, `augment_dream_apply`,
188
- `augment_dream_reject`
189
- - `augment_memory_insights`, `augment_memory_graph`
190
-
191
- Pi commands:
192
-
193
- - `/augment-context [query]`
194
- - `/augment-persist [summary]`
195
- - `/augment-dashboard [--no-open]`
196
- - `/augment-sleep`
197
- - `/augment-dream`
198
-
199
- Pi-specific environment variables:
200
-
201
- - `AUGMENT_PI_AUTO_CONTEXT=inject|reminder|off` (default `inject`).
202
- - `AUGMENT_PI_AUTO_PERSIST=reminder|followup|off` (default `reminder`).
203
- - `AUGMENT_PI_CONTEXT_LIMIT` (default `5`).
204
- - `AUGMENT_PI_CONTEXT_MAX_CHARS` (default `12000`).
205
-
206
- Pi and MCP expose the same sleep, decoction, and dream lifecycle operations;
207
- Claude/Codex skills supply the agent-side synthesis and approval guidance. The
208
- CLI and lifecycle-hook behavior is unchanged.
209
-
210
- ## Lifecycle Hooks
211
-
212
- Both installed integrations wire the same `hooks/hooks.json` (Claude Code and
213
- Codex share the event names and stdin-JSON contract). Every handler **fails
214
- open** any error yields empty output and exit 0, so a broken hook can never
215
- break the host agent.
216
-
217
- - `SessionStart` — warms the daemon and registers the project.
218
- - `UserPromptSubmit` — recalls memory for the prompt and injects it as
219
- `additionalContext` before the model sees the prompt.
220
- - `PreToolUse` (matcher `Edit|Write|Bash`) recalls additional memory keyed to
221
- the tool action (the edited file / the Bash command). Uses a raised relevance
222
- floor (0.45, calibrated on the real model tool queries are command/path
223
- shaped, not prose) and injects each distinct query at most once per session.
224
- Injection-only: never blocks, gates, or rewrites a tool call.
225
- - `Stop` blocks the turn once with a directive to upsert a memory, then allows
226
- the stop (loop-guarded per turn).
227
-
228
- Installed hook commands invoke the install-time-provisioned runtime directly
229
- (`node <prefix>/node_modules/@fingerskier/augment/dist/bin/augment.js hook
230
- <event>`) — no npm bootstrap on the hot path.
231
-
232
- The verification process for the whole flow is
233
- [docs/verify-memory-flow.md](verify-memory-flow.md).
234
-
235
- ## Recall Log
236
-
237
- Every `/memories/search` appends one JSON line to `<stateDir>/recall/events.jsonl`
238
- recording what recall actually returned: `ts`, `surface`, `project`, `query`,
239
- `abstained`, `result_count`, `top_score`, and `paths`. It is the passive
240
- instrument that caught the 2026-07-10 memoryRoot split-brain (six days of
241
- empty-corpus recalls that abstained silently).
242
-
243
- - **Passive and human-rating-free.** Search records events without asking users
244
- to rate individual results.
245
- - **Best-effort by design.** A failed append never fails the search that
246
- triggered it.
247
- - **Single-slot rotation.** When the file exceeds `RECALL_LOG_MAX_BYTES` (5 MB)
248
- it is rotated to `events.jsonl.1` before the next append the log is
249
- diagnostic, not a record of account.
250
-
251
- ## MCP Tools
252
-
253
- ### `init_project`
254
-
255
- Infers or accepts a project name and upserts a project record.
256
-
257
- Inputs:
258
-
259
- ```ts
260
- { project_name?: string }
261
- ```
262
-
263
- ### `list_projects`
264
-
265
- Lists known project records.
266
-
267
- Inputs:
268
-
269
- ```ts
270
- { name?: string }
271
- ```
272
-
273
- ### `search`
274
-
275
- Recalls memories semantically and lexically similar to a query.
276
-
277
- Inputs:
278
-
279
- ```ts
280
- {
281
- project_name?: string;
282
- query: string;
283
- limit?: number; // default 5, max 20
284
- max_chars?: number; // default 12000, max 50000
285
- kinds?: Array<"ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK">;
286
- include_linked?: boolean;
287
- min_score?: number; // 0..1 relevance floor; default 0.4, 0 disables
288
- }
289
- ```
290
-
291
- Behavior:
292
-
293
- - Returns plain text suitable for direct context injection.
294
- - Includes local memory IDs, project names, paths, kinds, scores, and link
295
- annotations.
296
- - May use the CWD project as a modest metadata boost, but cross-project results
297
- are allowed based on score.
298
- - Labels the provenance of each result relative to the querying project: a memory
299
- from another repo in the same org is marked `provenance:foreign-cross-repo`, and
300
- one from another org `provenance:foreign-cross-org`. The shared memory store is
301
- multi-author, so cross-project recall is also cross-author the marker lets the
302
- consuming agent discount memory it did not author (a relevance floor alone can't
303
- stop a genuinely-relevant foreign memory).
304
- - Prioritizes linked memories without requiring them.
305
- - **Down-weights archived memories** (a WORK source consolidated by a `sleep`
306
- pass) rather than hiding them: their blended score is multiplied by
307
- `ARCHIVED_SEARCH_WEIGHT` (0.5, after the blend and before the floor), so the
308
- consolidated record outranks its sources while the sources stay auditable.
309
- `read` still returns an archived memory's body verbatim.
310
- - Applies a minimum relevance threshold (`min_score`, default
311
- `DEFAULT_SEARCH_MIN_SCORE` = 0.4) and **abstains** when nothing clears it —
312
- returning no results and a "nothing injected" message rather than surfacing an
313
- unrelated memory. The floor is calibrated against the real embedding model:
314
- after the empirically-anchored cosine rescale (`SEMANTIC_COSINE_BASELINE`
315
- 0.33), an unrelated memory blends to ~0.12 while an on-topic one lands ~0.60,
316
- so 0.4 separates abstention from recall with margin. Pass `min_score: 0` to
317
- disable the floor (never abstain), or raise it to demand a stronger match.
318
- - Packs results under a fair-share character budget: each result may use an even
319
- split of the remaining `max_chars`, with unused share rolling forward; an
320
- oversized body is head-truncated with a visible `[truncated]` marker rather
321
- than omitted, and a result is skipped only when fewer than 80 usable characters
322
- remain. Bodies are whole-file prefixes never summarized.
323
-
324
- ### `upsert`
325
-
326
- Stores text in a memory file.
327
-
328
- Inputs:
329
-
330
- ```ts
331
- {
332
- project_id: number;
333
- memory_id?: number;
334
- kind?: "ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK";
335
- name: string;
336
- content: string;
337
- tags?: string[];
338
- }
339
- ```
340
-
341
- If `memory_id` is absent, Augment may automatically update a highly similar
342
- memory in the same project and kind but only when the new content subsumes the
343
- existing one (every distinct term of the prior body survives in the new content),
344
- so the in-place update is a lossless refresh. If the new content instead
345
- contradicts or omits something the prior memory held, Augment preserves the prior
346
- memory intact and stores the new content as its own memory rather than silently
347
- overwriting history.
348
-
349
- Content is capped at 12,000 characters; an oversized upsert is rejected — split
350
- the note instead.
351
-
352
- ### `read`
353
-
354
- Reads one memory by local numeric ID.
355
-
356
- Inputs:
357
-
358
- ```ts
359
- { id: number }
360
- ```
361
-
362
- ### `link`
363
-
364
- Creates a directional link between memories and persists it as a relative-path
365
- link in the source memory frontmatter.
366
-
367
- Inputs:
368
-
369
- ```ts
370
- {
371
- from_memory_id: number | string;
372
- to_memory_id: number | string;
373
- type?: "DEPENDS_ON" | "BLOCKS" | "IMPLEMENTS" | "PARENT" | "RELATED";
374
- }
375
- ```
376
-
377
- Each reference may be a local numeric ID **or** a relative path
378
- (`org/repo/KIND/name.md`). Paths are the durable handle they survive index
379
- rebuilds, while numeric IDs churn. An all-digit string is interpreted as a
380
- numeric ID.
381
-
382
- ### `list_links`
383
-
384
- Lists inbound and outbound links involving a memory.
385
-
386
- Inputs:
387
-
388
- ```ts
389
- { memory_id: number }
390
- ```
391
-
392
- ### `unlink`
393
-
394
- Removes a link by local link ID.
395
-
396
- Inputs:
397
-
398
- ```ts
399
- { id: number }
400
- ```
401
-
402
- ### `decoction_glean`
403
-
404
- Discovers recurring cross-project evidence or writes an agent-authored generic
405
- memory. It is separate from sleep and performs no LLM synthesis itself.
406
-
407
- Inputs:
408
-
409
- ```ts
410
- { action: "discover"; min_cosine?: number; limit?: number }
411
-
412
- // or
413
- {
414
- action: "write";
415
- kind: "SPEC" | "ARCH";
416
- name: string;
417
- content: string;
418
- tags?: string[];
419
- derived_from: string[];
420
- suggested_removals?: Array<{ path: string; reason: string }>;
421
- expected_content_hash?: string;
422
- expected_frontmatter_hash?: string;
423
- }
424
- ```
425
-
426
- Discovery uses the existing memory embeddings and complete-link clustering:
427
- every pair in a cluster must meet `min_cosine` (default `0.75`), and a result
428
- must span at least four distinct projects. Multiple memories from one project
429
- count once; `local/*` projects count normally. Existing generics, archived
430
- memories, and sources tagged `private` or `no-generalize` are excluded; there is
431
- no age gate. Eligible evidence kinds are WORK, ISSUE, SPEC, and ARCH.
432
-
433
- Write stores a normal `.generic/<KIND>/<name>.md` memory with `derived_from`
434
- provenance. Those unique sources must satisfy the same eligibility rules and
435
- span at least four projects. Removal suggestions and credential-shaped-content
436
- warnings are returned to the agent but are not persisted as lifecycle metadata.
437
- Warnings do not block the write. Creating a generic omits expected hashes;
438
- updating one requires both current hashes so a stale glean cannot overwrite a
439
- newer edit.
440
-
441
- ### `decoction_cleanup`
442
-
443
- Hard-deletes an explicitly approved set of originals after retargeting their
444
- typed inbound links to one generic memory.
445
-
446
- Inputs:
447
-
448
- ```ts
449
- { generic_path: string; source_paths: string[] }
450
- ```
451
-
452
- The whole request is prevalidated before deletion: the target must be generic,
453
- every source must exist, and no source may itself be generic. Cleanup then
454
- returns one result per source. There is no journal or rollback; a runtime failure
455
- does not undo sources already processed. The generic keeps its `derived_from`
456
- paths as historical provenance.
457
-
458
- ### `sleep_candidates`
459
-
460
- READ-ONLY preview of sleep consolidation. Clusters settled WORK memories
461
- (default: older than 3 days by `updated_at`) within each project into candidate
462
- groups a `sleep` pass distills into SPEC/ARCH records via `sleep_propose`
463
- user approval `sleep_apply`.
464
-
465
- - Edges: existing links of any type, or raw cosine >= `min_cosine`
466
- (default 0.75 semantic-only, deliberately above the blended recall floor;
467
- see `SLEEP_MIN_COSINE` in `src/constants.ts`).
468
- - Clusters never span projects; archived memories are excluded from candidacy.
469
- Output reports durable `relative_path`s.
470
- - Input: optional `project_name` (inferred from cwd otherwise), `min_cosine`,
471
- `min_age_days`, `limit` (default 20, `SLEEP_MAX_CLUSTERS`).
472
- - Mutates nothing.
473
-
474
- ### `sleep_propose`
475
-
476
- Draft a sleep consolidation: fold ≥2 settled WORK memories into one new SPEC or
477
- ARCH record. Writes **only** a proposal file outside the corpus (under
478
- `<stateDir>/sleeps/`), for user review the corpus is untouched until the user
479
- approves and `sleep_apply` runs.
480
-
481
- Inputs:
482
-
483
- ```ts
484
- {
485
- project_name?: string; // inferred from cwd otherwise
486
- kind: "SPEC" | "ARCH";
487
- name: string;
488
- content: string;
489
- derived_from: string[]; // >=2 WORK relative paths, all in project_name
490
- rationale?: string;
491
- }
492
- ```
493
-
494
- Validation (shared by propose, re-checked at apply since drafts sit while the
495
- corpus moves): every `derived_from` path resolves in the corpus, all are kind
496
- `WORK`, all belong to `project_name` (single-project constraint), none archived,
497
- `derived_from.length >= 2`, and the target path
498
- `<project>/<kind>/<name>.md` must not already exist. The proposal body is
499
- user-editable on disk before approval.
500
-
501
- ### `sleep_proposals`
502
-
503
- Lists sleep proposals drafted by `sleep_propose`, optionally filtered by status.
504
-
505
- Inputs:
506
-
507
- ```ts
508
- { status?: "proposed" | "applied" | "rejected" }
509
- ```
510
-
511
- ### `sleep_apply`
512
-
513
- Applies a sleep proposal by filename. Requires explicit user approval of the
514
- named proposal and is the **only** corpus write in the sleep flow: it re-reads
515
- the proposal fresh from disk, re-validates, upserts the consolidated SPEC/ARCH
516
- (with `derived_from` provenance), archives each WORK source in place
517
- (`archived: true` + `consolidated_into:`, body byte-untouched), and marks the
518
- proposal `applied`. The daemon route lands the whole pass as one revertible
519
- `sleep:` git commit on the memory root.
520
-
521
- Inputs:
522
-
523
- ```ts
524
- { filename: string }
525
- ```
526
-
527
- ### `sleep_reject`
528
-
529
- Rejects a pending sleep proposal by filename. Mutates only the proposal file
530
- (outside the corpus); the corpus is untouched.
531
-
532
- Inputs:
533
-
534
- ```ts
535
- { filename: string }
536
- ```
537
-
538
- ### `dream_propose`
539
-
540
- Writes a user-reviewable speculative memory or link proposal under
541
- `<stateDir>/dreams/`; it does not mutate the corpus. Agents gather inspiration
542
- through normal global search, which prioritizes the current project while still
543
- returning generic and foreign-project memories.
544
-
545
- Inputs:
546
-
547
- ```ts
548
- {
549
- project_name?: string; // defaults to cwd inference; must be a real project
550
- kind: "ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK";
551
- name: string;
552
- content: string;
553
- derived_from: string[]; // >=1 current, generic, or foreign memory
554
- rationale?: string;
555
- }
556
-
557
- // or
558
- {
559
- project_name?: string; // defaults to cwd inference; must be a real project
560
- link: {
561
- from: string;
562
- to: string;
563
- type: "DEPENDS_ON" | "BLOCKS" | "IMPLEMENTS" | "PARENT" | "RELATED";
564
- };
565
- rationale?: string;
566
- }
567
- ```
568
-
569
- A dream memory is created in the inferred or explicit current real project and
570
- may be inspired entirely by generic or foreign memories. `.generic` cannot be
571
- the active dream project. A dream link's source must belong to the current
572
- project; its target may belong to any project. The draft remains editable until
573
- apply.
574
-
575
- ### `dream_proposals`
576
-
577
- Lists both dream-memory and dream-link proposals, optionally filtered by status.
578
-
579
- Inputs:
580
-
581
- ```ts
582
- { status?: "proposed" | "applied" | "rejected" }
583
- ```
584
-
585
- ### `dream_apply`
586
-
587
- Re-reads and revalidates one explicitly approved proposal. A dream-memory apply
588
- creates the reviewed record with the `dream` tag and `derived_from` provenance;
589
- a dream-link apply creates exactly the reviewed link. The daemon records the
590
- corpus mutation as a `dream:` git commit when git auto-commit is available.
591
-
592
- Inputs:
593
-
594
- ```ts
595
- { filename: string }
596
- ```
597
-
598
- ### `dream_reject`
599
-
600
- Rejects a pending dream proposal without changing the corpus.
601
-
602
- Inputs:
603
-
604
- ```ts
605
- { filename: string }
606
- ```
607
-
608
- ### `memory_insights`
609
-
610
- Aggregates a project's memory graph into dashboard insights.
611
-
612
- Inputs:
613
-
614
- ```ts
615
- { project_name?: string }
616
- ```
617
-
618
- Behavior:
619
-
620
- - Resolves the project strictly (exact name, or a single unambiguous substring
621
- match) unlike `init_project` it never creates anything.
622
- - Returns a text summary (always) plus `structuredContent` with: totals
623
- (memories/links/distinct tags/chars), counts by kind, links by type, top tags,
624
- 12 weekly activity buckets (created vs updated), most-connected memories,
625
- orphan count, and freshest memory.
626
- - In MCP Apps hosts (see below) the result renders as an interactive dashboard
627
- snippet.
628
-
629
- ### `memory_graph`
630
-
631
- Returns a project's memory graph for visualization.
632
-
633
- Inputs:
634
-
635
- ```ts
636
- { project_name?: string }
637
- ```
638
-
639
- Behavior:
640
-
641
- - Text summary (node/link counts, top hubs) is always returned and points at
642
- `augment dashboard` for the full experience.
643
- - The compact node/edge payload (capped at the 300 most recently updated
644
- memories) is attached as `structuredContent` **only** when the client
645
- negotiated the MCP Apps extension or `AUGMENT_MCP_UI_EMBED=1` is set in a
646
- text-only host it would only burn model context.
647
-
648
- ## MCP Apps Dashboard Snippets (SEP-1865)
649
-
650
- The MCP server implements the [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps)
651
- (`io.modelcontextprotocol/ui`, spec version 2026-01-26):
652
-
653
- - Two UI templates are predeclared as resources with mime type
654
- `text/html;profile=mcp-app`: `ui://augment/insights.html` and
655
- `ui://augment/graph.html`. Both are fully self-contained HTML documents
656
- (inline CSS/JS, Cytoscape inlined from `node_modules` at read time) so they
657
- work offline under the extension's default CSP.
658
- - `memory_insights` / `memory_graph` reference their template via
659
- `_meta.ui.resourceUri`; UI-capable hosts render the tool result in a sandboxed
660
- iframe and stream data in over the spec's postMessage JSON-RPC
661
- (`ui/initialize` `ui/notifications/initialized`
662
- `ui/notifications/tool-result`). The snippets adapt to the host theme
663
- (`hostContext.theme` + host CSS variables), auto-resize via
664
- `ui/notifications/size-changed`, and the insights snippet can refresh itself
665
- through the host-proxied `tools/call`.
666
- - Hosts without the extension ignore the metadata entirely and get the text
667
- fallback the tools stay useful in text-only hosts like CLIs.
668
- - Classic MCP-UI hosts (embedded-block renderers that never negotiate the
669
- extension): set `AUGMENT_MCP_UI_EMBED=1` to append a self-contained
670
- `type: "resource"` HTML block (data inlined, `mimeType: text/html`) to tool
671
- results when and only when the client did not negotiate the extension.
672
-
673
- ## Configuration
674
-
675
- Resolution order:
676
-
677
- 1. Environment variables.
678
- 2. `~/.augment/config.json`.
679
- 3. Defaults.
680
-
681
- Environment variables:
682
-
683
- - `AUGMENT_MEMORY_ROOT`
684
- - `AUGMENT_STATE_DIR`
685
- - `AUGMENT_DAEMON_PORT`
686
- - `AUGMENT_GIT_AUTOCOMMIT` — default on; set `0`/`false`/`no`/`off` to disable the
687
- daemon's [git auto-commit](#git-auto-commit) of memory writes.
688
- - `AUGMENT_MCP_UI_EMBED` — set `1` to embed classic MCP-UI HTML blocks in
689
- `memory_insights`/`memory_graph` results for hosts that render embedded
690
- `ui://` resources but do not negotiate the MCP Apps extension.
691
-
692
- Defaults:
693
-
694
- - Memory root: `~/.augment/memories`
695
- - State directory: `~/.augment/state`
696
- - Database: `~/.augment/state/index.db`
697
- - Daemon discovery file: `~/.augment/state/daemon.json`
698
-
699
- ## Agent Integration Installer
700
-
701
- The `augment` CLI can install dogfooding integrations:
702
-
703
- ```powershell
704
- npm exec --yes --package @fingerskier/augment -- augment install codex --scope user --memory-root "C:\Users\you\Dropbox\augment-memories"
705
- npm exec --yes --package @fingerskier/augment -- augment install codex --scope repo
706
- npm exec --yes --package @fingerskier/augment -- augment install claude --scope repo
707
- npm exec --yes --package @fingerskier/augment -- augment install all --scope user --dry-run
708
- ```
709
-
710
- Codex install creates or updates:
711
-
712
- - A local plugin folder named `augment`.
713
- - `.codex-plugin/plugin.json`.
714
- - `.mcp.json` pointing to the published `@fingerskier/augment` package through
715
- an isolated npm `--prefix` directory.
716
- - `skills/augment-context/SKILL.md`, including the context, decoction, and dream
717
- workflows exposed through Codex's single packaged skill.
718
- - `hooks/hooks.json` wiring SessionStart / UserPromptSubmit /
719
- PreToolUse (`Edit|Write|Bash`) / Stop.
720
- - A personal or repo marketplace entry.
721
-
722
- Claude install creates or updates:
723
-
724
- - A real Claude Code plugin folder named `augment` with
725
- `.claude-plugin/plugin.json`, auto-discovered `augment-context`,
726
- `augment-sleep`, `augment-decoction`, and `augment-dream` skills, a bundled
727
- `.mcp.json` (same cwd-safe MCP command shape as Codex), and `hooks/hooks.json`
728
- (auto-discovered lifecycle hooks).
729
- - A `.claude-plugin/marketplace.json` entry so the plugin is installable via
730
- `/plugin marketplace add` + `/plugin install augment@<marketplace>`.
731
- - A direct MCP registration so the server is active immediately: repo scope writes
732
- `<repo>/.mcp.json`; user scope merges `mcpServers.augment` into `~/.claude.json`,
733
- preserving all other keys.
734
- - A best-effort plugin registration through Claude's own CLI — it shells out to
735
- `claude plugin marketplace add <root>` and `claude plugin install augment@<marketplace>`
736
- (mapping `--scope repo` to Claude's `project` scope). This uses Claude's official
737
- install path (cache + catalog) rather than hand-writing Claude's internal plugin
738
- state. It is skipped when `claude` is not on PATH, on `--dry-run`, or with
739
- `--no-plugin`, falling back to printing the manual `/plugin` commands.
740
- - A marked Augment block in `CLAUDE.md` carrying the always-on memory workflow.
741
-
742
- Both installers also provision the shared hook runtime once via
743
- `npm install --prefix ~/.augment/npm-exec @fingerskier/augment`, so hook commands
744
- run through a direct `node <entry>` invocation (tens of milliseconds) instead of
745
- an npm bootstrap on every event. If npm is unavailable at install time the
746
- installer prints the manual command; hooks fail open (silent no-ops) until it is
747
- run. This installer path is independent of the [Pi Package](#pi-package) manifest
748
- and remains the supported setup for Claude Code and Codex.
749
-
750
- ## Deferred
751
-
752
- - `sleep`/`dream` **automation** (scheduled passes, auto-approve, batch dreams)
753
- deferred until supervised proposals are consistently high-quality.
754
- - Memory `move`.
755
-
756
- Not planned:
757
-
758
- - Remote sync file sync (e.g. Dropbox) is the supported multi-machine story.
1
+ # Augment Features
2
+
3
+ Augment is a local RAG memory system for coding agents.
4
+
5
+ ## Memory Folder
6
+
7
+ - The memory folder is a normal directory.
8
+ - Only one memory root is configured per local system.
9
+ - Memory file paths are relative to this root.
10
+
11
+ ## Memories
12
+
13
+ - Memories are text files in the memory folder.
14
+ - Files are markdown with YAML frontmatter.
15
+ - Canonical organization:
16
+
17
+ ```txt
18
+ org/repo/kind/name.md
19
+ .generic/kind/name.md
20
+ ```
21
+
22
+ - Supported kinds:
23
+ - `ISSUE`
24
+ - `ARCH`
25
+ - `TODO`
26
+ - `SPEC`
27
+ - `WORK`
28
+
29
+ Memory files are the canonical source of truth. Numeric memory IDs are local
30
+ database IDs only and are not written to memory files. Relative paths are the
31
+ durable cross-system identity.
32
+
33
+ Example:
34
+
35
+ ```md
36
+ ---
37
+ kind: ARCH
38
+ project: fingerskier/augment
39
+ name: search-contract
40
+ tags: [mcp, search, ranking]
41
+ links:
42
+ - to: fingerskier/augment/SPEC/local-daemon.md
43
+ type: RELATED
44
+ created_at: 2026-06-29T00:00:00Z
45
+ updated_at: 2026-06-29T00:00:00Z
46
+ ---
47
+
48
+ Body text.
49
+ ```
50
+
51
+ Generic memories are ordinary memory files of any supported kind under the
52
+ reserved `.generic/` directory; glean output is restricted to durable SPEC or
53
+ ARCH records. The path is authoritative: `.generic/SPEC/retries.md` is generic
54
+ even if externally edited frontmatter says otherwise. Normal CRUD and an
55
+ explicit `project_name: ".generic"` work, but project inference never selects the
56
+ reserved pseudo-project and routine current-project search does not boost it as
57
+ an exact project match. Generic memories still participate in normal global
58
+ search alongside current- and foreign-project memories.
59
+
60
+ ## Database
61
+
62
+ - A shared local daemon watches memory files and maintains a rebuildable libsql
63
+ index.
64
+ - The database includes metadata, body text, embeddings, gzip density score, and
65
+ derived link rows.
66
+ - `Xenova/bge-small-en-v1.5` via `@huggingface/transformers` provides 384D
67
+ embeddings. The model revision is recorded as a tripwire constant
68
+ (`PINNED_MODEL_REVISION`) for reproducibility.
69
+ - Indexing is incremental: an external edit reindexes only the changed file, a
70
+ full rebuild skips unchanged files by mtime, and the daemon's own writes are
71
+ indexed inline (no watcher round-trip).
72
+ - The database file is rebuildable and should not be synced as canonical state.
73
+
74
+ Tables:
75
+
76
+ - `projects` — `id`, `name`, `org`, `repo`, `source`, `created_at`, `updated_at`.
77
+ - `memories` — `id`, `project_id`, `kind`, `name`, `relative_path`,
78
+ `content_hash`, `frontmatter_hash`, `size`, `density`, `mtime`, `tags_json`,
79
+ `links_json`, `body`, `created_at`, `updated_at`.
80
+ - `memory_embeddings` — `memory_id`, `model_id`, `model_version`, `dimensions`,
81
+ `vector_json`, `embedded_hash`, `embedded_at`.
82
+ - `links` — `id`, `from_memory_id`, `to_memory_id`, `type`, `created_at`
83
+ (unique on `from` + `to` + `type`).
84
+
85
+ Links are written to the source memory's frontmatter using target relative paths.
86
+ The daemon rebuilds local `links` rows from those declarations. A mutation
87
+ (`upsert`/`link`/`unlink`) repairs only the touched memory's link subgraph, so
88
+ link IDs survive *unrelated* mutations within a daemon run — but the touched
89
+ memory's own outbound link IDs are reassigned each time, and all IDs churn on a
90
+ full index rebuild. Relative paths remain the durable identity.
91
+
92
+ ## Daemon
93
+
94
+ - `augment-daemon` is shared by all local MCP servers for one memory root.
95
+ - The daemon owns file watching, embedding, and database writes.
96
+ - It exposes a localhost HTTP control endpoint.
97
+ - It binds to `127.0.0.1`, uses a dynamic port by default, writes a discovery
98
+ file, and serves all routes without auth (loopback-only; no token required).
99
+ - It starts serving immediately and builds the initial index in the background
100
+ (a cold corpus no longer blocks hooks or clients on the port);
101
+ `GET /index/status` reports `{ ok, ready, error? }`.
102
+ - Besides memory/link CRUD it serves `/health`, `/index/rebuild`, and the
103
+ dashboard UI.
104
+ - Memories can be deleted via the dashboard or `DELETE /memories/:id` (the file
105
+ and DB row are removed and inbound frontmatter links in other memories are
106
+ scrubbed). Ordinary delete is deliberately **not** exposed as an MCP tool;
107
+ `decoction_cleanup` is the narrowly scoped, explicitly approved exception.
108
+
109
+ ## Git auto-commit
110
+
111
+ When the memory root is itself a git repository, the daemon auto-commits
112
+ augment's own writes so the corpus carries its own version history — no manual
113
+ snapshotting required.
114
+
115
+ - **Enabled by default**; disable with `AUGMENT_GIT_AUTOCOMMIT=0` (also `false`,
116
+ `no`, `off`).
117
+ - **Daemon-side and debounced.** Only augment's own mutations (upsert, delete,
118
+ link, unlink) schedule a commit; a burst of writes coalesces into one snapshot
119
+ commit. External/editor/Dropbox edits are *not* committed.
120
+ - **Markdown only.** It stages `*.md` (`git add -A -- '*.md'`), so a nested state
121
+ dir or unrelated files are never swept in, and every memory mutation — including
122
+ deletes and link scrubs — is captured.
123
+ - **Root-repo only.** It engages only when the memory root is the git worktree
124
+ root, never when it merely sits inside a larger project repo.
125
+ - **Never pushes, always fails open.** Commits stay local; any git failure is
126
+ logged once and swallowed so a snapshot can never break a write. A fresh
127
+ `git init` with no configured identity still commits (a fallback
128
+ `Augment <augment@localhost>` identity is used only when none is set).
129
+ - The check runs **once at daemon startup**, so enabling the flag or `git init`-ing
130
+ the memory root takes effect on the next daemon restart.
131
+
132
+ ## Dashboard
133
+
134
+ A daemon-served single-page web UI for browsing and editing memories as a graph:
135
+
136
+ - Project graph drills into a per-project memory subgraph (nodes colored by
137
+ kind, edges labeled by link type).
138
+ - Ad hoc semantic search, memory create/edit/delete, link create/delete.
139
+ - Launched via `augment dashboard [--no-open]`; loopback-only; honors
140
+ `AUGMENT_DAEMON_PORT`.
141
+ - Fully self-contained assets (Cytoscape bundled from `node_modules`; no CDN).
142
+
143
+ ## CLI
144
+
145
+ Run without a clone via `npx -y @fingerskier/augment <command>`:
146
+
147
+ - `status` — print the resolved config (default command; `config` is an alias).
148
+ - `install <codex|claude|grok|all>` — wire agent integrations (see
149
+ [Agent Integration Installer](#agent-integration-installer)).
150
+ - `dashboard [--no-open]` — start the daemon and open the web UI.
151
+ - `recall "<query>" [--project <org/repo>] [--cwd <dir>] [--limit N]
152
+ [--max-chars N] [--min-score X]` — print the same context-injection text the
153
+ hooks use. No match prints the explicit abstention message ("No memory met
154
+ the relevance threshold …"); output is empty only on failure (daemon down,
155
+ blank query).
156
+ - `hook <session-start|user-prompt-submit|pre-tool-use|stop>` — run a lifecycle
157
+ hook over stdin JSON. Host-wired by `install`; rarely called directly.
158
+ - `help` — full usage.
159
+
160
+ ## Pi Package
161
+
162
+ The npm package is also a first-class Pi package (`keywords: ["pi-package"]` and
163
+ a `pi` manifest in `package.json`). `pi install npm:@fingerskier/augment` loads:
164
+
165
+ - `dist/pi/extension.js` — a Pi extension that registers namespaced
166
+ `augment_*` tools and slash commands.
167
+ - `integrations/pi/skills/augment-context/SKILL.md`,
168
+ `integrations/pi/skills/augment-decoction/SKILL.md`, and
169
+ `integrations/pi/skills/augment-dream/SKILL.md` — Pi-specific workflow guidance
170
+ using the `augment_*` tool names.
171
+
172
+ The Pi extension does not replace built-ins such as `read`; MCP `read` is exposed
173
+ as `augment_read_memory`. It lazily connects to the shared daemon from tools and
174
+ session events (no background resources start in the extension factory), warms
175
+ `init_project` on `session_start`, injects recalled task context on
176
+ `before_agent_start`, and reminds or follows up after non-trivial turns to
177
+ persist durable work.
178
+
179
+ Pi tools:
180
+
181
+ - `augment_init_project`, `augment_list_projects`
182
+ - `augment_search`, `augment_project_context`, `augment_read_memory`
183
+ - `augment_upsert`, `augment_link`, `augment_list_links`, `augment_unlink`
184
+ - `augment_decoction_glean`, `augment_decoction_cleanup`
185
+ - `augment_sleep_candidates`, `augment_sleep_propose`, `augment_sleep_proposals`,
186
+ `augment_sleep_apply`, `augment_sleep_reject`
187
+ - `augment_dream_propose`, `augment_dream_proposals`, `augment_dream_apply`,
188
+ `augment_dream_reject`
189
+ - `augment_memory_insights`, `augment_memory_graph`
190
+
191
+ Pi commands:
192
+
193
+ - `/augment-context [query]`
194
+ - `/augment-persist [summary]`
195
+ - `/augment-dashboard [--no-open]`
196
+ - `/augment-sleep`
197
+ - `/augment-dream`
198
+
199
+ Pi-specific environment variables:
200
+
201
+ - `AUGMENT_PI_AUTO_CONTEXT=inject|reminder|off` (default `inject`).
202
+ - `AUGMENT_PI_AUTO_PERSIST=reminder|followup|off` (default `reminder`).
203
+ - `AUGMENT_PI_CONTEXT_LIMIT` (default `5`).
204
+ - `AUGMENT_PI_CONTEXT_MAX_CHARS` (default `12000`).
205
+
206
+ Pi and MCP expose the same sleep, decoction, and dream lifecycle operations;
207
+ Claude/Codex skills supply the agent-side synthesis and approval guidance. The
208
+ CLI and lifecycle-hook behavior is unchanged.
209
+
210
+ ## Lifecycle Hooks
211
+
212
+ Installed Claude, Codex, and Grok integrations wire the same lifecycle hooks
213
+ (Claude Code, Codex, and Grok Build share the event names; Grok also accepts
214
+ Claude tool-name aliases in matchers and camelCase payload fields). Every
215
+ handler **fails open** — any error yields empty output and exit 0, so a broken
216
+ hook can never break the host agent.
217
+
218
+ - `SessionStart` — warms the daemon and registers the project.
219
+ - `UserPromptSubmit` recalls memory for the prompt and injects it as
220
+ `additionalContext` before the model sees the prompt.
221
+ - `PreToolUse` (matcher `Edit|Write|Bash`) recalls additional memory keyed to
222
+ the tool action (the edited file / the Bash command). Uses a raised relevance
223
+ floor (0.45, calibrated on the real model tool queries are command/path
224
+ shaped, not prose) and injects each distinct query at most once per session.
225
+ Injection-only: never blocks, gates, or rewrites a tool call.
226
+ - `Stop` — blocks the turn once with a directive to upsert a memory, then allows
227
+ the stop (loop-guarded per turn).
228
+
229
+ Installed hook commands invoke the install-time-provisioned runtime directly
230
+ (`node <prefix>/node_modules/@fingerskier/augment/dist/bin/augment.js hook
231
+ <event>`) — no npm bootstrap on the hot path.
232
+
233
+ The verification process for the whole flow is
234
+ [docs/verify-memory-flow.md](verify-memory-flow.md).
235
+
236
+ ## Recall Log
237
+
238
+ Every `/memories/search` appends one JSON line to `<stateDir>/recall/events.jsonl`
239
+ recording what recall actually returned: `ts`, `surface`, `project`, `query`,
240
+ `abstained`, `result_count`, `top_score`, and `paths`. It is the passive
241
+ instrument that caught the 2026-07-10 memoryRoot split-brain (six days of
242
+ empty-corpus recalls that abstained silently).
243
+
244
+ - **Passive and human-rating-free.** Search records events without asking users
245
+ to rate individual results.
246
+ - **Best-effort by design.** A failed append never fails the search that
247
+ triggered it.
248
+ - **Single-slot rotation.** When the file exceeds `RECALL_LOG_MAX_BYTES` (5 MB)
249
+ it is rotated to `events.jsonl.1` before the next append — the log is
250
+ diagnostic, not a record of account.
251
+
252
+ ## MCP Tools
253
+
254
+ ### `init_project`
255
+
256
+ Infers or accepts a project name and upserts a project record.
257
+
258
+ Inputs:
259
+
260
+ ```ts
261
+ { project_name?: string }
262
+ ```
263
+
264
+ ### `list_projects`
265
+
266
+ Lists known project records.
267
+
268
+ Inputs:
269
+
270
+ ```ts
271
+ { name?: string }
272
+ ```
273
+
274
+ ### `search`
275
+
276
+ Recalls memories semantically and lexically similar to a query.
277
+
278
+ Inputs:
279
+
280
+ ```ts
281
+ {
282
+ project_name?: string;
283
+ query: string;
284
+ limit?: number; // default 5, max 20
285
+ max_chars?: number; // default 12000, max 50000
286
+ kinds?: Array<"ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK">;
287
+ include_linked?: boolean;
288
+ min_score?: number; // 0..1 relevance floor; default 0.4, 0 disables
289
+ }
290
+ ```
291
+
292
+ Behavior:
293
+
294
+ - Returns plain text suitable for direct context injection.
295
+ - Includes local memory IDs, project names, paths, kinds, scores, and link
296
+ annotations.
297
+ - May use the CWD project as a modest metadata boost, but cross-project results
298
+ are allowed based on score.
299
+ - Labels the provenance of each result relative to the querying project: a memory
300
+ from another repo in the same org is marked `provenance:foreign-cross-repo`, and
301
+ one from another org `provenance:foreign-cross-org`. The shared memory store is
302
+ multi-author, so cross-project recall is also cross-author the marker lets the
303
+ consuming agent discount memory it did not author (a relevance floor alone can't
304
+ stop a genuinely-relevant foreign memory).
305
+ - Prioritizes linked memories without requiring them.
306
+ - **Down-weights archived memories** (a WORK source consolidated by a `sleep`
307
+ pass) rather than hiding them: their blended score is multiplied by
308
+ `ARCHIVED_SEARCH_WEIGHT` (0.5, after the blend and before the floor), so the
309
+ consolidated record outranks its sources while the sources stay auditable.
310
+ `read` still returns an archived memory's body verbatim.
311
+ - Applies a minimum relevance threshold (`min_score`, default
312
+ `DEFAULT_SEARCH_MIN_SCORE` = 0.4) and **abstains** when nothing clears it
313
+ returning no results and a "nothing injected" message rather than surfacing an
314
+ unrelated memory. The floor is calibrated against the real embedding model:
315
+ after the empirically-anchored cosine rescale (`SEMANTIC_COSINE_BASELINE`
316
+ 0.33), an unrelated memory blends to ~0.12 while an on-topic one lands ~0.60,
317
+ so 0.4 separates abstention from recall with margin. Pass `min_score: 0` to
318
+ disable the floor (never abstain), or raise it to demand a stronger match.
319
+ - Packs results under a fair-share character budget: each result may use an even
320
+ split of the remaining `max_chars`, with unused share rolling forward; an
321
+ oversized body is head-truncated with a visible `[truncated]` marker rather
322
+ than omitted, and a result is skipped only when fewer than 80 usable characters
323
+ remain. Bodies are whole-file prefixes — never summarized.
324
+
325
+ ### `upsert`
326
+
327
+ Stores text in a memory file.
328
+
329
+ Inputs:
330
+
331
+ ```ts
332
+ {
333
+ project_id: number;
334
+ memory_id?: number;
335
+ kind?: "ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK";
336
+ name: string;
337
+ content: string;
338
+ tags?: string[];
339
+ }
340
+ ```
341
+
342
+ If `memory_id` is absent, Augment may automatically update a highly similar
343
+ memory in the same project and kind but only when the new content subsumes the
344
+ existing one (every distinct term of the prior body survives in the new content),
345
+ so the in-place update is a lossless refresh. If the new content instead
346
+ contradicts or omits something the prior memory held, Augment preserves the prior
347
+ memory intact and stores the new content as its own memory rather than silently
348
+ overwriting history.
349
+
350
+ Content is capped at 12,000 characters; an oversized upsert is rejected — split
351
+ the note instead.
352
+
353
+ ### `read`
354
+
355
+ Reads one memory by local numeric ID.
356
+
357
+ Inputs:
358
+
359
+ ```ts
360
+ { id: number }
361
+ ```
362
+
363
+ ### `link`
364
+
365
+ Creates a directional link between memories and persists it as a relative-path
366
+ link in the source memory frontmatter.
367
+
368
+ Inputs:
369
+
370
+ ```ts
371
+ {
372
+ from_memory_id: number | string;
373
+ to_memory_id: number | string;
374
+ type?: "DEPENDS_ON" | "BLOCKS" | "IMPLEMENTS" | "PARENT" | "RELATED";
375
+ }
376
+ ```
377
+
378
+ Each reference may be a local numeric ID **or** a relative path
379
+ (`org/repo/KIND/name.md`). Paths are the durable handle they survive index
380
+ rebuilds, while numeric IDs churn. An all-digit string is interpreted as a
381
+ numeric ID.
382
+
383
+ ### `list_links`
384
+
385
+ Lists inbound and outbound links involving a memory.
386
+
387
+ Inputs:
388
+
389
+ ```ts
390
+ { memory_id: number }
391
+ ```
392
+
393
+ ### `unlink`
394
+
395
+ Removes a link by local link ID.
396
+
397
+ Inputs:
398
+
399
+ ```ts
400
+ { id: number }
401
+ ```
402
+
403
+ ### `decoction_glean`
404
+
405
+ Discovers recurring cross-project evidence or writes an agent-authored generic
406
+ memory. It is separate from sleep and performs no LLM synthesis itself.
407
+
408
+ Inputs:
409
+
410
+ ```ts
411
+ { action: "discover"; min_cosine?: number; limit?: number }
412
+
413
+ // or
414
+ {
415
+ action: "write";
416
+ kind: "SPEC" | "ARCH";
417
+ name: string;
418
+ content: string;
419
+ tags?: string[];
420
+ derived_from: string[];
421
+ suggested_removals?: Array<{ path: string; reason: string }>;
422
+ expected_content_hash?: string;
423
+ expected_frontmatter_hash?: string;
424
+ }
425
+ ```
426
+
427
+ Discovery uses the existing memory embeddings and complete-link clustering:
428
+ every pair in a cluster must meet `min_cosine` (default `0.75`), and a result
429
+ must span at least four distinct projects. Multiple memories from one project
430
+ count once; `local/*` projects count normally. Existing generics, archived
431
+ memories, and sources tagged `private` or `no-generalize` are excluded; there is
432
+ no age gate. Eligible evidence kinds are WORK, ISSUE, SPEC, and ARCH.
433
+
434
+ Write stores a normal `.generic/<KIND>/<name>.md` memory with `derived_from`
435
+ provenance. Those unique sources must satisfy the same eligibility rules and
436
+ span at least four projects. Removal suggestions and credential-shaped-content
437
+ warnings are returned to the agent but are not persisted as lifecycle metadata.
438
+ Warnings do not block the write. Creating a generic omits expected hashes;
439
+ updating one requires both current hashes so a stale glean cannot overwrite a
440
+ newer edit.
441
+
442
+ ### `decoction_cleanup`
443
+
444
+ Hard-deletes an explicitly approved set of originals after retargeting their
445
+ typed inbound links to one generic memory.
446
+
447
+ Inputs:
448
+
449
+ ```ts
450
+ { generic_path: string; source_paths: string[] }
451
+ ```
452
+
453
+ The whole request is prevalidated before deletion: the target must be generic,
454
+ every source must exist, and no source may itself be generic. Cleanup then
455
+ returns one result per source. There is no journal or rollback; a runtime failure
456
+ does not undo sources already processed. The generic keeps its `derived_from`
457
+ paths as historical provenance.
458
+
459
+ ### `sleep_candidates`
460
+
461
+ READ-ONLY preview of sleep consolidation. Clusters settled WORK memories
462
+ (default: older than 3 days by `updated_at`) within each project into candidate
463
+ groups a `sleep` pass distills into SPEC/ARCH records via `sleep_propose` →
464
+ user approval → `sleep_apply`.
465
+
466
+ - Edges: existing links of any type, or raw cosine >= `min_cosine`
467
+ (default 0.75 semantic-only, deliberately above the blended recall floor;
468
+ see `SLEEP_MIN_COSINE` in `src/constants.ts`).
469
+ - Clusters never span projects; archived memories are excluded from candidacy.
470
+ Output reports durable `relative_path`s.
471
+ - Input: optional `project_name` (inferred from cwd otherwise), `min_cosine`,
472
+ `min_age_days`, `limit` (default 20, `SLEEP_MAX_CLUSTERS`).
473
+ - Mutates nothing.
474
+
475
+ ### `sleep_propose`
476
+
477
+ Draft a sleep consolidation: fold ≥2 settled WORK memories into one new SPEC or
478
+ ARCH record. Writes **only** a proposal file outside the corpus (under
479
+ `<stateDir>/sleeps/`), for user review — the corpus is untouched until the user
480
+ approves and `sleep_apply` runs.
481
+
482
+ Inputs:
483
+
484
+ ```ts
485
+ {
486
+ project_name?: string; // inferred from cwd otherwise
487
+ kind: "SPEC" | "ARCH";
488
+ name: string;
489
+ content: string;
490
+ derived_from: string[]; // >=2 WORK relative paths, all in project_name
491
+ rationale?: string;
492
+ }
493
+ ```
494
+
495
+ Validation (shared by propose, re-checked at apply since drafts sit while the
496
+ corpus moves): every `derived_from` path resolves in the corpus, all are kind
497
+ `WORK`, all belong to `project_name` (single-project constraint), none archived,
498
+ `derived_from.length >= 2`, and the target path
499
+ `<project>/<kind>/<name>.md` must not already exist. The proposal body is
500
+ user-editable on disk before approval.
501
+
502
+ ### `sleep_proposals`
503
+
504
+ Lists sleep proposals drafted by `sleep_propose`, optionally filtered by status.
505
+
506
+ Inputs:
507
+
508
+ ```ts
509
+ { status?: "proposed" | "applied" | "rejected" }
510
+ ```
511
+
512
+ ### `sleep_apply`
513
+
514
+ Applies a sleep proposal by filename. Requires explicit user approval of the
515
+ named proposal and is the **only** corpus write in the sleep flow: it re-reads
516
+ the proposal fresh from disk, re-validates, upserts the consolidated SPEC/ARCH
517
+ (with `derived_from` provenance), archives each WORK source in place
518
+ (`archived: true` + `consolidated_into:`, body byte-untouched), and marks the
519
+ proposal `applied`. The daemon route lands the whole pass as one revertible
520
+ `sleep:` git commit on the memory root.
521
+
522
+ Inputs:
523
+
524
+ ```ts
525
+ { filename: string }
526
+ ```
527
+
528
+ ### `sleep_reject`
529
+
530
+ Rejects a pending sleep proposal by filename. Mutates only the proposal file
531
+ (outside the corpus); the corpus is untouched.
532
+
533
+ Inputs:
534
+
535
+ ```ts
536
+ { filename: string }
537
+ ```
538
+
539
+ ### `dream_propose`
540
+
541
+ Writes a user-reviewable speculative memory or link proposal under
542
+ `<stateDir>/dreams/`; it does not mutate the corpus. Agents gather inspiration
543
+ through normal global search, which prioritizes the current project while still
544
+ returning generic and foreign-project memories.
545
+
546
+ Inputs:
547
+
548
+ ```ts
549
+ {
550
+ project_name?: string; // defaults to cwd inference; must be a real project
551
+ kind: "ISSUE" | "ARCH" | "TODO" | "SPEC" | "WORK";
552
+ name: string;
553
+ content: string;
554
+ derived_from: string[]; // >=1 current, generic, or foreign memory
555
+ rationale?: string;
556
+ }
557
+
558
+ // or
559
+ {
560
+ project_name?: string; // defaults to cwd inference; must be a real project
561
+ link: {
562
+ from: string;
563
+ to: string;
564
+ type: "DEPENDS_ON" | "BLOCKS" | "IMPLEMENTS" | "PARENT" | "RELATED";
565
+ };
566
+ rationale?: string;
567
+ }
568
+ ```
569
+
570
+ A dream memory is created in the inferred or explicit current real project and
571
+ may be inspired entirely by generic or foreign memories. `.generic` cannot be
572
+ the active dream project. A dream link's source must belong to the current
573
+ project; its target may belong to any project. The draft remains editable until
574
+ apply.
575
+
576
+ ### `dream_proposals`
577
+
578
+ Lists both dream-memory and dream-link proposals, optionally filtered by status.
579
+
580
+ Inputs:
581
+
582
+ ```ts
583
+ { status?: "proposed" | "applied" | "rejected" }
584
+ ```
585
+
586
+ ### `dream_apply`
587
+
588
+ Re-reads and revalidates one explicitly approved proposal. A dream-memory apply
589
+ creates the reviewed record with the `dream` tag and `derived_from` provenance;
590
+ a dream-link apply creates exactly the reviewed link. The daemon records the
591
+ corpus mutation as a `dream:` git commit when git auto-commit is available.
592
+
593
+ Inputs:
594
+
595
+ ```ts
596
+ { filename: string }
597
+ ```
598
+
599
+ ### `dream_reject`
600
+
601
+ Rejects a pending dream proposal without changing the corpus.
602
+
603
+ Inputs:
604
+
605
+ ```ts
606
+ { filename: string }
607
+ ```
608
+
609
+ ### `memory_insights`
610
+
611
+ Aggregates a project's memory graph into dashboard insights.
612
+
613
+ Inputs:
614
+
615
+ ```ts
616
+ { project_name?: string }
617
+ ```
618
+
619
+ Behavior:
620
+
621
+ - Resolves the project strictly (exact name, or a single unambiguous substring
622
+ match) unlike `init_project` it never creates anything.
623
+ - Returns a text summary (always) plus `structuredContent` with: totals
624
+ (memories/links/distinct tags/chars), counts by kind, links by type, top tags,
625
+ 12 weekly activity buckets (created vs updated), most-connected memories,
626
+ orphan count, and freshest memory.
627
+ - In MCP Apps hosts (see below) the result renders as an interactive dashboard
628
+ snippet.
629
+
630
+ ### `memory_graph`
631
+
632
+ Returns a project's memory graph for visualization.
633
+
634
+ Inputs:
635
+
636
+ ```ts
637
+ { project_name?: string }
638
+ ```
639
+
640
+ Behavior:
641
+
642
+ - Text summary (node/link counts, top hubs) is always returned and points at
643
+ `augment dashboard` for the full experience.
644
+ - The compact node/edge payload (capped at the 300 most recently updated
645
+ memories) is attached as `structuredContent` **only** when the client
646
+ negotiated the MCP Apps extension or `AUGMENT_MCP_UI_EMBED=1` is set — in a
647
+ text-only host it would only burn model context.
648
+
649
+ ## MCP Apps Dashboard Snippets (SEP-1865)
650
+
651
+ The MCP server implements the [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps)
652
+ (`io.modelcontextprotocol/ui`, spec version 2026-01-26):
653
+
654
+ - Two UI templates are predeclared as resources with mime type
655
+ `text/html;profile=mcp-app`: `ui://augment/insights.html` and
656
+ `ui://augment/graph.html`. Both are fully self-contained HTML documents
657
+ (inline CSS/JS, Cytoscape inlined from `node_modules` at read time) so they
658
+ work offline under the extension's default CSP.
659
+ - `memory_insights` / `memory_graph` reference their template via
660
+ `_meta.ui.resourceUri`; UI-capable hosts render the tool result in a sandboxed
661
+ iframe and stream data in over the spec's postMessage JSON-RPC
662
+ (`ui/initialize` → `ui/notifications/initialized`
663
+ `ui/notifications/tool-result`). The snippets adapt to the host theme
664
+ (`hostContext.theme` + host CSS variables), auto-resize via
665
+ `ui/notifications/size-changed`, and the insights snippet can refresh itself
666
+ through the host-proxied `tools/call`.
667
+ - Hosts without the extension ignore the metadata entirely and get the text
668
+ fallback the tools stay useful in text-only hosts like CLIs.
669
+ - Classic MCP-UI hosts (embedded-block renderers that never negotiate the
670
+ extension): set `AUGMENT_MCP_UI_EMBED=1` to append a self-contained
671
+ `type: "resource"` HTML block (data inlined, `mimeType: text/html`) to tool
672
+ results when — and only when — the client did not negotiate the extension.
673
+
674
+ ## Configuration
675
+
676
+ Resolution order:
677
+
678
+ 1. Environment variables.
679
+ 2. `~/.augment/config.json`.
680
+ 3. Defaults.
681
+
682
+ Environment variables:
683
+
684
+ - `AUGMENT_MEMORY_ROOT`
685
+ - `AUGMENT_STATE_DIR`
686
+ - `AUGMENT_DAEMON_PORT`
687
+ - `AUGMENT_GIT_AUTOCOMMIT` default on; set `0`/`false`/`no`/`off` to disable the
688
+ daemon's [git auto-commit](#git-auto-commit) of memory writes.
689
+ - `AUGMENT_MCP_UI_EMBED` set `1` to embed classic MCP-UI HTML blocks in
690
+ `memory_insights`/`memory_graph` results for hosts that render embedded
691
+ `ui://` resources but do not negotiate the MCP Apps extension.
692
+
693
+ Defaults:
694
+
695
+ - Memory root: `~/.augment/memories`
696
+ - State directory: `~/.augment/state`
697
+ - Database: `~/.augment/state/index.db`
698
+ - Daemon discovery file: `~/.augment/state/daemon.json`
699
+
700
+ ## Agent Integration Installer
701
+
702
+ The `augment` CLI can install dogfooding integrations:
703
+
704
+ ```powershell
705
+ npm exec --yes --package @fingerskier/augment -- augment install codex --scope user --memory-root "C:\Users\you\Dropbox\augment-memories"
706
+ npm exec --yes --package @fingerskier/augment -- augment install codex --scope repo
707
+ npm exec --yes --package @fingerskier/augment -- augment install claude --scope repo
708
+ npm exec --yes --package @fingerskier/augment -- augment install grok --scope user --memory-root "C:\Users\you\Dropbox\augment-memories"
709
+ npm exec --yes --package @fingerskier/augment -- augment install all --scope user --dry-run
710
+ ```
711
+
712
+ Grok Build install creates or updates:
713
+
714
+ - `[mcp_servers.augment]` in `~/.grok/config.toml` (user) or
715
+ `<repo>/.grok/config.toml` (repo), preserving unrelated TOML keys.
716
+ - Skills under `~/.grok/skills/` or `<repo>/.grok/skills/` (context, sleep,
717
+ decoction, dream same skill bodies as Claude).
718
+ - Lifecycle hooks at `~/.grok/hooks/augment.json` or
719
+ `<repo>/.grok/hooks/augment.json`.
720
+ - A marked Augment memory-workflow block in `~/.grok/AGENTS.md` (user) or
721
+ `<repo>/AGENTS.md` (repo).
722
+
723
+ Codex install creates or updates:
724
+
725
+ - A local plugin folder named `augment`.
726
+ - `.codex-plugin/plugin.json`.
727
+ - `.mcp.json` pointing to the published `@fingerskier/augment` package through
728
+ an isolated npm `--prefix` directory.
729
+ - `skills/augment-context/SKILL.md`, including the context, decoction, and dream
730
+ workflows exposed through Codex's single packaged skill.
731
+ - `hooks/hooks.json` wiring SessionStart / UserPromptSubmit /
732
+ PreToolUse (`Edit|Write|Bash`) / Stop.
733
+ - A personal or repo marketplace entry.
734
+
735
+ Claude install creates or updates:
736
+
737
+ - A real Claude Code plugin folder named `augment` with
738
+ `.claude-plugin/plugin.json`, auto-discovered `augment-context`,
739
+ `augment-sleep`, `augment-decoction`, and `augment-dream` skills, a bundled
740
+ `.mcp.json` (same cwd-safe MCP command shape as Codex), and `hooks/hooks.json`
741
+ (auto-discovered lifecycle hooks).
742
+ - A `.claude-plugin/marketplace.json` entry so the plugin is installable via
743
+ `/plugin marketplace add` + `/plugin install augment@<marketplace>`.
744
+ - A direct MCP registration so the server is active immediately: repo scope writes
745
+ `<repo>/.mcp.json`; user scope merges `mcpServers.augment` into `~/.claude.json`,
746
+ preserving all other keys.
747
+ - A best-effort plugin registration through Claude's own CLI it shells out to
748
+ `claude plugin marketplace add <root>` and `claude plugin install augment@<marketplace>`
749
+ (mapping `--scope repo` to Claude's `project` scope). This uses Claude's official
750
+ install path (cache + catalog) rather than hand-writing Claude's internal plugin
751
+ state. It is skipped when `claude` is not on PATH, on `--dry-run`, or with
752
+ `--no-plugin`, falling back to printing the manual `/plugin` commands.
753
+ - A marked Augment block in `CLAUDE.md` carrying the always-on memory workflow.
754
+
755
+ Both installers also provision the shared hook runtime once via
756
+ `npm install --prefix ~/.augment/npm-exec @fingerskier/augment`, so hook commands
757
+ run through a direct `node <entry>` invocation (tens of milliseconds) instead of
758
+ an npm bootstrap on every event. If npm is unavailable at install time the
759
+ installer prints the manual command; hooks fail open (silent no-ops) until it is
760
+ run. This installer path is independent of the [Pi Package](#pi-package) manifest
761
+ and remains the supported setup for Claude Code and Codex.
762
+
763
+ ## Deferred
764
+
765
+ - `sleep`/`dream` **automation** (scheduled passes, auto-approve, batch dreams)
766
+ — deferred until supervised proposals are consistently high-quality.
767
+ - Memory `move`.
768
+
769
+ Not planned:
770
+
771
+ - Remote sync — file sync (e.g. Dropbox) is the supported multi-machine story.