What happened?
packages/pi-plugin/package.json declares typebox as a regular runtime dependency:
"dependencies": {
...
"typebox": "^1.3.1",
"zod": "^4.1.8"
}
The host this plugin runs inside pins the same library to an exact version — @earendil-works/pi-agent-core, @earendil-works/pi-ai and @earendil-works/pi-coding-agent all declare "typebox": "1.3.27".
Two things follow from that:
^1.3.1 resolves to the newest 1.x, so installing the plugin pulls a second copy into the tree. In my Pi extension install (~/.pi/agent/npm/pnpm-lock.yaml) the typebox that ends up hoisted is magic-context's:
'@cortexkit/pi-magic-context@0.42.6(@types/node@26.6.2)':
dependencies:
typebox: 1.3.34
- The build inlines it.
dist/index-r918mh6w.js ships TypeBox's runtime, with bundler comments keeping the source path:
// ../../node_modules/.bun/typebox@1.3.7/node_modules/typebox/build/system/memory/metrics.mjs
// ../../node_modules/.bun/typebox@1.3.7/node_modules/typebox/build/guard/guard.mjs
So the plugin executes its own copy (built against whatever version bun resolved at build time) while Pi executes 1.3.27 — two different instances of the same library inside one process, plus a third version installed next to it in node_modules.
Expected
TypeBox is part of the host API surface: extension code hands TSchema values to Pi's tool registration and validation, so schema objects cross the plugin/host boundary. It should be host-provided, the way @earendil-works/* already is:
"peerDependencies": {
"@earendil-works/pi-tui": ">=0.80.2",
"@earendil-works/pi-coding-agent": ">=0.80.2",
"typebox": ">=1.3.1"
},
"devDependencies": {
"typebox": "1.3.27"
}
with the dev-only copy pinned to whatever Pi currently pins, so local type-checking matches the runtime. Marking the peer optional (peerDependenciesMeta) is fine if you would rather not require it — the point is that it should not be a hard runtime dependency of the published plugin, nor bundled into dist/.
Impact
- Three typebox instances per install: one in
node_modules, one bundled in dist/, and neither is the version Pi runs.
- Plugin and host can drift apart silently; Pi pins its own exactly, so nothing keeps them aligned.
- Extensions installed alongside that declare typebox correctly as a peer dependency inherit
1.3.34 from this dependency edge instead of Pi's pinned 1.3.27. That is how I ran into it: a second extension in the same install ended up resolving typebox from magic-context's edge rather than from the host.
Environment
@cortexkit/pi-magic-context 0.42.6 (current latest)
- Harness: Pi (the same package serves OMP)
- Platform: linux x64
No runtime diagnostics apply here — this is a dependency-declaration/packaging issue rather than a runtime failure, so doctor --issue output would not add anything.
What happened?
packages/pi-plugin/package.jsondeclares typebox as a regular runtime dependency:The host this plugin runs inside pins the same library to an exact version —
@earendil-works/pi-agent-core,@earendil-works/pi-aiand@earendil-works/pi-coding-agentall declare"typebox": "1.3.27".Two things follow from that:
^1.3.1resolves to the newest 1.x, so installing the plugin pulls a second copy into the tree. In my Pi extension install (~/.pi/agent/npm/pnpm-lock.yaml) the typebox that ends up hoisted is magic-context's:dist/index-r918mh6w.jsships TypeBox's runtime, with bundler comments keeping the source path:So the plugin executes its own copy (built against whatever version bun resolved at build time) while Pi executes 1.3.27 — two different instances of the same library inside one process, plus a third version installed next to it in
node_modules.Expected
TypeBox is part of the host API surface: extension code hands
TSchemavalues to Pi's tool registration and validation, so schema objects cross the plugin/host boundary. It should be host-provided, the way@earendil-works/*already is:with the dev-only copy pinned to whatever Pi currently pins, so local type-checking matches the runtime. Marking the peer optional (
peerDependenciesMeta) is fine if you would rather not require it — the point is that it should not be a hard runtime dependency of the published plugin, nor bundled intodist/.Impact
node_modules, one bundled indist/, and neither is the version Pi runs.1.3.34from this dependency edge instead of Pi's pinned1.3.27. That is how I ran into it: a second extension in the same install ended up resolving typebox from magic-context's edge rather than from the host.Environment
@cortexkit/pi-magic-context0.42.6 (current latest)No runtime diagnostics apply here — this is a dependency-declaration/packaging issue rather than a runtime failure, so
doctor --issueoutput would not add anything.