mlx-bun 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -20
- package/docs/design/batching-perf-path.md +232 -0
- package/docs/design/batching-v2-plan.md +515 -0
- package/docs/design/bucketing-stage.md +196 -0
- package/docs/design/compat-cli-surface-design.md +11 -11
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dreaming-nightly-pipeline.md +291 -0
- package/docs/design/dspark-speculative-decoding.md +106 -0
- package/docs/design/generic-model-support.md +381 -0
- package/docs/design/memory-inference-path.md +422 -0
- package/docs/design/memory-synthesis.md +287 -0
- package/docs/design/minicpm5-decode-megakernel.md +484 -0
- package/docs/design/mlx-lm-tool-parity-plan.md +535 -0
- package/docs/design/omlx-adoption-map.md +90 -0
- package/docs/design/orpo-dynamic-lambda.md +41 -0
- package/docs/design/orpo-training.md +35 -5
- package/docs/design/parallel-slots.md +12 -1
- package/docs/design/parity-tier-dag.md +13 -5
- package/docs/design/segmented-backward-training.md +15 -0
- package/docs/design/spec-decode-larger-targets.md +229 -0
- package/docs/design/ssd-kv-cold-tier.md +158 -0
- package/docs/design/tauri-desktop-app.md +2 -2
- package/docs/design/the-dreaming-handoff.md +141 -0
- package/docs/design/the-dreaming-master-plan.md +446 -0
- package/docs/design/write-pipeline-entity.md +468 -0
- package/docs/investigations/curve-bisector-routing.md +1 -1
- package/docs/investigations/decode-roofline-lookagain.md +348 -0
- package/docs/investigations/dspark-handoff.md +58 -0
- package/docs/investigations/kernel-perf-review-2026-07.md +171 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -2
- package/docs/planning/curve-sampler-research-plan.md +331 -0
- package/docs/planning/memory-docs-and-dag-plan.md +185 -0
- package/docs/planning/pi-integration-review.md +178 -0
- package/docs/planning/release-notes-v0.0.10.md +57 -0
- package/docs/planning/release-notes-v0.0.9.md +122 -0
- package/docs/planning/web-ui-pass-plan.md +213 -0
- package/docs/planning/website-readme-pass-plan.md +224 -0
- package/docs/reference/cli.md +255 -0
- package/docs/reference/embedding.md +7 -2
- package/docs/reference/library-api.md +22 -3
- package/docs/reference/memory.md +5 -5
- package/docs/reference/models.md +137 -0
- package/docs/reference/orpo-quickstart.md +6 -0
- package/docs/reference/server-api.md +187 -9
- package/docs/reference/server-config.md +43 -9
- package/docs/reference/training.md +31 -12
- package/package.json +1 -1
- package/src/anthropic.ts +22 -0
- package/src/assets/curve-designer.html +1 -1
- package/src/chat-template.ts +25 -7
- package/src/cli.ts +1077 -90
- package/src/config.ts +4 -1
- package/src/download.ts +99 -8
- package/src/embed.ts +77 -0
- package/src/eval/perplexity.ts +164 -0
- package/src/eval/runner.ts +15 -6
- package/src/eval/tasks/bfcl.ts +1 -1
- package/src/generate.ts +149 -18
- package/src/harness-pi.ts +43 -17
- package/src/index.ts +2 -0
- package/src/kv-store.ts +240 -98
- package/src/lora.ts +2 -2
- package/src/memory/article.ts +558 -0
- package/src/memory/chunk-validation.ts +150 -0
- package/src/memory/chunk.ts +305 -12
- package/src/memory/cluster.ts +344 -17
- package/src/memory/coverage.ts +134 -0
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +184 -45
- package/src/memory/entity.ts +203 -0
- package/src/memory/gate.ts +187 -0
- package/src/memory/history.ts +152 -0
- package/src/memory/ingest.ts +324 -11
- package/src/memory/model.ts +321 -0
- package/src/memory/normalize.ts +671 -0
- package/src/memory/parse.ts +22 -0
- package/src/memory/pipeline.ts +242 -30
- package/src/memory/prompts.ts +42 -0
- package/src/memory/query.ts +334 -0
- package/src/memory/reconcile.ts +734 -0
- package/src/memory/redirect.ts +108 -0
- package/src/memory/reindex.ts +325 -0
- package/src/memory/resolve.ts +307 -0
- package/src/memory/route.ts +272 -0
- package/src/memory/schedule.ts +6 -4
- package/src/memory/stages.ts +774 -0
- package/src/memory/synthesize.ts +1629 -20
- package/src/memory/tools.ts +446 -96
- package/src/memory/vault.ts +462 -35
- package/src/memory/wikify.ts +1057 -16
- package/src/mlx/array.ts +21 -0
- package/src/mlx/ffi.ts +3 -0
- package/src/mlx/ops.ts +72 -0
- package/src/model/compiled-decode.ts +43 -8
- package/src/model/factory.ts +29 -8
- package/src/model/flash-attention.ts +4 -2
- package/src/model/fused-decode-kernel.ts +14 -7
- package/src/model/fused-mlp-kernel.ts +169 -0
- package/src/model/fused-swiglu-kernel.ts +240 -0
- package/src/model/gemma4-base.ts +96 -7
- package/src/model/gemma4.ts +33 -2
- package/src/model/minicpm5.ts +106 -8
- package/src/model/qwen3-delta.ts +48 -1
- package/src/model/qwen3.ts +276 -0
- package/src/model/qwen3_5.ts +11 -2
- package/src/model/steel-linear-kernel.ts +96 -0
- package/src/model/support.ts +38 -8
- package/src/model/universal/archs.ts +332 -0
- package/src/model/universal/dense.ts +576 -0
- package/src/model/universal/modules.ts +163 -0
- package/src/model/universal/rope.ts +366 -0
- package/src/pi-provider.ts +1 -1
- package/src/pi-terminal.ts +29 -8
- package/src/pi-web.ts +19 -2
- package/src/prompt-cache.ts +55 -9
- package/src/quantize/config-writer.ts +1 -1
- package/src/registry.ts +219 -8
- package/src/responses.ts +23 -0
- package/src/sampler.ts +220 -9
- package/src/serve/batch-scheduler.ts +307 -83
- package/src/serve/generation-gateway.ts +156 -29
- package/src/server.ts +746 -73
- package/src/spec/drafter.ts +81 -49
- package/src/spec/dspark/data-dflash.ts +156 -0
- package/src/spec/dspark/data.ts +201 -0
- package/src/spec/dspark/generate-dflash.ts +193 -0
- package/src/spec/dspark/generate.ts +290 -0
- package/src/spec/dspark/loss.ts +213 -0
- package/src/spec/dspark/module-dflash.ts +361 -0
- package/src/spec/dspark/module.ts +540 -0
- package/src/spec/dspark/sample.ts +112 -0
- package/src/spec/generate.ts +40 -19
- package/src/ssd-cache.ts +213 -0
- package/src/status-page.html +1 -1
- package/src/tokenizer.ts +7 -0
- package/src/train/flash-cce.ts +81 -23
- package/src/train/fuse.ts +243 -0
- package/src/train/index.ts +3 -0
- package/src/train/job.ts +8 -0
- package/src/train/loss.ts +341 -40
- package/src/train/prefix-shared.ts +62 -11
- package/src/train/segmented.ts +215 -55
- package/src/train/trainer.ts +112 -38
- package/src/web/skills/memory/SKILL.md +40 -17
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Memory synthesis — the local Morpheus (M1 design)
|
|
2
|
+
|
|
3
|
+
> **SUPERSEDED (2026-07-01)** by
|
|
4
|
+
> [dreaming-nightly-pipeline.md](./dreaming-nightly-pipeline.md). Kept for
|
|
5
|
+
> history. Known-dead parts: embedding-based section-routing and silhouette
|
|
6
|
+
> signals (**no embeddings anywhere in the project**), bucket-as-optional
|
|
7
|
+
> framing, and the periodic-only wikify (RECONCILE/LINK/infobox are nightly
|
|
8
|
+
> stages now).
|
|
9
|
+
|
|
10
|
+
Status: **design**, 2026-06-26. Companion to [memory-system.md](./memory-system.md)
|
|
11
|
+
(the M0 substrate: vault, read tools, CLI, scheduling — all landed). This doc is
|
|
12
|
+
the M1 design for the **write side**: the synthesis pipeline that turns raw
|
|
13
|
+
conversations into well-formed wiki articles, **on local models**.
|
|
14
|
+
|
|
15
|
+
The inspiration and proof-of-concept is Lucien / The Dreaming / Morpheus
|
|
16
|
+
(`../lucien`) — it works, but every stage runs on a cloud model (`claude --model
|
|
17
|
+
opus`, `pi`). The whole point of M1 is to keep every learning from Lucien and
|
|
18
|
+
**solve the cost by running the pipeline locally**, using one local base model +
|
|
19
|
+
a per-stage LoRA adapter trained from Lucien's corpus (the e4b chunk adapter is
|
|
20
|
+
the first of these — designed components of the appliance, each distilled from
|
|
21
|
+
the cloud pipeline's gold output).
|
|
22
|
+
|
|
23
|
+
Guiding principle, inherited verbatim from Lucien: **do whatever Wikipedia does.**
|
|
24
|
+
Wikipedia turned a crowd of strangers into the largest organized, continuously-
|
|
25
|
+
updated knowledge base ever built. We are not going to out-design it — we copy
|
|
26
|
+
its conventions (articles, sections, talk pages, citations, wikilinks, edit
|
|
27
|
+
history) and supply the per-edit labor with local models instead of volunteers.
|
|
28
|
+
|
|
29
|
+
And the division of labor is fixed: **AI does the judgment; deterministic code
|
|
30
|
+
enforces the invariants we can't trust AI on** (footnote bijection, wikilink
|
|
31
|
+
canonicalization, the conservative write gate).
|
|
32
|
+
|
|
33
|
+
## Current state: ZERO articles
|
|
34
|
+
|
|
35
|
+
The vault starts empty. So the pipeline has to handle the **creation flow**, not
|
|
36
|
+
just steady-state updates — most of the early design discussion assumed an
|
|
37
|
+
existing structured article to patch; from zero there is nothing to patch yet.
|
|
38
|
+
The two flows are genuinely different operations and the doc treats them
|
|
39
|
+
separately below.
|
|
40
|
+
|
|
41
|
+
## The pipeline (DAG)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
WRITE · the local Morpheus (what `mlx-bun memory synthesize` runs)
|
|
45
|
+
══════════════════════════════════════════════════════════════════
|
|
46
|
+
|
|
47
|
+
conversation transcripts (ingest, by cursor)
|
|
48
|
+
│
|
|
49
|
+
▼ CHUNK ································· local model + chunk LoRA [e4b ✓]
|
|
50
|
+
single-topic (segment + label)
|
|
51
|
+
│
|
|
52
|
+
▼ FILTER — worth keeping? ──no──▶ drop
|
|
53
|
+
│ yes
|
|
54
|
+
▼ CLASSIFY → bucket(s) many-to-many ──no fit──▶ drop
|
|
55
|
+
│ bucket ≈ article; from zero, buckets are PROPOSED (taxonomy emerges)
|
|
56
|
+
▼ SYNTHESIZE ······························ local model + synth LoRA
|
|
57
|
+
│ ├─ article does NOT exist → CREATE (sub-cluster → outline → per-section draft)
|
|
58
|
+
│ └─ article EXISTS → UPDATE (SECTION-ROUTE → PATCH one section)
|
|
59
|
+
│ + conservative write gate (≥70% prose floor, every citation survives, weak → NO-OP)
|
|
60
|
+
▼
|
|
61
|
+
article written / one section changed (rest byte-identical)
|
|
62
|
+
│
|
|
63
|
+
▼ NORMALIZE (deterministic code, not a model)
|
|
64
|
+
│ footnote renumber/repair · wikilink canonicalize
|
|
65
|
+
▼
|
|
66
|
+
▼ WIKIFY (periodic, local model + wikify LoRA) ◀── distinct LLM node
|
|
67
|
+
│ "make this a BETTER version" — per-section improve + structural pass
|
|
68
|
+
└──▶ Talk-page signals (embedding/silhouette): SPLIT · MERGE · CONTRADICTION
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
READ · any chat agent (M0, landed; read-only via memory_* tools)
|
|
72
|
+
══════════════════════════════════════════════════════════════════
|
|
73
|
+
question ─▶ search / toc ─▶ read section · follow [[links]] ─▶ reason ─▶ answer
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```mermaid
|
|
77
|
+
flowchart TD
|
|
78
|
+
T[conversation transcripts] --> C["CHUNK · local+LoRA"]
|
|
79
|
+
C -->|segment+label| F{worth keeping?}
|
|
80
|
+
F -->|no| D1((drop))
|
|
81
|
+
F -->|yes| CL["CLASSIFY → bucket(s)"]
|
|
82
|
+
CL -->|no fit| D2((drop))
|
|
83
|
+
CL --> EX{article exists?}
|
|
84
|
+
EX -->|no| CR["CREATE: sub-cluster → outline → per-section draft"]
|
|
85
|
+
EX -->|yes| UP["UPDATE: section-route → patch one section"]
|
|
86
|
+
CR --> GATE["conservative write gate"]
|
|
87
|
+
UP --> GATE
|
|
88
|
+
GATE --> NORM["NORMALIZE footnotes + wikilinks · deterministic"]
|
|
89
|
+
NORM --> WK["WIKIFY periodic · per-section improve + structural pass"]
|
|
90
|
+
WK -->|talk-page| SIG["SPLIT · MERGE · CONTRADICTION"]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## The two synthesis flows
|
|
94
|
+
|
|
95
|
+
### CREATE (cold-start / bootstrap — the zero-article case)
|
|
96
|
+
|
|
97
|
+
Trigger: a bucket has accumulated enough chunks (≥N, conservative) and has **no
|
|
98
|
+
article file yet**. Naively this is whole-article generation from a pile of
|
|
99
|
+
chunks — exactly the open-ended task a small local model is *worst* at. So we
|
|
100
|
+
decompose it the same way we decompose updates — **section-granular**:
|
|
101
|
+
|
|
102
|
+
1. **Sub-cluster** the bucket's chunks into proto-sections (cluster the chunks
|
|
103
|
+
*within* the bucket — the cohesion/embedding machinery applies one level down;
|
|
104
|
+
silhouette is a strong cohesion signal, ρ≈0.68 vs the judges).
|
|
105
|
+
2. **Outline** — name each section from its sub-cluster, write the lead. A small
|
|
106
|
+
structural task, not long-form prose.
|
|
107
|
+
3. **Draft each section** by synthesizing only its sub-cluster's chunks — the
|
|
108
|
+
*same bounded per-section operation* as a patch, just starting from empty.
|
|
109
|
+
4. **Assemble** → article with `# Title`, lead, sections, `## References`, TOC.
|
|
110
|
+
|
|
111
|
+
So even creation never asks the model to hold a whole article in its head: it's
|
|
112
|
+
sub-cluster → outline → N bounded section drafts. Conservative bootstrap bias:
|
|
113
|
+
**under-cover rather than over-cover** — thin buckets stay `{{stub}}` or wait for
|
|
114
|
+
more material (Lucien's lesson: twenty good articles beat a sprawling mediocre
|
|
115
|
+
set).
|
|
116
|
+
|
|
117
|
+
### UPDATE (steady state — article exists)
|
|
118
|
+
|
|
119
|
+
1. **SECTION-ROUTE** the new chunk to the section(s) it affects, via the TOC —
|
|
120
|
+
"this topic affects THESE sections" (e.g. a Reflecting-Pool-renovation chunk →
|
|
121
|
+
the *Renovation* section, and possibly an *Abuse-of-Power* section of a Trump
|
|
122
|
+
article). Many-to-many at section granularity. If it fits no existing section,
|
|
123
|
+
the route is "new section."
|
|
124
|
+
2. **PATCH** just that section: hand the model the section text + the chunk, ask
|
|
125
|
+
it to weave the chunk in with a `[^N]` citation. Bounded in, bounded out.
|
|
126
|
+
Facet extraction is implicit — the same chunk becomes the renovation facts in
|
|
127
|
+
one section and the no-bid-contract framing in another, because the model
|
|
128
|
+
writes what's relevant to the section it's editing.
|
|
129
|
+
3. **Everything else stays byte-identical** — only the routed section is rewritten.
|
|
130
|
+
|
|
131
|
+
Both flows share the **conservative write gate** (already specced in
|
|
132
|
+
`synthesize.ts`): preserve prose, ≥70% word-count floor, every original `conv:`
|
|
133
|
+
citation survives, integrate-not-overwrite; a weak local pass is gated to NO-OP
|
|
134
|
+
rather than allowed to corrupt the vault.
|
|
135
|
+
|
|
136
|
+
## Why WIKIFY is its own (necessary) node
|
|
137
|
+
|
|
138
|
+
Section-patches are greedy and local. Over many of them an article accumulates
|
|
139
|
+
cruft: a section sprawls, sentences go redundant, the lead goes stale, section
|
|
140
|
+
order drifts. **Wikify is the periodic global pass that keeps the article *good*
|
|
141
|
+
— "how do I turn this into a better version of this article" — and it is
|
|
142
|
+
necessary; without it you just keep bolting things on.** This is the LLM
|
|
143
|
+
editorial-restructure (Lucien's "Editorial restructure" commits), *distinct from*
|
|
144
|
+
the deterministic footnote/wikilink normalize that the current `wikify.ts` stub
|
|
145
|
+
conflates it with.
|
|
146
|
+
|
|
147
|
+
Structure makes even this global pass decompose toward local: wikify can run
|
|
148
|
+
**per-section "improve this section"** + a **cheap structural pass over the TOC**
|
|
149
|
+
(reorder, fix the lead, re-section, emit split/merge signals) instead of one
|
|
150
|
+
whole-article regeneration. So wikify is local-tractable for the same reason
|
|
151
|
+
synthesis is: sections.
|
|
152
|
+
|
|
153
|
+
## Data model — pointers, not copies
|
|
154
|
+
|
|
155
|
+
The SQLite store (`~/.cache/mlx-bun/memory.sqlite`) is **derived, rebuildable**
|
|
156
|
+
state — not the source of truth. The principle that keeps it lean and consistent:
|
|
157
|
+
**materialize text in exactly one place; everything else points.**
|
|
158
|
+
|
|
159
|
+
- **Messages hold the text, once.** A `messages` table (text per message), keyed
|
|
160
|
+
by `(conv, position)`.
|
|
161
|
+
- **A chunk is a pointer range, not a copy.** `chunks(id, conv, start, end, label)`
|
|
162
|
+
— a segmentation is *where the boundaries are*, so storing it as a message range
|
|
163
|
+
+ label is the natural representation. Synthesis *dereferences* to message text
|
|
164
|
+
only when it reads a chunk. Re-chunking rewrites pointer rows, never text.
|
|
165
|
+
- **Assignments are join tables (many-to-many).** `chunk_buckets(chunk_id,
|
|
166
|
+
bucket_name)` and, for the section design, `chunk_sections(chunk_id, article,
|
|
167
|
+
section_anchor)` — "this chunk affects THESE sections of THESE articles."
|
|
168
|
+
- **The article markdown is the only materialized synthesis.** Its `[^N]:
|
|
169
|
+
conv:HASH` citations are themselves *pointers back to source conversations*, not
|
|
170
|
+
copies. The vault is the precious git-tracked truth for *articles*; the DB is the
|
|
171
|
+
rebuildable index for *pipeline state*.
|
|
172
|
+
|
|
173
|
+
**The current `db.ts` stub violates this and must be fixed for M1** (it mirrors a
|
|
174
|
+
naive copy design, not Lucien's pointer design):
|
|
175
|
+
- `conversations.transcript` stores the whole transcript blob AND `chunks.text`
|
|
176
|
+
copies each slice → the same text twice. Replace with a `messages` table +
|
|
177
|
+
pointer `chunks` (drop `chunks.text`).
|
|
178
|
+
- `chunks.bucket TEXT` is one-bucket-per-chunk → breaks many-to-many. Replace with
|
|
179
|
+
`chunk_buckets`. Add `chunk_sections` for the section-route output.
|
|
180
|
+
- `synthesized_bucket_chunks` → `synthesized_chunk_sections(article, section_anchor,
|
|
181
|
+
chunk_id, synthesized_at)` so the patch ledger is per-section (fold each chunk
|
|
182
|
+
into each section exactly once).
|
|
183
|
+
|
|
184
|
+
Target tables: `messages` · `chunks` (pointers) · `conversations` · `buckets` ·
|
|
185
|
+
`chunk_buckets` · `chunk_sections` · `synthesized_chunk_sections` · `watermarks`.
|
|
186
|
+
|
|
187
|
+
### Engine: bun:sqlite now, Turso swappable (for vectors)
|
|
188
|
+
|
|
189
|
+
Build M1 on **`bun:sqlite`** — native to Bun, zero-dependency, synchronous, the
|
|
190
|
+
most battle-tested DB there is, and already the project's pattern (`JobStore`,
|
|
191
|
+
`EvalDB`, `registry`, `MemoryStore`). No reason to pay friction on day one.
|
|
192
|
+
|
|
193
|
+
**Turso** (the current product — a from-scratch Rust rewrite of SQLite that is
|
|
194
|
+
*embedded / on-device / offline / SQLite-compatible*, NOT the old cloud-sync
|
|
195
|
+
product) is the evaluation path. Its one concrete payoff for us is **native vector
|
|
196
|
+
search** — and this design is embedding-heavy (section-routing, semantic article
|
|
197
|
+
search, the silhouette signals). Reasons to defer rather than adopt now: it's a
|
|
198
|
+
young engine vs C SQLite, and the Bun-integration story (native binding vs
|
|
199
|
+
FFI/overhead) needs checking.
|
|
200
|
+
|
|
201
|
+
The decision is cheap to defer because (a) Turso is SQLite-*compatible* so the
|
|
202
|
+
schema/SQL above is identical either way, (b) `MemoryStore` already wraps the DB
|
|
203
|
+
behind a small class, so it's a driver swap not a rewrite, and (c) this DB is a
|
|
204
|
+
**rebuildable cache** (truth = vault + git), so it's a low-risk place to adopt a
|
|
205
|
+
younger engine. Plan: keep the SQL standard, keep the driver swappable, and switch
|
|
206
|
+
to Turso *if/when* its vector search beats in-process cosine (or `sqlite-vec`) at a
|
|
207
|
+
corpus size that actually needs ANN.
|
|
208
|
+
|
|
209
|
+
## The cascade (why local is possible at all)
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
clean single-topic chunks → clean buckets → clean section-routing → bounded section-patch
|
|
213
|
+
└──── purity at the root ────┘
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Each stage's locality depends on the prior stage's cleanliness. If a chunk fuses
|
|
217
|
+
two topics, it pollutes every section it's routed into. So **chunk purity is the
|
|
218
|
+
foundation of the whole local system** — not an abstract metric.
|
|
219
|
+
|
|
220
|
+
Caution from the chunk research (research-journal, reports/orpo-chunk-paper):
|
|
221
|
+
embeddings measure **cohesion/dispersion well** (silhouette ρ≈0.68 per-conv vs
|
|
222
|
+
the LLM judges) but **purity/contamination poorly** (−intraSpread ρ≈0.32, ns
|
|
223
|
+
within variants). So a clean-bucket guarantee cannot lean on a cheap embedding
|
|
224
|
+
signal — it rides on the local **chunker** actually being good at single-topic
|
|
225
|
+
splitting (the e4b adapter's real job), backed where needed by a non-embedding
|
|
226
|
+
purity check, not by cosine geometry.
|
|
227
|
+
|
|
228
|
+
## Stage → model → adapter
|
|
229
|
+
|
|
230
|
+
| stage | file | model | adapter |
|
|
231
|
+
|---|---|---|---|
|
|
232
|
+
| chunk | `src/memory/chunk.ts` | local | **chunk LoRA (e4b chunk-300, exists)** |
|
|
233
|
+
| classify | `src/memory/cluster.ts` | local + embeddings | classify LoRA (TODO) |
|
|
234
|
+
| synthesize (create/update) | `src/memory/synthesize.ts` | local | synth LoRA (TODO) |
|
|
235
|
+
| normalize | `src/memory/wikify.ts` (rename) | **deterministic code** | — |
|
|
236
|
+
| wikify (LLM) | **new node** | local | wikify LoRA (TODO) |
|
|
237
|
+
|
|
238
|
+
Section-routing (the new intra-article step) is embeddings-shaped: embed the
|
|
239
|
+
chunk (or its label) and the article's section headings/lead (from `parseToc` /
|
|
240
|
+
`extractSection`, already in `vault.ts`), route to the nearest section(s) over a
|
|
241
|
+
threshold. The local Qwen3-Embedding backbone (bit-exact, served, `/v1/embeddings`)
|
|
242
|
+
is exactly the "vector search over articles, not conversations" the vision calls
|
|
243
|
+
for — now applied at section granularity.
|
|
244
|
+
|
|
245
|
+
## What changes in the scaffold
|
|
246
|
+
|
|
247
|
+
The M1 stubs are wired (`pipeline.ts` orchestrates ingest→chunk→cluster→
|
|
248
|
+
synthesize→wikify→changelog; stage bodies throw "not implemented"). Two
|
|
249
|
+
corrections vs the stubs:
|
|
250
|
+
|
|
251
|
+
1. **`synthesize.ts` is whole-article today.** Make it `create-or-update`, with
|
|
252
|
+
update = section-route + section-patch (not whole-article regeneration).
|
|
253
|
+
2. **The LLM wikify node is missing.** The current `wikify.ts` is *only*
|
|
254
|
+
deterministic normalize. Keep that (rename to `normalize.ts`), and add a
|
|
255
|
+
distinct **LLM wikify** node for the periodic "better version" pass.
|
|
256
|
+
|
|
257
|
+
## Build sequence
|
|
258
|
+
|
|
259
|
+
Cold-start first, because the vault is empty and you can't patch what doesn't exist:
|
|
260
|
+
|
|
261
|
+
1. **Wire CHUNK** to the e4b chunk adapter (`chunk.ts`) — the one stage with an
|
|
262
|
+
adapter in hand. Verify single-topic chunks + labels on real conversations.
|
|
263
|
+
2. **CLASSIFY from zero** (`cluster.ts`) — emergent bucket taxonomy
|
|
264
|
+
(`Meta/Buckets.md`); assign chunks to buckets, propose new ones; filter no-fit.
|
|
265
|
+
3. **CREATE flow** (`synthesize.ts`) — sub-cluster → outline → per-section draft
|
|
266
|
+
for buckets crossing the chunk threshold. Behind the conservative gate. This
|
|
267
|
+
is what gets us from zero to a first set of articles.
|
|
268
|
+
4. **NORMALIZE** (`normalize.ts`) — wire the deterministic footnote/wikilink
|
|
269
|
+
repair (`vault.ts` already has the resolver).
|
|
270
|
+
5. **UPDATE flow** — section-route + patch, once articles exist to update.
|
|
271
|
+
6. **WIKIFY (LLM)** + Talk-page split/merge signals — once articles have
|
|
272
|
+
accumulated enough cruft/drift to need them.
|
|
273
|
+
|
|
274
|
+
Steps 1–4 are the cold-start path (zero → first articles); 5–6 are steady state.
|
|
275
|
+
|
|
276
|
+
## Open questions
|
|
277
|
+
|
|
278
|
+
- **Article granularity / when to CREATE** — chunk threshold per bucket; when a
|
|
279
|
+
bucket should become one article vs several (the vision's "soft size caps").
|
|
280
|
+
- **Section-route confidence** — threshold for "fits an existing section" vs
|
|
281
|
+
"new section needed" vs "route to a different article."
|
|
282
|
+
- **Provisional facts** — representing "work set to begin July" so the next pass
|
|
283
|
+
cleanly updates it to "began / completed" (temporal/trajectory tracking).
|
|
284
|
+
- **Create vs strong-model** — is first-creation good enough on the local model,
|
|
285
|
+
or is bootstrap the one place a stronger model is worth it (vision: bootstrap is
|
|
286
|
+
heavier but the same code path)?
|
|
287
|
+
- **The purity check** — what non-embedding signal guarantees clean buckets.
|