mlx-bun 0.2.0 → 0.3.0
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 +71 -588
- package/docs/README.md +91 -0
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +394 -159
- package/docs/reference/distribution.md +321 -182
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +566 -168
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +104 -6
- package/docs/reference/server-api.md +886 -425
- package/docs/reference/server-config.md +638 -330
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +58 -25
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +236 -3
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +8 -96
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +1 -1
- package/src/generate.ts +656 -268
- package/src/grammar.ts +12 -7
- package/src/harness-pi.ts +14 -33
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +7 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +12 -12
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-store.ts +109 -49
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
- package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +1 -1
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +30 -169
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +1 -3
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +58 -11
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +33 -13
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/batched-mask.ts +8 -2
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +2 -2
- package/src/model/batched-rotating.ts +1 -1
- package/src/model/compiled-decode.ts +1 -1
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +76 -33
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +26 -9
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +2 -2
- package/src/model/generated/gemma4-26b.ts +2 -2
- package/src/model/generated/gemma4-e4b.ts +2 -2
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +6 -8
- package/src/model/profile.ts +12 -2
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +140 -56
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/universal/dense.ts +1 -1
- package/src/model/universal/modules.ts +8 -1
- package/src/native-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/prompt-cache.ts +96 -53
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/config-writer.ts +10 -3
- package/src/quantize/rotate.ts +4 -4
- package/src/quantize/trellis.ts +586 -0
- package/src/responses.ts +28 -1
- package/src/runtime-config.ts +18 -4
- package/src/sampler.ts +4 -4
- package/src/serve/batch-scheduler.ts +8 -1671
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +15 -7
- package/src/serve/discovery-routes.ts +12 -13
- package/src/serve/generation-gateway.ts +154 -193
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/lab-routes.ts +3 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +7 -5
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +512 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/request-plan.ts +19 -15
- package/src/serve/request-prep.ts +346 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +317 -2649
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +8 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +4 -3
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +1 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +166 -69
- package/src/spec/serve-loop.ts +154 -156
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +80 -12
- package/src/ssd-durability.ts +25 -13
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +2 -2
- package/src/train/forward.ts +6 -0
- package/src/train/loss.ts +1 -1
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +5 -3
- package/src/train/trainer.ts +6 -6
- package/src/vision/prompt.ts +1 -1
- package/src/vision/qwen3vl-tower.ts +52 -10
- package/src/web/app.html +1 -1
- package/src/web/app.js +5 -3
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +4 -4
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +55 -9
- package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/archive/investigations/hlg-ab.html +0 -34
- package/docs/archive/investigations/hlg-explorer.html +0 -238
- package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
- package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/archive/investigations/hlg-report.html +0 -262
- package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -318
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -231
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -415
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/turboquant-weights.md +0 -467
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -101
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -11
- /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
- /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
- /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
- /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
- /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
- /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -1,291 +1,684 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
1
|
+
---
|
|
2
|
+
status: active
|
|
3
|
+
axis: USING
|
|
4
|
+
canonical-for: memory-synthesis (the Dreaming)
|
|
5
|
+
plan-anchor: none
|
|
6
|
+
last-verified: 2026-08-23
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# The Dreaming — memory write path + synthesis (canonical design)
|
|
10
|
+
|
|
11
|
+
This is THE design doc for mlx-bun's memory write path: the pipeline that
|
|
12
|
+
turns conversations into a personal wiki (`src/memory/`, `scripts/memory/`),
|
|
13
|
+
the local-model inference seam it runs on, the read path it feeds, and the
|
|
14
|
+
evaluation methodology that sits beside it. It consolidates, in supersession
|
|
15
|
+
order, `docs/design/dreaming-nightly-pipeline.md` → `docs/design/dreaming-nightly-pipeline.md` →
|
|
16
|
+
`docs/design/dreaming-nightly-pipeline.md` → this doc, plus the architecture half of
|
|
17
|
+
`docs/design/dreaming-nightly-pipeline.md`, `docs/design/dreaming-nightly-pipeline.md`, and the still-open task list
|
|
18
|
+
from `docs/design/dreaming-nightly-pipeline.md`. Where those docs disagree, this doc wins.
|
|
19
|
+
|
|
20
|
+
- User-facing behaviour (CLI, tools, vault layout as the user sees it) lives
|
|
21
|
+
in `docs/reference/memory.md`. Status and changelog prose belong in
|
|
22
|
+
`PLAN.md`; this doc carries design plus a short dated History.
|
|
23
|
+
- Every code claim below was re-read against `src/memory/` on 2026-08-23.
|
|
24
|
+
Where the code and the settled design differ, both are stated
|
|
25
|
+
("as built" vs "target") — the code is the truth about what runs; the
|
|
26
|
+
design is the truth about where it goes.
|
|
27
|
+
|
|
28
|
+
The system is the second iteration of Lucien's memory pipeline
|
|
29
|
+
(`~/Code/lucien`, cloud models), rebuilt to run entirely on local models. Same
|
|
30
|
+
methodology at the core — do whatever Wikipedia does — with two consequences
|
|
31
|
+
of the local constraint:
|
|
32
|
+
|
|
33
|
+
1. **Small tasks.** Every AI step is the smallest single-purpose unit a small
|
|
34
|
+
local model does well — one chunk, one section, ideally a binary judgment.
|
|
35
|
+
Never a whole-article blob in or out. And every AI step is pure
|
|
36
|
+
text-in/text-out: no tool calls, no agent loop. The pipeline hands the
|
|
37
|
+
model exactly the context it needs and applies the output
|
|
38
|
+
deterministically.
|
|
39
|
+
2. **Deterministic gates between AI steps.** AI does judgment; code enforces
|
|
40
|
+
invariants (citations, footnotes, wikilinks, infobox shape, word floors).
|
|
41
|
+
A weak output is gated to NO-OP, never allowed to corrupt the vault.
|
|
42
|
+
"LoRAs propose, gates dispose."
|
|
43
|
+
|
|
44
|
+
## 1. Contract and fixed principles
|
|
45
|
+
|
|
46
|
+
**The memory contract (ported from Lucien):** chat-time agents READ memory;
|
|
47
|
+
the synthesis pipeline WRITES memory. Articles are durable priors,
|
|
48
|
+
conversations are evidence, synthesis is the deliberate, auditable process
|
|
49
|
+
that turns evidence into updated articles. Normal chat never mutates an
|
|
50
|
+
article; writes happen only through `mlx-bun memory synthesize` (or its
|
|
51
|
+
per-stage subcommands) and the user's own edits in the vault.
|
|
52
|
+
|
|
53
|
+
Fixed principles (do not re-derive, do not contradict):
|
|
30
54
|
|
|
31
55
|
- **Conversations are the base.** The pipeline's only input is conversation
|
|
32
|
-
transcripts
|
|
33
|
-
|
|
34
|
-
- **
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- **No
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
transcripts — pi sessions in steady state, a one-time historical import
|
|
57
|
+
through the same code for onboarding.
|
|
58
|
+
- **Articles are THINGS (subjects), with sections.** One subject per
|
|
59
|
+
article: a lead, an infobox, `##` sections, See also, References. Subject
|
|
60
|
+
mentions are `[[wikilinks]]`. Every article is "the thing AND how the user
|
|
61
|
+
relates to it"; general world-facts link out.
|
|
62
|
+
- **No notability filter.** "If I talk about it, it's notable." Nothing is
|
|
63
|
+
dropped as trivia. A thin subject is CAPTURED (kept searchable in
|
|
64
|
+
`_captured`) until it recurs; stubs are a feature.
|
|
65
|
+
- **Capacity by decomposition.** A small model's effective capacity scales
|
|
66
|
+
inversely with task size; you don't make the model smarter, you make each
|
|
67
|
+
task narrower. Decompose to binary where possible and run M×N — affordable
|
|
68
|
+
because local inference is nearly free. Coarse gates prune fine ones
|
|
69
|
+
(chunk → article → section).
|
|
70
|
+
- **No embeddings in the pipeline.** Routing, grouping, and reading are
|
|
71
|
+
deterministic name/alias/category lookup plus small-model judgments. The
|
|
72
|
+
hot path asserts the `src/embed.ts` tripwire (`getEmbedCounter()`) stays
|
|
73
|
+
at 0. Embeddings survive only as offline eval instruments (§8) — see the
|
|
74
|
+
contradiction note there.
|
|
75
|
+
- **Vault = truth, DB = derived cache.** Markdown in the vault is canonical
|
|
76
|
+
and git-tracked; SQLite is pipeline ledger + rebuildable index
|
|
46
77
|
(`reindex`).
|
|
47
|
-
- **
|
|
48
|
-
|
|
49
|
-
latest
|
|
50
|
-
- **
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
- **Chronology is load-bearing.** Every stage walks
|
|
79
|
+
`conversations.updated_at ASC, chunks.start ASC`. This is what makes
|
|
80
|
+
self-healing correct: the user's latest statement dominates.
|
|
81
|
+
- **Self-healing through ordinary use.** Corrections arrive as ordinary
|
|
82
|
+
chunks; a later-dated contradiction resolves the article toward the
|
|
83
|
+
user's latest position. The user's evolving positions keep a `## History`
|
|
84
|
+
trace; an AI factual error is silently overwritten.
|
|
85
|
+
- **Prompts and Meta pages are SCHEMATIC** — no real names, specs, or dates.
|
|
86
|
+
The small model parrots concrete example values into unrelated articles
|
|
87
|
+
(observed five times during bring-up). Every prompt carries a no-copy
|
|
88
|
+
guard; leaky drafts are rejected (`isLeakyDraft`).
|
|
89
|
+
- **Runs nightly, locally, unattended** (launchd, `src/memory/schedule.ts`).
|
|
90
|
+
- **Lucien is a read-only oracle.** `~/Code/lucien/.lucien/lucien.db` is
|
|
91
|
+
opened read-only; `~/Dreaming` is never written. Never suggest modifying
|
|
92
|
+
Lucien's code, DB, or vault.
|
|
93
|
+
- **Model evals are beside the system, not inside it.** Judges, gold sets,
|
|
94
|
+
and signal scripts choose and train the models the pipeline uses; they are
|
|
95
|
+
never a pipeline stage.
|
|
96
|
+
|
|
97
|
+
## 2. Data model
|
|
98
|
+
|
|
99
|
+
### 2.1 Vault (truth)
|
|
100
|
+
|
|
101
|
+
- Root `~/.mlx-bun/wiki/` (override `MLX_BUN_WIKI`, honoured by `vaultRoot()`
|
|
102
|
+
— every script and test redirects the whole pipeline by setting it).
|
|
103
|
+
- `articles/*.md` user articles · `Meta/*.md` editable policy pages ·
|
|
104
|
+
`Talk/` restructure suggestions · `Reference/*.md` read-only symlinks to
|
|
105
|
+
mlx-bun's own docs (chat tools may read them; synthesis must never write
|
|
106
|
+
through them).
|
|
107
|
+
- Plain Markdown, git-tracked, usable as an Obsidian vault. Every pipeline
|
|
108
|
+
write ends in `commitVault`.
|
|
109
|
+
- Meta pages seeded by `setupVault` (`src/memory/vault.ts` `META_PAGES`):
|
|
110
|
+
Editorial_Guidelines, Bucketing, Article_Conventions, Infobox_Schemas,
|
|
111
|
+
Category_Definitions, Entities, Summary_Style, Buckets, Chunking,
|
|
112
|
+
Topics_to_Ignore. Policy lives in the vault, not in code:
|
|
113
|
+
`loadMetaPolicy(names)` (`src/memory/prompts.ts`) inlines pages into a
|
|
114
|
+
stage prompt (single-turn, bounded prefill — never "go read the page")
|
|
115
|
+
and throws if a requested page is missing.
|
|
116
|
+
|
|
117
|
+
### 2.2 Article grammar (`src/memory/article.ts`)
|
|
118
|
+
|
|
119
|
+
Fixed skeleton, top to bottom: `# H1` (== filename stem with `_`→space) →
|
|
120
|
+
optional series banner `*Part of a series on [[X]].*` → optional infobox
|
|
121
|
+
(fenced ```` ```info ```` block of `key: value` lines) → lead (present-tense
|
|
122
|
+
relationship abstract) → `##` sections → `## See also` → optional `## Notes`
|
|
123
|
+
→ `## References` last. Templates the parser and NORMALIZE recognise:
|
|
124
|
+
`{{stub}}`, `*Main article: [[Child]]*`, `*Redirects to [[X]]*`.
|
|
125
|
+
|
|
126
|
+
- **Infobox** — `snake_case` keys; entity-valued fields are `[[wikilinks]]`
|
|
127
|
+
(they feed the link graph); `aliases:` is a comma list feeding the entity
|
|
128
|
+
index; `kind:` is the closed set `ENTITY_KINDS = thing | person | domain |
|
|
129
|
+
project | standard`; `type:` and every other field label are EMERGENT
|
|
130
|
+
(governed by `Infobox_Schemas.md`, never a code enum). Fields are either
|
|
131
|
+
world-facts (citable specs) or relationship-facts (owned / used_for /
|
|
132
|
+
opinion / status … — the personal layer). The infobox is CONTENT the model
|
|
133
|
+
reads, never a query/filter engine; there is no field query anywhere.
|
|
134
|
+
- **Categories** — emergent and explicit: an article declares
|
|
135
|
+
`[[Category:Name]]`; the deriver accumulates names into `categories`. A
|
|
136
|
+
fresh vault has zero.
|
|
137
|
+
- **Citations** — footnote defs in the Lucien standard
|
|
138
|
+
`` [^N]: `conv:HASH` (YYYY-MM-DD, source) — desc ``, HASH = first 8 hex of
|
|
139
|
+
the conversation UUID. A hash identifies the CONVERSATION only; chunk →
|
|
140
|
+
section provenance is recovered from the ledger, never by parsing
|
|
141
|
+
footnotes. The model only PLACES markers; code writes every definition
|
|
142
|
+
line (`buildFootnoteMap`, `footnoteDefLine` in `synthesize.ts`).
|
|
143
|
+
- One shared fence scanner (`isFenceLine`/`fenceLabel`) so `article.ts`,
|
|
144
|
+
`vault.ts`, `normalize.ts`, `crosslink.ts` agree on "inside a code block";
|
|
145
|
+
`repairFences` closes a dangling fence deterministically.
|
|
146
|
+
|
|
147
|
+
### 2.3 Store (`src/memory/db.ts`, `~/.cache/mlx-bun/memory.sqlite`)
|
|
148
|
+
|
|
149
|
+
bun:sqlite, WAL, `PRAGMA foreign_keys = ON`, `ON DELETE CASCADE`. A DB
|
|
150
|
+
carrying the pre-rewrite schema (`chunks.text` column or a
|
|
151
|
+
`synthesized_bucket_chunks` table) is dropped and recreated on open.
|
|
152
|
+
|
|
153
|
+
- **Derived cache** (rebuilt from markdown by `reindex`, never the reverse):
|
|
154
|
+
`entities` · `entity_aliases` · `categories` · `article_categories` ·
|
|
155
|
+
`infobox_facts` · `links` (`via ∈ prose|infobox|seealso|series|main`).
|
|
156
|
+
- **Synthesis ledger** (authoritative pipeline progress, not derivable from
|
|
157
|
+
the vault): `conversations` · `messages` · `chunks` · `chunk_entities` ·
|
|
158
|
+
`chunk_sections` · `synthesized_chunk_sections` · `reconciled_articles` ·
|
|
159
|
+
`watermarks` · `buckets` / `chunk_buckets` · `subject_redirects`.
|
|
160
|
+
- **Pointers, not copies.** `messages` holds text once, keyed
|
|
161
|
+
`(conv, position)`. A chunk is a `[start,end]` range plus a label, id
|
|
162
|
+
`${conv}:${start}-${end}` (deterministic, idempotent re-chunking);
|
|
163
|
+
`chunkText(id)` reassembles on demand. Assignments are join tables
|
|
164
|
+
(many-to-many at every layer). The article markdown is the only
|
|
165
|
+
materialised synthesis; its `conv:` citations point back at sources.
|
|
166
|
+
- `reindex` (`src/memory/reindex.ts`) drops and rebuilds exactly the six
|
|
167
|
+
derived tables from the vault with foreign keys off (so pipeline
|
|
168
|
+
`chunk_entities` rows survive), in sorted-stem order, deterministically.
|
|
169
|
+
It also PROJECTS `subject_redirects` into `entity_aliases` so a subject
|
|
170
|
+
that folded into or was captured near another article still resolves.
|
|
171
|
+
|
|
172
|
+
Turso/sqlite-vec were considered as a vector-capable engine and are moot
|
|
173
|
+
under the no-embeddings rule; the driver stays bun:sqlite.
|
|
174
|
+
|
|
175
|
+
## 3. The pipeline as built (verified 2026-08-23)
|
|
59
176
|
|
|
60
177
|
```
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
│
|
|
76
|
-
▼ ── deterministic gates ── citation survival · footnote bijection ·
|
|
77
|
-
│ word floor · wikilink resolution · weak output → NO-OP
|
|
78
|
-
│
|
|
79
|
-
▼ RECONCILE ────────────── infobox = ground truth; lead/body/infobox agree
|
|
80
|
-
▼ LINK ─────────────────── cross-link: mentions → [[links]], co-occurrence → See also
|
|
81
|
-
▼ NORMALIZE ────────────── deterministic: footnote renumber, wikilink canonicalize,
|
|
82
|
-
│ structure guards (References last, stub marking)
|
|
83
|
-
▼ EDITORIAL (wikify) ───── AI: remove redundancy, organize, make it read well —
|
|
84
|
-
│ per-section improve + structural pass over the TOC
|
|
85
|
-
▼
|
|
86
|
-
commit to vault (git) + run changelog
|
|
178
|
+
pi sessions / Lucien import ingest.ts (watermark per source) [NOT wired into the nightly run — §9]
|
|
179
|
+
│
|
|
180
|
+
▼ SEGMENT ─────────── AI (memory-chunk adapter): one conversation → single-topic chunks + labels
|
|
181
|
+
▼ ENTITY-EXTRACT ──── AI (base+Entities.md): one chunk → the THINGS it is about (name list)
|
|
182
|
+
▼ ROUTE ────────────── deterministic resolve → binary disambiguate → create | routed | capture
|
|
183
|
+
▼ SYNTHESIZE
|
|
184
|
+
│ CREATE ─────────── AI: sub-cluster → OUTLINE → per-section DRAFT → INFOBOX → assemble
|
|
185
|
+
│ SECTION-ROUTE ──── AI: M×N binary "does this chunk update THIS section?" (+ name a new one)
|
|
186
|
+
│ PATCH ──────────── AI: one (chunk, section) → replacement section, rest byte-identical
|
|
187
|
+
│ RECONCILE ──────── AI+code: infobox = ground truth; lead/body/infobox agree; History
|
|
188
|
+
│ ── every write: NORMALIZE (code) → conservative gate (code) → weak ⇒ NO-OP ──
|
|
189
|
+
▼ LINK ─────────────── code: first-mention [[links]] + co-occurrence See also (idempotent)
|
|
190
|
+
▼ commit (git)
|
|
191
|
+
▼ WIKIFY sweep ─────── AI (editor): per-section tighten + infobox refresh, every article
|
|
87
192
|
```
|
|
88
193
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
`
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
holds a whole article
|
|
168
|
-
- **
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
194
|
+
Orchestration: `runSynthesis` (`src/memory/pipeline.ts`) drives
|
|
195
|
+
`runPipeline` = `runSegmentStage → runExtractStage → runRouteStage →
|
|
196
|
+
runSynthesizeStage → runLinkStage`, then `wikifyVault` over every article.
|
|
197
|
+
Each stage worker (`src/memory/stages.ts`) pulls its eligible work from the
|
|
198
|
+
DB by state, processes a bounded batch, persists, and is individually
|
|
199
|
+
runnable: `mlx-bun memory segment | extract | route | synthesize-stage |
|
|
200
|
+
link`; `mlx-bun memory synthesize` is the full DAG; `--dry-run` plans without
|
|
201
|
+
model calls. A failed article never blocks the rest of a run.
|
|
202
|
+
|
|
203
|
+
### 3.1 INGEST (`ingest.ts`)
|
|
204
|
+
|
|
205
|
+
Two sources, watermark-gated per `source`: pi sessions via
|
|
206
|
+
`SessionManager.listAll()` (`ingestSessions`) and the one-time Lucien
|
|
207
|
+
bootstrap (`ingestLucien`, read-only; maps Lucien's UUID-anchored chunks to
|
|
208
|
+
positions). Idempotent — a re-touched conversation is rewritten in place.
|
|
209
|
+
**As built, neither entry point is called by `runSynthesis` or any
|
|
210
|
+
`scripts/memory/` driver** (only `tests/memory-ingest.test.ts` exercises
|
|
211
|
+
`ingestLucien`); `runPipeline` emits "ingest: corpus already in the store".
|
|
212
|
+
The nightly fold-in of new pi sessions is therefore not yet end-to-end — see
|
|
213
|
+
§9.
|
|
214
|
+
|
|
215
|
+
### 3.2 SEGMENT (`chunk.ts`, `chunk-validation.ts`)
|
|
216
|
+
|
|
217
|
+
The `memory-chunk` adapter (`e4b-chunk-300`, symlinked to
|
|
218
|
+
`~/.cache/mlx-bun/adapters/memory-chunk`) segments each conversation whose
|
|
219
|
+
`chunked_at` is NULL or older than `updated_at`. Prompt = `CHUNK_SYSTEM`
|
|
220
|
+
(the exact trained system turn, byte-for-byte) + `CHUNK_PROMPT` with
|
|
221
|
+
`Chunking.md` + `Topics_to_Ignore.md` inlined. Output is JSON of message-UUID
|
|
222
|
+
anchors + a 4–10-word label; anchors are validated and repaired
|
|
223
|
+
(`validateChunks`) before pointer rows are written; a conversation whose
|
|
224
|
+
output fails validation is left unmarked and retried next run. Re-run is a
|
|
225
|
+
no-op by watermark. Chunk purity is the foundation of everything downstream:
|
|
226
|
+
a chunk that fuses two topics pollutes every article it routes to.
|
|
227
|
+
|
|
228
|
+
### 3.3 ENTITY-EXTRACT (`entity.ts`, `resolve.ts`)
|
|
229
|
+
|
|
230
|
+
One chunk per call, base model + `Entities.md`: "what things is this chunk
|
|
231
|
+
about? canonical wiki-title names, one per line, specific things AND the
|
|
232
|
+
broad domain, NONE if nothing nameable." Plain newline list parsed by
|
|
233
|
+
`parseLines` — no multi-item JSON, no batch indices (the batch-index drift
|
|
234
|
+
that sank Lucien's batched assign). Persists `chunk_entities(chunk_id,
|
|
235
|
+
entity_name, surface_form)` and a candidate `entities` row (article_stem
|
|
236
|
+
NULL). Canonicalisation is deterministic and conservative
|
|
237
|
+
(`EntityResolver`): `canonicalize` (casefold, whitespace, leading
|
|
238
|
+
articles/possessives) → `squeeze` (strip all non-alphanumerics) → alias index
|
|
239
|
+
(store + `goldens/dreaming-entities-gold.json` seeds) → token-subset fuzzy
|
|
240
|
+
match requiring a distinctive token (the over-merge guard). When in doubt it
|
|
241
|
+
mints a new canonical rather than fusing two things.
|
|
242
|
+
|
|
243
|
+
### 3.4 ROUTE (`route.ts`, `redirect.ts`)
|
|
244
|
+
|
|
245
|
+
Per surface: (1) RESOLVE against the known-entity index — a hit folds into
|
|
246
|
+
that article with no model call; (2) DISAMBIGUATE a miss with a trigram
|
|
247
|
+
shortlist of existing entities and one bounded binary per candidate ("is X
|
|
248
|
+
the same thing as Y? yes/no", `parseBinary`, existing wins); (3) CREATE /
|
|
249
|
+
CAPTURE for a surface matching nothing: it earns its own article when it
|
|
250
|
+
RECURS (`RECURRENCE_THRESHOLD = 2` routed chunks) or, with the optional
|
|
251
|
+
`useSubjectGate`, when a chunk engages it as a genuine subject; otherwise it
|
|
252
|
+
is CAPTURED — its chunks go to the reserved `_captured` bucket, `notable = 0`,
|
|
253
|
+
still searchable, never dropped, promoted later if it recurs. There is no
|
|
254
|
+
ownership/usefulness test. `runRouteStage` also registers
|
|
255
|
+
`subject_redirects` so every discussed subject resolves to a home (a folded
|
|
256
|
+
subject → its article; a captured subject → the article it most co-occurs
|
|
257
|
+
with). A chunk fans out to every article it names — this is where facet
|
|
258
|
+
extraction falls out: the same chunk lands on several articles, each keeping
|
|
259
|
+
only what is relevant to it at patch time.
|
|
260
|
+
|
|
261
|
+
### 3.5 SYNTHESIZE (`stages.ts` `runSynthesizeStage`, `synthesize.ts`, `cluster.ts`)
|
|
262
|
+
|
|
263
|
+
Chronological throughout; commits once at the end.
|
|
264
|
+
|
|
265
|
+
- **CREATE** (`synthesizeCreate`) for each `notable = 1` entity with no
|
|
266
|
+
article file, oldest entity first, capped by `DEFAULT_ARTICLE_CAP = 20`
|
|
267
|
+
per pass: `subClusterChunks` groups the entity's chunks into proto-sections
|
|
268
|
+
by label/text token overlap (deterministic, no embeddings) → OUTLINE (2–6
|
|
269
|
+
headings) → per-section DRAFT from only that section's chunks → LEAD →
|
|
270
|
+
seed INFOBOX (`buildInfoboxFields`, kind + declared aliases) → assemble →
|
|
271
|
+
NORMALIZE → gate → write + `synthesized_chunk_sections` ledger. The model
|
|
272
|
+
never holds a whole article. Leaky drafts retry once, then NO-OP.
|
|
273
|
+
- **SECTION-ROUTE** (`routeSections`) for each chunk routed to an existing
|
|
274
|
+
article and not yet in the ledger: one binary per routable section
|
|
275
|
+
(structural tails References/See also/Notes excluded; the lead is a
|
|
276
|
+
first-class target, `LEAD_ANCHOR`), prompt = title + heading + section's
|
|
277
|
+
first ~2 sentences + chunk label + gist. All-no + substantive → "name a new
|
|
278
|
+
section (2–5 words) or NONE"; a named section is honoured
|
|
279
|
+
(`synthesizeNewSection`), never a silent drop. Hierarchical pruning is
|
|
280
|
+
structural: only articles ROUTE matched are ever gridded.
|
|
281
|
+
- **PATCH** (`synthesizePatch`, `patchSection`) — the model is handed the
|
|
282
|
+
current section + the chunk (with its pre-assigned `[^N]`) and outputs a
|
|
283
|
+
complete REPLACEMENT SECTION; code swaps exactly that section
|
|
284
|
+
(`replaceSection`), appends the definition line, and leaves the rest of
|
|
285
|
+
the file byte-identical. Contradiction = correction: rewrite toward the
|
|
286
|
+
latest statement, classified by `classifyContradiction` (`history.ts`) as
|
|
287
|
+
EVOLUTION (keep a `## History` entry citing both sources; default when
|
|
288
|
+
ambiguous) or ERROR (silent overwrite, the wrong value's citation may be
|
|
289
|
+
pruned via `allowDroppedHashes`). Idempotent via the ledger PK.
|
|
290
|
+
- **RECONCILE** (`reconcileArticle`) runs after the patch loop over every
|
|
291
|
+
article touched this run: the infobox is ground truth; relationship
|
|
292
|
+
fields (favourite/opinion/status/owned … — never `PHYSICAL_SPEC_KEYS`) and
|
|
293
|
+
sibling body sections still asserting a superseded value are refreshed
|
|
294
|
+
toward the latest-dated position, provenance-preserving (every `[^k]`
|
|
295
|
+
survives, phrased as change over time). Consistent article ⇒ NO-OP;
|
|
296
|
+
unresolved present-tense assertions are logged, not forced.
|
|
297
|
+
|
|
298
|
+
### 3.6 The conservative write gate (`gate.ts`) and NORMALIZE (`normalize.ts`)
|
|
299
|
+
|
|
300
|
+
`gateEdit(before, after)` is a faithful port of Lucien's editorial gate and
|
|
301
|
+
guards every write (create, patch, new section, reconcile, link, wikify):
|
|
302
|
+
every pre-existing `conv:` citation survives (unless deliberately pruned),
|
|
303
|
+
footnote bijection, edited word count ≥ `floor` (default 0.7) of the
|
|
304
|
+
original, H1 and `## References` survive, at most one `## See also`. It can
|
|
305
|
+
only reject, never rewrite; it catches citation/structure/bulk-prose loss,
|
|
306
|
+
not nuance loss (that is the judge's job, §8).
|
|
307
|
+
|
|
308
|
+
`normalizeArticle` runs inside every write before the gate, pure and
|
|
309
|
+
idempotent: footnote renumber/merge (`normalizeFootnotes`), wikilink
|
|
310
|
+
canonicalisation to on-disk stems (`normalizeWikilinks`), infobox key sort,
|
|
311
|
+
section order (`## See also` before `## References` last), `{{stub}}` guard
|
|
312
|
+
for thin articles (`articleThinness`), `title = H1 = stem`, fence repair.
|
|
313
|
+
Non-fatal per step. `normalizeVault` exists for a whole-vault pass but is not
|
|
314
|
+
a nightly stage; normalisation is constitutive of each write instead.
|
|
315
|
+
|
|
316
|
+
### 3.7 LINK (`crosslink.ts`)
|
|
317
|
+
|
|
318
|
+
Cross-linking is its own deterministic stage because synthesis is bounded to
|
|
319
|
+
one article and cannot know the others. (1) MENTION edges: wrap the first
|
|
320
|
+
whole-word mention of another article's title/alias as
|
|
321
|
+
`[[Stem|surface]]` — never inside an existing link, code span, marker,
|
|
322
|
+
infobox, heading, or References. (2) CO-OCCURRENCE edges from shared folded
|
|
323
|
+
chunks (`synthesized_chunk_sections` ⋈ `chunk_entities`). (3) Rebuild
|
|
324
|
+
`## See also` idempotently (mentions first, then top co-occurring articles
|
|
325
|
+
that exist). Every edit passes `normalizeWikilinks` + `gateEdit`; a fully
|
|
326
|
+
linked article re-runs to a byte-identical no-op. Measured on a 587-article
|
|
327
|
+
snapshot of the import (2026-06-28, M1 Max 32 GB): See-also coverage 18% →
|
|
328
|
+
96%, resolved edges 309 → 7026.
|
|
329
|
+
|
|
330
|
+
### 3.8 WIKIFY — the editorial pass (`wikify.ts`)
|
|
331
|
+
|
|
332
|
+
The periodic sweep, distinct from NORMALIZE: the model supplies judgment, the
|
|
333
|
+
gate disposes of weak judgment. As built, `runSynthesis` runs `wikifyVault`
|
|
334
|
+
over EVERY article every night after the write branch; each article commits
|
|
335
|
+
its own change or NO-OPs, and a wikify defect cannot lose the committed
|
|
336
|
+
create/patch work.
|
|
337
|
+
|
|
338
|
+
- Per-section IMPROVE (`improveSections`, `editor` stage): "tighten this
|
|
339
|
+
section — remove redundancy, keep every citation and every specific
|
|
340
|
+
detail." Behind the gate.
|
|
341
|
+
- Infobox EXTRACT/REFRESH (`refreshInfobox`): creates a missing infobox,
|
|
342
|
+
refreshes present ones without losing a grounded fact, entity-valued
|
|
343
|
+
fields as wikilinks, declared `aliases:` feed the entity index on reindex.
|
|
344
|
+
- Summary-style SPLIT (`detectSplitCandidate`, `applySplit`): when one body
|
|
345
|
+
section dominates the article it becomes a child article with the full
|
|
346
|
+
cited prose; the parent keeps a summary + `*Main article: [[Child]]*`
|
|
347
|
+
(a `via=main` edge). Skips the word floor (a sanctioned bulk move); gated
|
|
348
|
+
structurally instead. Series banner maintenance (`setSeriesBanner`).
|
|
349
|
+
- MERGE signals (`detectMergeCandidates`) and structure suggestions are
|
|
350
|
+
written to `Talk/<stem>.md` (`writeTalkPage`) — the pass never
|
|
351
|
+
restructures across articles on its own. `sectionCohesion` (an injected
|
|
352
|
+
`EmbedFn` silhouette) exists here as an offline triage instrument only;
|
|
353
|
+
`wikify.ts` never imports `src/embed.ts`.
|
|
354
|
+
|
|
355
|
+
### 3.9 Nightly run contract
|
|
356
|
+
|
|
357
|
+
- Trigger: launchd `com.mlx-bun.memory` (`schedule.ts`; `mlx-bun memory
|
|
358
|
+
schedule --at HH:MM`, default 03:00), running `mlx-bun memory synthesize`;
|
|
359
|
+
logs `~/.mlx-bun/logs/memory-synthesis.{out,err}.log`.
|
|
360
|
+
- Scope: only work past each stage's state (watermark / missing downstream
|
|
361
|
+
row / ledger). A normal night is minutes, not hours; throughput only
|
|
362
|
+
matters for the one-time import.
|
|
363
|
+
- Inference: one resident Gemma-4-e4b (§4); a stage's adapter is mounted iff
|
|
364
|
+
`~/.cache/mlx-bun/adapters/memory-<stage>` exists, else base + policy.
|
|
365
|
+
- Every article change is a git commit; the run ends with a summary line.
|
|
366
|
+
- Never started by an agent: the full-corpus import and any GPU training are
|
|
367
|
+
user actions.
|
|
368
|
+
|
|
369
|
+
## 4. The inference seam (`src/memory/model.ts`)
|
|
370
|
+
|
|
371
|
+
One shared runtime: one `RuntimeModel` (Gemma-4-e4b OptiQ-4bit, snapshot
|
|
372
|
+
resolved by globbing for `config.json`), the `memory-chunk` adapter mounted
|
|
373
|
+
once and ACTIVATED per call (`loraState.active`), one in-process
|
|
374
|
+
`BatchScheduler`. Two seams: `callLocal(stage, {system?, user})` (bit-exact
|
|
375
|
+
greedy via the eval runner's raw-forward decode) and `callLocalBatch(stage,
|
|
376
|
+
inputs[])` (order-preserving; batched only when `MLX_BUN_MEMORY_BATCH > 1`
|
|
377
|
+
and N > 1, else the same serial loop). Never auto-downloads; throws with the
|
|
378
|
+
`hf download` hint until the snapshot lands.
|
|
379
|
+
|
|
380
|
+
**Templating.** Each stage renders a `[system?, user]` message array through
|
|
381
|
+
the model's chat template exactly as the server and the trainer's
|
|
382
|
+
prompt-region render do (render with generation prompt → encode → dedupe a
|
|
383
|
+
double BOS; `memoryPromptIds`). This fixed the bring-up defect where the
|
|
384
|
+
chunk adapter — SFT'd with a system turn that Gemma-4 renders as a distinct
|
|
385
|
+
`<|turn>system…<turn|>` block — was decoded with the system segment dropped.
|
|
386
|
+
`tests/memory-templating.test.ts` asserts `memoryPromptIds("chunk", …)` is
|
|
387
|
+
id-identical to a real training row's prompt region. Base stages get concise
|
|
388
|
+
default systems (`DEFAULT_STAGE_SYSTEM`); only `chunk` must match training
|
|
389
|
+
byte-for-byte.
|
|
390
|
+
|
|
391
|
+
**Token budget.** `MAX_OUTPUT_TOKENS = 64_000` is the single backstop; stages
|
|
392
|
+
pass it rather than per-call caps, because a finished answer stops at EOS and
|
|
393
|
+
a cap can only truncate an unfinished one. (The per-stage 4/16/128/2048 caps
|
|
394
|
+
in the original inference-path design are superseded; `extractEntityNamesRaw`
|
|
395
|
+
still defaults to 128 when called directly.)
|
|
396
|
+
|
|
397
|
+
**Batching — implemented, off by default (decision: Josh, 2026-07-01).**
|
|
398
|
+
Measured 2026-06-28 on Gemma-4-e4b OptiQ-4bit, held-out
|
|
399
|
+
`chunk-data-le4000/valid.jsonl` + the live 2096-conversation store, M-series
|
|
400
|
+
GPU: 8 extract-style prompts (~400-token prefills) batched 9345 ms vs serial
|
|
401
|
+
5001 ms (≈1.9× slower, 8/8 exact); 8 short replies batched 2085 ms vs 1067 ms
|
|
402
|
+
(≈2× slower, 7/8 match — one documented near-tie divergence); only 16 short
|
|
403
|
+
uniform one-liners won (≈1.2× faster). The warm uniform chunk workload on the
|
|
404
|
+
M1 Max 32 GB measured 0.607 vs 0.357 s/chunk (~1.7× slower). Root cause: the
|
|
405
|
+
scheduler pads heterogeneous prefills to the batch max, losing to one
|
|
406
|
+
efficient single-sequence prefill per row. The real efficiency lever for
|
|
407
|
+
daily use is load-once (the shared runtime above; a persistent-server route
|
|
408
|
+
remains open, §9), not batching.
|
|
409
|
+
|
|
410
|
+
**Adapter constraint.** `loraState.active` is a single global field read per
|
|
411
|
+
forward, so a batch is necessarily single-adapter; `callLocalBatch` is
|
|
412
|
+
per-stage and stage→adapter is fixed. The seam must never be shared with a
|
|
413
|
+
live server process.
|
|
414
|
+
|
|
415
|
+
## 5. Target design: the BUCKET layer (settled with Josh 2026-07-01, not built)
|
|
416
|
+
|
|
417
|
+
**The Wikipedia-editor analogy.** A news story is reported seven times in a
|
|
418
|
+
day, each report carrying a little different information; an editor who
|
|
419
|
+
heard ALL of them incorporates everything into every article the story
|
|
420
|
+
affects. Conversations are the news shows, topics (chunks) are the stories,
|
|
421
|
+
and the **bucket is the editor's brain** — where everything reported TODAY
|
|
422
|
+
about THAT STORY accumulates before any article is touched.
|
|
423
|
+
|
|
424
|
+
**A bucket is keyed by the STORY, not by a subject.** Worked example: the
|
|
425
|
+
story "2026 Lincoln Memorial Reflecting Pool controversy" has no article of
|
|
426
|
+
its own and may never get one, but it affects three: *Lincoln Memorial
|
|
427
|
+
Reflecting Pool*, *Second presidency of Donald Trump*, *John J. Cafaro*. Each
|
|
428
|
+
receives the facet relevant to it. Bucket ≠ article is structural: articles
|
|
429
|
+
are THINGS, buckets are STORIES, story→things is many-to-many. Buckets are
|
|
430
|
+
emergent (never a predefined list) and short-lived relative to articles.
|
|
431
|
+
|
|
432
|
+
Target stage order:
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
SEGMENT → BUCKET → RESOLVE → SYNTHESIZE (delta-at-once) → RECONCILE → LINK → NORMALIZE → EDITORIAL
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
- **BUCKET** — group chunks by story: normalise/compare labels
|
|
439
|
+
deterministically first, a binary "same story? yes/no" for near-misses, a
|
|
440
|
+
new-bucket proposal for genuinely new stories. `_captured` remains the
|
|
441
|
+
catch-all so nothing is dropped.
|
|
442
|
+
- **RESOLVE** — per non-empty bucket delta (all new chunks since the last
|
|
443
|
+
run, TOGETHER): "which articles does this story affect?" Existing article →
|
|
444
|
+
UPDATE (section-route the delta's facet for that article); missing →
|
|
445
|
+
CREATE the subject article (a THING, never an article named after the
|
|
446
|
+
story). The as-built entity-keyed ROUTE becomes RESOLVE.
|
|
447
|
+
- **SYNTHESIZE, one edit per (bucket, article)** — the cardinal rule. Never
|
|
448
|
+
patch a section from one chunk and re-patch it from the next five minutes
|
|
449
|
+
later: sequential single-chunk edits overwrite each other, churn
|
|
450
|
+
citations, and produce patchwork prose. The delta arrives aggregated; the
|
|
451
|
+
model rewrites one section once, weaving everything in, resolving
|
|
452
|
+
contradictions within the delta toward the latest chunk. Edit mechanics
|
|
453
|
+
stay as built (replacement section, code performs the write, same gate).
|
|
454
|
+
Two buckets touching the SAME section of one article fold
|
|
455
|
+
chronologically; the editorial pass smooths the seam.
|
|
456
|
+
|
|
457
|
+
As-built vs target, so nobody re-derives it:
|
|
458
|
+
|
|
459
|
+
| Target (2026-07-01) | As built (2026-08-23) |
|
|
460
|
+
| --- | --- |
|
|
461
|
+
| Story-keyed BUCKET stage between SEGMENT and article fan-out | No bucket stage; `buckets`/`chunk_buckets` hold only `_captured` |
|
|
462
|
+
| RESOLVE: bucket delta → affected articles | ROUTE: chunk-entity surfaces → articles (`route.ts`) |
|
|
463
|
+
| One edit per (bucket, article) per run | One PATCH per (chunk, section), chronological |
|
|
464
|
+
| RECONCILE every night over every article | RECONCILE over articles touched by this run's patches |
|
|
465
|
+
| EDITORIAL over touched articles (cadence open) | `wikifyVault` over every article every run |
|
|
466
|
+
|
|
467
|
+
## 6. The read path (design; user-facing details in `docs/reference/memory.md`)
|
|
468
|
+
|
|
469
|
+
The read path is deliberately trivial — all the acceptance pressure is on
|
|
470
|
+
the write side keeping each article a good, current account. FIND → READ →
|
|
471
|
+
ANSWER in small reads, never a context dump: find the one article (name /
|
|
472
|
+
alias / category / a `[[link]]` hop), open its TOC, read the ONE relevant
|
|
473
|
+
section, answer from the user's recorded position there. Silent-colleague
|
|
474
|
+
contract (ported from Lucien): look up before answering; each article is the
|
|
475
|
+
consolidated position, don't reconstruct from raw history; speak as a
|
|
476
|
+
continuation, never "per the wiki…".
|
|
477
|
+
|
|
478
|
+
- Tools (`src/memory/tools.ts`, registered by the shared pi surface for
|
|
479
|
+
terminal and web, read-only, auto-allowed): `memory_resolve`,
|
|
480
|
+
`memory_category`, `memory_read` (TOC + lead by default; full text only on
|
|
481
|
+
request), `memory_section` (the default read), `memory_links`,
|
|
482
|
+
`memory_infobox` (readable content, not a query), `memory_list`,
|
|
483
|
+
`memory_status`, `memory_search` (last-resort substring fallback). There is
|
|
484
|
+
deliberately no infobox-field query tool. mlx-bun's own docs are a
|
|
485
|
+
separate `reference_*` surface, never mixed into personal memory.
|
|
486
|
+
- Navigation index (`src/memory/query.ts`): mtime-incremental in-memory maps
|
|
487
|
+
(alias → stem, category/series/kind/type → stems, infobox, lead, link
|
|
488
|
+
graph) mirroring the derived tables; zero embedding calls by contract.
|
|
489
|
+
- Exposure: tools and the bundled memory skill appear only when the vault
|
|
490
|
+
exists; `memoryIndexHint()` adds a one-line presence hint, never a title
|
|
491
|
+
dump. Memory is for personal continuity, not weather, public facts, or
|
|
492
|
+
ordinary coding tasks.
|
|
493
|
+
- Acceptance budget (the bar Lucien's traces failed at 33–150 KB per query,
|
|
494
|
+
one 671-line blob read up to 42× in a query): mean context < 5 KB (8 KB
|
|
495
|
+
hard ceiling), no single read > 2 KB, `getEmbedCounter() == 0`, local
|
|
496
|
+
only, silent. Harness: `scripts/memory/eval-northstar.ts` over the frozen
|
|
497
|
+
`scripts/memory/northstar-queries.json` (Q1–Q6; Q6 is the negative
|
|
498
|
+
control), graded by `scripts/memory/judge-answer.ts`; traversal proof
|
|
499
|
+
`scripts/memory/north-star-traversal.ts`.
|
|
500
|
+
|
|
501
|
+
## 7. Adapters and training
|
|
502
|
+
|
|
503
|
+
One base model for every stage. Per-stage adapters are product assets (the
|
|
504
|
+
creator trains them, publishes to Hugging Face, `memory init` may offer to
|
|
505
|
+
download); they never get write authority — they produce candidates, the
|
|
506
|
+
gates decide.
|
|
507
|
+
|
|
508
|
+
| stage string | task | adapter |
|
|
509
|
+
| --- | --- | --- |
|
|
510
|
+
| `chunk` | one conversation → single-topic chunks + labels | **`memory-chunk` = `e4b-chunk-300` (exists, the only trained adapter)** |
|
|
511
|
+
| `entity` | one chunk → the things it is about | base + `Entities.md` (`memory-entity` only on a measured recall miss) |
|
|
512
|
+
| `route` | binary "same thing?" / "engages as subject?" | base |
|
|
513
|
+
| `section` | binary "does this chunk update THIS section?" / name a new one | base (`memory-section` only if the binary misfires) |
|
|
514
|
+
| `synthesis` | draft one section / integrate one chunk into one section / reconcile | base (`memory-synthesis` is the highest-value adapter to train) |
|
|
515
|
+
| `editor` | tighten one section / refresh an infobox / summarise a split | base (`memory-editor` if base misfires) |
|
|
516
|
+
|
|
517
|
+
Staged LoRA decision, per stage: measure the base + inlined policy on the
|
|
518
|
+
stage's own judge first; train only on a measured miss; pick checkpoints by
|
|
519
|
+
the task judge, never validation loss. Recipe: `scripts/examples/chunk-finetune.ts`
|
|
520
|
+
(sft, rank 16, lr 1e-5, seq 8192, `ops.sdpa`; e4b needs the segmented-backward
|
|
521
|
+
path — `SEG=2` as `e4b-chunk-300` was trained; see
|
|
522
|
+
`docs/design/orpo-training.md`). Training data uses the
|
|
523
|
+
trainer's `messages` row shape with loss masked to the assistant turn.
|
|
524
|
+
Section-granular synthesis gold can be mined from Lucien's structured tables
|
|
525
|
+
plus `~/Dreaming` git history (chunk identity from `chunks`/`chunk_buckets`/
|
|
526
|
+
`synthesized_bucket_chunks`, section before/after from integration commits) —
|
|
527
|
+
never from footnote parsing. All training is a user action.
|
|
528
|
+
|
|
529
|
+
Recorded chunk-adapter numbers (`reports/orpo-chunk-paper/research-journal.md`,
|
|
530
|
+
via `scripts/examples/chunk-eval.ts`): `e4b-chunk-300` purity 92.2 /
|
|
531
|
+
cohesion 87.8 vs base e4b 99.5 / 58.8; the e4b metric is purity × cohesion.
|
|
532
|
+
The chunk eval score is well-formedness, not accuracy — see the memory note
|
|
533
|
+
"chunk-eval 95.10 = format, not accuracy".
|
|
534
|
+
|
|
535
|
+
## 8. Evaluation methodology (beside the system)
|
|
536
|
+
|
|
537
|
+
- **Lucien bucket-gold is NOT the write-path oracle.** Its 379-bucket /
|
|
538
|
+
385-article topic-bin taxonomy (245 `X_and_Y` bins, 0 infoboxes) is
|
|
539
|
+
exactly what this pipeline replaces; bucket-F1 / Jaccard against it are
|
|
540
|
+
routing-instrument numbers, never a pipeline-health gate.
|
|
541
|
+
- **Cloud LLM-judge on real output + hand-curated gold.** Quality is judged
|
|
542
|
+
by a strong cloud model reading END articles (the article the user reads
|
|
543
|
+
next morning, after every stage has run — not intermediate drafts), against
|
|
544
|
+
`goldens/dreaming-entities-gold.json` (hand-curated variant groups and
|
|
545
|
+
notable entities, grounded by reading `~/Dreaming` and live chunks; NOT
|
|
546
|
+
derived from bucket-gold). The judge is never in the hot path.
|
|
547
|
+
- **Metrics that mean something:** topic aggregation (many conversations →
|
|
548
|
+
one article), coverage (0 engaged-with things lost even as article count
|
|
549
|
+
drops), structural invariants (title is a thing, infobox present and
|
|
550
|
+
resolvable, footnote bijection, every claim cited), gate pass-rate, and
|
|
551
|
+
the read-path byte/embedding budgets. Do not measure articles per
|
|
552
|
+
conversation — there is no conv→article link.
|
|
553
|
+
- **Embeddings as instruments only.** They measure cohesion/dispersion well
|
|
554
|
+
(silhouette ρ≈0.68 vs the LLM judges, per-conversation) and purity poorly
|
|
555
|
+
(ρ≈0.32) — so purity rides on the chunker, never on cosine geometry. The
|
|
556
|
+
P4 label-proxy routing measured a pessimistic ~39% recall@12 on chunk
|
|
557
|
+
labels, which is why ENTITY-EXTRACT reads full chunk text.
|
|
558
|
+
|
|
559
|
+
Instruments, all under `scripts/memory/` (moved 2026-08-23; Lucien read-only
|
|
560
|
+
throughout):
|
|
561
|
+
|
|
562
|
+
| script | what it measures |
|
|
243
563
|
| --- | --- |
|
|
244
|
-
|
|
|
245
|
-
|
|
|
246
|
-
|
|
|
247
|
-
|
|
|
248
|
-
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
564
|
+
| `bucket-cohesion-signal.ts` | embedding shortlist recall ceiling chunk→bucket, per bucket-size bin (the bucketing-stage foundation check) |
|
|
565
|
+
| `chunk-embedding-signal.ts` · `chunk-judge-correlate.ts` | boundary-local embedding features vs the two LLM chunk judges |
|
|
566
|
+
| `eval-name-recall.ts` · `dreaming-lex.ts` | lexical (trigram + token-overlap) shortlist recall over names, no model |
|
|
567
|
+
| `eval-route.ts` | no-vector routing proof; `--phase embed` and `--phase route` run as separate processes so the embedder and e4b are never co-resident |
|
|
568
|
+
| `eval-entity-extract.ts` | precision/recall/F1 + canonicalisation rate for ENTITY-EXTRACT |
|
|
569
|
+
| `eval-section-route.ts` | per-pair accuracy + section-set Jaccard on frozen proxy gold; new-section-not-drop |
|
|
570
|
+
| `eval-patch.ts` | only-that-section-changed + self-healing scenarios, judged on output |
|
|
571
|
+
| `eval-wikify-split.ts` · `p8-judge-wikify.ts` · `wikify-smoke.ts` | split/series/merge/Talk mechanics; cloud-judge fixture for improve-not-degrade |
|
|
572
|
+
| `audit-bootstrap.ts` · `eval-coverage.ts` | structural audit of a bootstrap; migration parity against the notable-entity gold |
|
|
573
|
+
| `north-star-traversal.ts` · `eval-northstar.ts` · `judge-answer.ts` · `northstar-queries.json` | read-path proof, acceptance harness, grader |
|
|
574
|
+
| `segment-smoke.ts` · `dreaming-create-smoke.ts` · `dreaming-coldstart-smoke.ts` · `dreaming-stages-independent.ts` | wiring smokes (real adapter; one entity; whole DAG; stage independence, model-free) |
|
|
575
|
+
| `dreaming-selfheal-demo.ts` | the timestamp-ordered self-healing demonstration |
|
|
576
|
+
| `dreaming-full-run.ts` · `dreaming-slice-select.ts` · `dreaming-slice-run.ts` · `dreaming-slice-inventory.ts` · `dreaming-chunk-diag.ts` | the resumable full-corpus import driver (user-launched, writes `~/.mlx-bun/wiki-full`, cursor `~/.mlx-bun/full-run-cursor.txt`) and its slice tools |
|
|
577
|
+
| `mine-gold-entities.ts` | the frozen entity vocabulary (`goldens/entities.json`) from `~/Dreaming` titles/lead bolds/bucket names |
|
|
578
|
+
| `eval-pi-memory-fixation.ts` | the pi surface exposes memory only when enabled and names the negative cases |
|
|
579
|
+
|
|
580
|
+
**Contradiction with the no-embeddings principle, recorded rather than
|
|
581
|
+
hidden:** `wikify.ts sectionCohesion` (injected `EmbedFn`), the
|
|
582
|
+
`bucket-cohesion-signal` / `chunk-embedding-signal` / `chunk-judge-correlate`
|
|
583
|
+
scripts and `eval-route.ts --phase embed` still use an embedder. None of them
|
|
584
|
+
is on the pipeline or read path (`src/memory/` never imports `src/embed.ts`;
|
|
585
|
+
the tripwire asserts 0). The design rule as settled 2026-07-01 says "no
|
|
586
|
+
embeddings anywhere in the project"; the code keeps them as offline
|
|
587
|
+
instruments. Deleting them is an open decision (§9), not a silent rewrite.
|
|
588
|
+
|
|
589
|
+
## 9. Open work (verified against `src/memory/` 2026-08-23)
|
|
590
|
+
|
|
591
|
+
Ordered. None of it touches the user's real vault (`~/.mlx-bun/wiki`) without
|
|
592
|
+
the promotion step.
|
|
593
|
+
|
|
594
|
+
1. **Wire ingest into the nightly run.** `ingestSessions` has no caller
|
|
595
|
+
outside tests; `runSynthesis` assumes the corpus is already in the store.
|
|
596
|
+
Without this the launchd job cannot fold in new pi sessions. Sequence:
|
|
597
|
+
ingest → the existing DAG; watermark per source already exists.
|
|
598
|
+
2. **Bucket layer** (§5): story-keyed BUCKET stage, RESOLVE, delta-at-once
|
|
599
|
+
synthesis replacing the per-chunk patch loop (not wrapping it). The
|
|
600
|
+
`buckets`/`chunk_buckets` tables already exist.
|
|
601
|
+
3. **Nightly DAG order**: RECONCILE over every article (today: touched
|
|
602
|
+
stems only) and a single NORMALIZE/EDITORIAL closing pass in the settled
|
|
603
|
+
order.
|
|
604
|
+
4. **Persistent-server inference routing**: route memory generation through
|
|
605
|
+
the resident server when one is running (load-once for daily use), with
|
|
606
|
+
the in-process runtime as the no-server fallback. Batching is not the
|
|
607
|
+
lever (§4).
|
|
608
|
+
5. **Chunk user-turn drift**: `CHUNK_PROMPT` still differs from the trained
|
|
609
|
+
user turn (an added no-copy line; 2 inlined Meta pages vs 8 in training;
|
|
610
|
+
abstracted label examples; the training vault-path line). Either
|
|
611
|
+
reconcile the prompt to training or retrain `e4b-chunk-300` on the live
|
|
612
|
+
prompt — pick one, don't stay half-aligned. Re-segmenting conversations
|
|
613
|
+
chunked under the old user-only template is principled but low-urgency
|
|
614
|
+
(old output was valid in-range).
|
|
615
|
+
6. **Promote + schedule**: after the import (`~/.mlx-bun/wiki-full`) is
|
|
616
|
+
judged good on a broad, diverse cloud-judged sample — `reindex`,
|
|
617
|
+
`mlx-bun memory link`, browse in Obsidian — point `~/.mlx-bun/wiki` at
|
|
618
|
+
it and enable the nightly job. The `Reference/` symlinks into the repo
|
|
619
|
+
are non-portable; drop them for the real personal vault.
|
|
620
|
+
7. **Known quality fixes**: schematic-prompt leaks (<1% of articles), run-on
|
|
277
621
|
leads, `owned:` framing on abstract concepts (reframe the lead spec per
|
|
278
|
-
subject kind)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
622
|
+
subject kind), and stale in-code comments that still describe the dead
|
|
623
|
+
"≥3 chunks or owned/decided" CREATE rule (`synthesize.ts` header;
|
|
624
|
+
`prompts.ts` M1 stub constants) — the live rule is
|
|
625
|
+
`RECURRENCE_THRESHOLD = 2` in `route.ts`.
|
|
626
|
+
8. **Per-stage adapters** (§7), each a user-launched training run gated on a
|
|
627
|
+
measured base miss: `memory-synthesis` first (RECONCILE logs
|
|
628
|
+
"UNRESOLVED … a memory-synthesis LoRA would close it" when the base model
|
|
629
|
+
leaves a stale present-tense assertion), then section, entity, editor.
|
|
630
|
+
Prerequisite: give `chunk-finetune.ts` a `TASK` selector defaulting
|
|
631
|
+
DATA/ADAPTER per stage and an e4b (not MiniCPM5) default model.
|
|
632
|
+
9. **Embedding residue** (§8): decide whether `sectionCohesion` and the
|
|
633
|
+
embedding signal scripts stay as instruments or go.
|
|
634
|
+
10. **Jobs-runner integration**: move `memory synthesize` onto the jobs
|
|
635
|
+
runner with SSE progress once manual synthesis is boring.
|
|
636
|
+
|
|
637
|
+
## 10. Decisions overridden (explicit, so no agent re-derives them)
|
|
638
|
+
|
|
639
|
+
| Earlier statement | Superseded by |
|
|
640
|
+
| --- | --- |
|
|
641
|
+
| Personal-notability checklist; CREATE gate "≥3 chunks OR owned/decided, else PARK as trivia"; ≤40-article first-run cap (master plan P1-T5, P5-T4, R5, P9-T3) | **No notability filter.** Everything surfaces; `_captured` keeps the tail searchable; recurrence (2 chunks) or subject engagement earns an article; thin subjects → stubs. |
|
|
642
|
+
| Buckets demoted to "optional staging, may ship empty" (master plan L4, write-pipeline-entity) | **Buckets are first-class** story-keyed accumulators between chunks and articles (§5). |
|
|
643
|
+
| Embeddings as routing narrower / offline instruments (bucketing-stage, memory-synthesis section-routing, master plan P4/P8-T4) | **No embeddings in the pipeline**; the tripwire is permanent. Residual instruments are catalogued in §8 pending deletion. |
|
|
644
|
+
| Routing / section-route acceptance gated on Lucien bucket-F1 / Jaccard (P4-T2, P7-T1) | Model-selection evals live outside the design; pipeline health is judged on real END output by a cloud judge, never Lucien's bin taxonomy. |
|
|
645
|
+
| Cross-linking + infobox work assigned to periodic WIKIFY (P8) | LINK and RECONCILE are nightly stages; wikify is the readability pass. |
|
|
646
|
+
| Whole-article synthesis (Lucien `synthesize-update`) and per-chunk sequential patches (as built) | One replacement section per (bucket, article) per run, code performs the write (§5). |
|
|
647
|
+
| Per-stage `maxTokens` caps 4/16/128/2048 (inference-path design) | One `MAX_OUTPUT_TOKENS` backstop; never cap below it. |
|
|
648
|
+
| Batching as the import throughput lever | Measured slower for the real workload; default serial; load-once is the lever. |
|
|
649
|
+
| Turso / vector-capable store evaluation | Moot without embeddings; bun:sqlite stays. |
|
|
650
|
+
|
|
651
|
+
## 11. Open questions
|
|
652
|
+
|
|
653
|
+
- **When does a `_captured` chunk graduate?** Re-scan `_captured` nightly for
|
|
654
|
+
subjects that have since accumulated related chunks, or only when a new
|
|
655
|
+
bucket's name matches? (Today: promotion happens when ROUTE recomputes and
|
|
656
|
+
the subject recurs.)
|
|
657
|
+
- **Editorial cadence.** Every night over every article (as built), or
|
|
658
|
+
touched articles nightly plus a slower full-vault sweep?
|
|
659
|
+
- **Provisional / temporal facts.** A convention (e.g. "as of YYYY-MM" tied
|
|
660
|
+
to the citation date) so "work set to begin July" updates cleanly to
|
|
661
|
+
"began / completed" rather than contradicting.
|
|
662
|
+
- **Domain vs specific granularity.** ENTITY-EXTRACT emits both; the
|
|
663
|
+
summary-style split decides what becomes its own page. Is that enough?
|
|
664
|
+
- **Bootstrap on a stronger model?** Is first creation good enough locally,
|
|
665
|
+
or is the one-time import the one place a stronger model earns its cost?
|
|
666
|
+
|
|
667
|
+
## History
|
|
668
|
+
|
|
669
|
+
- 2026-06-19 — M0 landed: vault, read tools, CLI, launchd scheduling
|
|
670
|
+
(`docs/design/dreaming-nightly-pipeline.md`); synthesis a safe no-op stub.
|
|
671
|
+
- 2026-06-26 — M1 design (`docs/design/dreaming-nightly-pipeline.md`): pointer DB, create/update
|
|
672
|
+
split, wikify as its own node; bucketing decomposition
|
|
673
|
+
(`docs/design/dreaming-nightly-pipeline.md`); entity-keyed routing (`docs/design/dreaming-nightly-pipeline.md`).
|
|
674
|
+
- 2026-06-28 — Pipeline built end-to-end on real data; stage workers,
|
|
675
|
+
chronological order, self-healing, LINK stage, templating fix; batching
|
|
676
|
+
measured and shelved (`docs/design/dreaming-nightly-pipeline.md`); full import resumed
|
|
677
|
+
from 720/2096 into `~/.mlx-bun/wiki-full`.
|
|
678
|
+
- 2026-07-01 — Settled with Josh: no notability filter, no embeddings,
|
|
679
|
+
buckets are stories, one edit per (bucket, article), replacement-section
|
|
680
|
+
edit mechanics; `MLX_BUN_MEMORY_BATCH` default 1. This doc became
|
|
681
|
+
canonical.
|
|
682
|
+
- 2026-08-23 — Consolidated the source docs into this one; scripts moved to
|
|
683
|
+
`scripts/memory/`; every code claim re-verified; ingest-not-wired and
|
|
684
|
+
embedding-residue contradictions recorded.
|