Context
Operator direction, 2026-07-30: "if chroma and better-sqlite now run inside docker, package.json (neo root level) no longer needs it. probably more now obsolete dependencies. vba." Filed as an audit-and-decide ticket rather than a removal ticket, because the V-B-A showed the two named packages are not equivalent and the blocker is not the one the framing assumed.
Live latest-open sweep at 2026-07-30T23:05Z: searched open issues for dependency / devDependencies / better-sqlite3 / chromadb; nothing equivalent (#14192 and #14079 are Chroma store concerns, not dependency placement). A2A claim sweep at the same time: no competing claim. Sweep caveat: ChromaDB is down (see #16167), so semantic retrieval was unavailable; live-GitHub-and-source only, no semantic-memory miss claimed.
What the V-B-A established
dependencies is empty — 0 keys. Everything heavy is in devDependencies (45 entries). That placement is already correct and load-bearing, and it is why the flexibility the operator wants already partly exists:
| install surface |
gets the heavy deps? |
native compile |
npx neo-app@latest workspace (declares neo.mjs as a dependency — buildScripts/create/app.mjs:60) |
no — npm never installs a dependency's devDependencies |
none |
| Body-only consumer |
no |
none |
contributor cloning neomjs/neo |
yes |
yes |
So exactly one audience pays the compile cost, and the operator's Body-only-user rationale for dev placement is already satisfied by construction.
The two named packages are not comparable:
chromadb (^3.5.0) — pure-JS HTTP client, no native build step. 12 real importers, 9 non-test: 3 container-side managers, 5 ad-hoc maintenance scripts, 1 test-isolation helper. No host daemon. Removing it saves install weight and zero compile pain.
better-sqlite3 (^12.11.1) — the native one, and the actual Windows prize. 56 real importers: 26 non-test, 30 test. Note a static-import grep undercounts it; several call sites use dynamic await import().
The blocker is the test surface, not the daemons. Daemon-side importers are being handled elsewhere: #16180 removes the wake path, #16202 relocates the NL recorder. But npm install pulls devDependencies regardless, so 30 specs needing a local SQLite driver keeps the native compile for every contributor no matter what the daemons do.
The Problem
Two distinct problems wear one label:
- Nobody knows which of the 45 devDependencies survive the cut. Only the two the operator named have been examined. "Probably more now obsolete" is a well-founded hunch with no census behind it, and a removal PR built on a hunch will either miss packages or break a lane.
- There is one install tier for two audiences. A Body-contributor and a Brain-contributor run the same
npm install despite needing different things. That is the same Body/Brain split already applied to consumers — just never applied to contributors.
Framing "obsolete" is slightly wrong and worth correcting: post-cut these packages are still needed by Brain work and by the test suite. They are correctly placed and still compiled. The missing thing is a tier, not a deletion.
The Architectural Reality
package.json — dependencies: {}, devDependencies with 45 entries.
ai/configBase.mjs, ai/graph/storage/SQLite.mjs, ai/services/memory-core/**, ai/services/knowledge-base/**, ai/mcp/server/memory-core/helpers/** — container-side better-sqlite3 importers; correct where they are post-cut.
ai/daemons/wake/queries.mjs — host-side importer, owned by #16180.
ai/services/neural-link/RecorderService.mjs — host-side importer, owned by #16202.
ai/scripts/{maintenance,migrations,diagnostics,fleet}/** — ~15 real importers, invoked ad hoc; post-cut they would target a graph no longer on the host (see OQ3).
- 30 spec files under
test/playwright/** import better-sqlite3 for real.
buildScripts/create/app.mjs:60 — generated apps declare npmPackages: ['neo.mjs'], which is what insulates consumers.
The Fix
- Census. Classify all 45 devDependencies by whether a real importer (static or dynamic) survives the cut, and on which side — container, host, ad-hoc script, test, build. Mechanical, and it is the deliverable that makes any later removal safe.
- Report the compile-cost subset separately: which entries have native build steps, since those are the only ones that cause the pain the operator actually cares about.
- Decide the install tier (OQ1) — the architectural half.
- Remove only what the census proves unreachable, in a follow-up, once 1–3 land.
Open Questions
- OQ1 — what is the install-tier mechanism? Candidates: (a)
optionalDependencies plus capability gating so absent natives degrade rather than fail; (b) two documented install paths (npm install for Body work, an opt-in script for Brain work); (c) leave one tier and accept the compile. Falsifier for (a): capability gating only works if every consumer checks — a bare import of an absent optional dependency still throws, so this needs a real audit of call sites, not a package.json edit. Falsifier for (c): it forfeits the stated Windows win, which is the reason parity existed.
- OQ2 — how do the 30 test importers get satisfied without a local driver? Run those specs against a container graph, gate them behind the Brain tier, or keep the driver for tests only (which reinstates the compile). This is the load-bearing question and OQ1 depends on it.
- OQ3 — do the ~15 ad-hoc scripts move into the container, or reach the graph over HTTP? They are invoked deliberately, so requiring a Brain-tier install for them may be acceptable — but post-cut they point at a graph that no longer lives on the host, which is a quieter version of the divergence #16167 exists to prevent.
- OQ4 — is
chromadb worth removing on its own? It is genuinely removable once its 5 maintenance scripts reach Chroma over HTTP (which is what the client already does), but the payoff is install weight only. Possibly a cheap standalone win, possibly not worth a separate PR.
Acceptance Criteria
Out of Scope
- Removing any dependency. This ticket produces the evidence and the tier decision; removal follows.
- The host-side importers already owned: #16180 (wake) and #16202 (NL recorder).
- Chroma store size concerns — #14079, #14192.
dependencies placement. It is empty and correct; consumers are already insulated.
Avoided Traps
- "They're obsolete, delete them." They are correctly placed and still needed by Brain work and 30 specs. The problem is the absence of a tier, not the presence of the packages.
- Treating
chromadb and better-sqlite3 as one job. One is a pure-JS HTTP client with no compile; the other is the native module that is the entire point. Bundling them hides which work delivers the win.
- Using a static-import grep as the census. Verified to undercount —
SQLite.mjs and the NL recorder both use dynamic await import() and were invisible to a ^import .*'pkg' pattern.
- Counting
git grep -l <pkg> as importers. It matches comments and strings; the raw count over-reported by roughly 40% on one package and under-reported on another once test/** was included.
Related
- #16167 — the cut that makes the container-side importers correct
- #16180 — graphless wake receiver (removes the wake-path importer)
- #16202 — NL recorder data relocation (removes the other host importer)
- #16040 — deployment-guide rewrite, a natural consumer of the install-tier decision
- D#16193 — contributor provisioning ideation; OQ1 overlaps its "what is a contributor's target" question
Origin Session ID: 0a7f5f1d-cf12-4698-984c-17b64eea5178
Retrieval Hint: 45 devDependencies census real importers dynamic await import better-sqlite3 native compile contributor install tier optionalDependencies capability gating chromadb pure JS
Context
Operator direction, 2026-07-30: "if chroma and better-sqlite now run inside docker, package.json (neo root level) no longer needs it. probably more now obsolete dependencies. vba." Filed as an audit-and-decide ticket rather than a removal ticket, because the V-B-A showed the two named packages are not equivalent and the blocker is not the one the framing assumed.
Live latest-open sweep at 2026-07-30T23:05Z: searched open issues for dependency / devDependencies /
better-sqlite3/chromadb; nothing equivalent (#14192 and #14079 are Chroma store concerns, not dependency placement). A2A claim sweep at the same time: no competing claim. Sweep caveat: ChromaDB is down (see #16167), so semantic retrieval was unavailable; live-GitHub-and-source only, no semantic-memory miss claimed.What the V-B-A established
dependenciesis empty — 0 keys. Everything heavy is indevDependencies(45 entries). That placement is already correct and load-bearing, and it is why the flexibility the operator wants already partly exists:npx neo-app@latestworkspace (declaresneo.mjsas a dependency —buildScripts/create/app.mjs:60)neomjs/neoSo exactly one audience pays the compile cost, and the operator's Body-only-user rationale for
devplacement is already satisfied by construction.The two named packages are not comparable:
chromadb(^3.5.0) — pure-JS HTTP client, no native build step. 12 real importers, 9 non-test: 3 container-side managers, 5 ad-hoc maintenance scripts, 1 test-isolation helper. No host daemon. Removing it saves install weight and zero compile pain.better-sqlite3(^12.11.1) — the native one, and the actual Windows prize. 56 real importers: 26 non-test, 30 test. Note a static-import grep undercounts it; several call sites use dynamicawait import().The blocker is the test surface, not the daemons. Daemon-side importers are being handled elsewhere: #16180 removes the wake path, #16202 relocates the NL recorder. But
npm installpulls devDependencies regardless, so 30 specs needing a local SQLite driver keeps the native compile for every contributor no matter what the daemons do.The Problem
Two distinct problems wear one label:
npm installdespite needing different things. That is the same Body/Brain split already applied to consumers — just never applied to contributors.Framing "obsolete" is slightly wrong and worth correcting: post-cut these packages are still needed by Brain work and by the test suite. They are correctly placed and still compiled. The missing thing is a tier, not a deletion.
The Architectural Reality
package.json—dependencies: {},devDependencieswith 45 entries.ai/configBase.mjs,ai/graph/storage/SQLite.mjs,ai/services/memory-core/**,ai/services/knowledge-base/**,ai/mcp/server/memory-core/helpers/**— container-sidebetter-sqlite3importers; correct where they are post-cut.ai/daemons/wake/queries.mjs— host-side importer, owned by #16180.ai/services/neural-link/RecorderService.mjs— host-side importer, owned by #16202.ai/scripts/{maintenance,migrations,diagnostics,fleet}/**— ~15 real importers, invoked ad hoc; post-cut they would target a graph no longer on the host (see OQ3).test/playwright/**importbetter-sqlite3for real.buildScripts/create/app.mjs:60— generated apps declarenpmPackages: ['neo.mjs'], which is what insulates consumers.The Fix
Open Questions
optionalDependenciesplus capability gating so absent natives degrade rather than fail; (b) two documented install paths (npm installfor Body work, an opt-in script for Brain work); (c) leave one tier and accept the compile. Falsifier for (a): capability gating only works if every consumer checks — a bareimportof an absent optional dependency still throws, so this needs a real audit of call sites, not apackage.jsonedit. Falsifier for (c): it forfeits the stated Windows win, which is the reason parity existed.chromadbworth removing on its own? It is genuinely removable once its 5 maintenance scripts reach Chroma over HTTP (which is what the client already does), but the payoff is install weight only. Possibly a cheap standalone win, possibly not worth a separate PR.Acceptance Criteria
Out of Scope
dependenciesplacement. It is empty and correct; consumers are already insulated.Avoided Traps
chromadbandbetter-sqlite3as one job. One is a pure-JS HTTP client with no compile; the other is the native module that is the entire point. Bundling them hides which work delivers the win.SQLite.mjsand the NL recorder both use dynamicawait import()and were invisible to a^import .*'pkg'pattern.git grep -l <pkg>as importers. It matches comments and strings; the raw count over-reported by roughly 40% on one package and under-reported on another oncetest/**was included.Related
Origin Session ID: 0a7f5f1d-cf12-4698-984c-17b64eea5178
Retrieval Hint:
45 devDependencies census real importers dynamic await import better-sqlite3 native compile contributor install tier optionalDependencies capability gating chromadb pure JS