* docs: add npm managed python runtime design * build: add bundled python runtime wheel builder * build: make local embedding dependencies optional * build: bundle python runtime wheel in cli artifacts * build: track bundled python runtime release artifact * test: verify bundled python runtime wheel * docs: add plan for bundled python runtime wheel * test: cover managed python runtime lifecycle * feat: add managed python runtime installer * feat: add runtime command runner * feat: expose runtime management commands * test: verify managed python runtime commands * docs: add plan for managed python runtime installer * feat: add managed python command helper * feat: use managed runtime for sl query compute * feat: route sl query managed runtime policy * docs: add plan for managed runtime sl query integration * feat: add managed runtime daemon metadata * feat: manage python daemon lifecycle * feat: add runtime daemon start stop commands * fix: verify managed runtime daemon lifecycle * docs: add plan for managed runtime daemon lifecycle * feat: add managed local embeddings config marker * feat: add managed local embeddings daemon helper * feat: use managed runtime for local embedding setup * feat: pass managed runtime policy through setup * docs: add plan for managed local embeddings runtime * feat: read CLI package metadata dynamically * feat: assemble public kaelio ktx npm package * feat: release one public kaelio ktx npm artifact * test: cover public kaelio ktx package invocations * chore: verify public kaelio ktx package artifacts * docs: add plan for public kaelio ktx npm package * test: verify managed runtime in public package smoke * test: finalize managed runtime release smoke * docs: add plan for managed runtime release smoke * test: specify local embeddings release smoke * feat: add local embeddings runtime smoke * chore: register local embeddings smoke * fix: verify local embeddings smoke * fix: restore artifact smoke python env helper * docs: add plan for managed local embeddings release smoke * refactor: share managed runtime install policy parsing * feat: use managed runtime for agent semantic queries * feat: use managed runtime for MCP semantic compute * docs: add plan for managed agent and MCP semantic runtime * feat(cli): add managed daemon HTTP helpers * feat(cli): route local adapters through managed daemon * feat(cli): use managed daemon for ingest helpers * feat(cli): pass managed daemon options to scan * feat(context): pass MCP ingest pull config options * feat(cli): pass managed daemon options to serve ingest * test: verify managed local ingest daemon runtime * docs: add plan for managed local ingest daemon runtime * docs: align managed runtime examples * docs: add plan for managed runtime docs cleanup * test: cover published package runtime smoke commands * test: validate published package smoke outputs * docs: add plan for published package runtime smoke * build: stamp public npm package version * release: add npm public release policy * release: add guarded npm publish script * release: document public npm release handoff * docs: add plan for public npm release handoff * test: cover managed runtime prune in package smoke * docs: document managed runtime prune * docs: add plan for managed runtime prune smoke and docs * chore: encode uv runtime prerequisite policy * fix: clarify missing uv runtime error * docs: document uv runtime prerequisite * docs: add plan for uv runtime prerequisite contract * refactor: limit release artifacts to public package runtime * chore: align release policy with bundled runtime wheel * docs: describe single public runtime artifact surface * test: verify single public runtime artifact contract * docs: add plan for single public runtime artifact cleanup * fix: align local embeddings smoke with public version * docs: add plan for local embeddings smoke public version * release: soft-launch as @kaelio/ktx@0.1.0-rc.0 on next tag Publish target moves to the pre-release version 0.1.0-rc.0 under the next dist-tag so npm install @kaelio/ktx (which resolves to latest) does not pick up the soft-launch build. Users opt in via @kaelio/ktx@next. * Fix release script boundary checks * Remove PostHog from public package bundle
20 KiB
Managed Python Runtime Release Smoke Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Make the public @kaelio/ktx artifact smoke prove that the npm
package installs and uses its own managed Python runtime without an externally
prepared Python environment.
Architecture: Keep the release smoke black-box: install the packed public
npm tarball into a clean project, isolate KTX_RUNTIME_ROOT, and exercise the
installed ktx binary. The first ktx sl query --yes performs the lazy core
runtime install from bundled package assets, then the smoke verifies
runtime status, runtime doctor, daemon start/reuse, and daemon stop.
Tech Stack: Node 22 ESM scripts, node:test, pnpm, uv, KTX CLI managed
Python runtime assets.
Existing status
This plan is based on
docs/superpowers/specs/2026-05-11-npm-managed-python-runtime-design.md.
Existing plans based on the spec:
docs/superpowers/plans/2026-05-11-bundled-python-runtime-wheel.mddocs/superpowers/plans/2026-05-11-managed-python-runtime-installer.mddocs/superpowers/plans/2026-05-11-managed-python-runtime-command-integration.mddocs/superpowers/plans/2026-05-11-managed-python-runtime-daemon-lifecycle.mddocs/superpowers/plans/2026-05-11-managed-local-embeddings-runtime.mddocs/superpowers/plans/2026-05-11-public-kaelio-ktx-npm-package.md
All six are implemented in this worktree. Evidence found before writing this plan includes:
scripts/build-python-runtime-wheel.mjsandscripts/build-python-runtime-wheel.test.mjs.packages/cli/assets/python/kaelio_ktx-0.1.0-py3-none-any.whlandpackages/cli/assets/python/manifest.json.packages/cli/src/managed-python-runtime.ts,packages/cli/src/runtime.ts, andpackages/cli/src/commands/runtime-commands.ts.packages/cli/src/managed-python-command.tsandktx sl queryruntime install policy flags.packages/cli/src/managed-python-daemon.ts, daemon state paths, andktx runtime start/ktx runtime stop.packages/cli/src/managed-local-embeddings.ts,packages/context/src/llm/local-config.tsmanaged marker constants, and setup wiring inpackages/cli/src/setup-embeddings.ts.scripts/build-public-npm-package.mjs,scripts/build-public-npm-package.test.mjs,release-policy.jsonlisting@kaelio/ktx, and published smoke command construction for the required@kaelio/ktxinvocation modes.
The remaining release-smoke gap is in scripts/package-artifacts.mjs:
verifyNpmArtifacts()creates a smoke.venv, installs the built Python runtime wheel into it, and runs installed CLI smoke scripts with that venv at the front ofPATH.- The installed CLI smoke does run
ktx sl query --yes, but it does not isolateKTX_RUNTIME_ROOT, does not assert that the first query installed the managed runtime from bundled npm assets, and does not exercisektx runtime status,doctor,start, reuse, andstop.
This plan closes that release-flow gap without changing the separate Python
artifact smoke. verifyPythonArtifacts() must continue to install the built
Python wheel directly because it verifies the Python artifact itself.
File structure
- Modify
scripts/package-artifacts.test.mjs: remove the npm-smoke venv test, add a source-level guard that npm artifact verification does not prepare an external Python venv, and assert that the installed CLI smoke exercises the managed runtime lifecycle. - Modify
scripts/package-artifacts.mjs: remove npm-smoke Python venv PATH setup, isolateKTX_RUNTIME_ROOTinsidenpmRuntimeSmokeSource(), assert first-run lazy install, and add runtime status/doctor/start/reuse/stop smoke commands.
Task 1: Add failing release-smoke tests
Files:
-
Modify:
scripts/package-artifacts.test.mjs -
Test:
scripts/package-artifacts.test.mjs -
Step 1: Remove the stale npm-smoke venv import
In scripts/package-artifacts.test.mjs, delete npmSmokePythonEnv from the
import list. The surrounding import block must contain this sequence after the
edit:
npmDemoSmokeSource,
npmRuntimeSmokeSource,
npmSmokePackageJson,
npmVerifySource,
- Step 2: Replace the npm-smoke venv test with a source guard
Delete this entire test block:
describe('npmSmokePythonEnv', () => {
it('prepends the npm smoke virtualenv bin directory to PATH', () => {
const env = npmSmokePythonEnv('/tmp/ktx-npm-smoke', { PATH: '/usr/bin' });
assert.match(env.PATH, /^\/tmp\/ktx-npm-smoke\/\.venv\/(bin|Scripts)/);
assert.match(env.PATH, /\/usr\/bin$/);
});
});
Insert this block in the same location:
describe('verifyNpmArtifacts', () => {
it('does not prepare an external Python environment for the npm smoke', async () => {
const source = await readFile(new URL('./package-artifacts.mjs', import.meta.url), 'utf8');
const start = source.indexOf('async function verifyNpmArtifacts');
const end = source.indexOf('async function verifyNpmDemoArtifacts');
assert.ok(start > 0, 'verifyNpmArtifacts function must exist');
assert.ok(end > start, 'verifyNpmDemoArtifacts must follow verifyNpmArtifacts');
const body = source.slice(start, end);
assert.doesNotMatch(body, /uv', \['venv', '\.venv'\]/);
assert.doesNotMatch(body, /pythonArtifactInstallArgs/);
assert.doesNotMatch(body, /npmSmokePythonEnv/);
});
});
- Step 3: Extend the installed CLI smoke assertions
In the it('runs installed CLI commands through the public package runtime', ...) test, add these assertions after the existing
assert.match(source, /ktx sl query sqlite execute/); assertion:
assert.match(source, /import Database from 'better-sqlite3'/);
assert.doesNotMatch(source, /run\('python'/);
assert.match(source, /KTX_RUNTIME_ROOT/);
assert.match(source, /managed-runtime/);
assert.match(source, /ktx runtime status missing/);
assert.match(source, /runtimeStatusBefore\.kind, 'missing'/);
assert.match(source, /Installing KTX Python runtime \(core\) with uv/);
assert.match(source, /KTX Python runtime ready:/);
assert.match(source, /ktx runtime status ready/);
assert.match(source, /runtimeStatusAfter\.kind, 'ready'/);
assert.match(source, /runtimeStatusAfter\.manifest\.features/);
assert.match(source, /ktx runtime doctor/);
assert.match(source, /PASS Managed Python runtime/);
assert.match(source, /ktx runtime start/);
assert.match(source, /ktx runtime start reuse/);
assert.match(source, /Using existing KTX Python daemon/);
assert.match(source, /ktx runtime stop/);
- Step 4: Run the failing package artifact tests
Run:
node --test scripts/package-artifacts.test.mjs
Expected: FAIL. The guard fails because verifyNpmArtifacts() still creates
the npm-smoke .venv, and the installed CLI smoke assertions fail because
npmRuntimeSmokeSource() does not yet isolate or verify the managed runtime.
Task 2: Make the npm smoke use only the managed runtime
Files:
-
Modify:
scripts/package-artifacts.mjs -
Modify:
scripts/package-artifacts.test.mjs -
Test:
scripts/package-artifacts.test.mjs -
Step 1: Remove the npm-smoke PATH helper
In scripts/package-artifacts.mjs, change the path import from:
import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
to:
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
Then delete this exported helper:
export function npmSmokePythonEnv(projectDir, baseEnv = process.env) {
const binDir = process.platform === 'win32' ? join(projectDir, '.venv', 'Scripts') : join(projectDir, '.venv', 'bin');
const existingPath = baseEnv.PATH ?? '';
return Object.assign({}, baseEnv, {
PATH: existingPath ? `${binDir}${delimiter}${existingPath}` : binDir,
});
}
- Step 2: Add runtime-smoke helpers to
npmRuntimeSmokeSource()
Inside the template string returned by npmRuntimeSmokeSource(), add this
helper immediately after requireSuccess():
function requireSuccessWithStderr(label, result, stderrPattern) {
assert.equal(
result.code,
0,
label + ' failed with code ' + result.code + '\\nstdout:\\n' + result.stdout + '\\nstderr:\\n' + result.stderr,
);
assert.match(result.stderr, stderrPattern, label + ' stderr did not match ' + stderrPattern);
}
Then replace the smoke root setup:
const root = await mkdtemp(join(tmpdir(), 'ktx-installed-cli-smoke-'));
try {
const projectDir = join(root, 'project');
const sourceDir = join(root, 'source');
with:
const root = await mkdtemp(join(tmpdir(), 'ktx-installed-cli-smoke-'));
const previousRuntimeRoot = process.env.KTX_RUNTIME_ROOT;
process.env.KTX_RUNTIME_ROOT = join(root, 'managed-runtime');
let daemonStarted = false;
try {
const projectDir = join(root, 'project');
const sourceDir = join(root, 'source');
Finally replace the existing finally block at the end of
npmRuntimeSmokeSource():
} finally {
await rm(root, { recursive: true, force: true });
}
with:
} finally {
if (daemonStarted) {
await run('pnpm', ['exec', 'ktx', 'runtime', 'stop']);
}
if (previousRuntimeRoot === undefined) {
delete process.env.KTX_RUNTIME_ROOT;
} else {
process.env.KTX_RUNTIME_ROOT = previousRuntimeRoot;
}
await rm(root, { recursive: true, force: true });
}
- Step 3: Create the sqlite smoke warehouse without Python
Inside the template string returned by npmRuntimeSmokeSource(), add this
import after the assert import:
import Database from 'better-sqlite3';
Then replace the current writeSqliteWarehouse() function:
async function writeSqliteWarehouse(projectDir) {
const createDb = await run('python', [
'-c',
[
'import sqlite3',
'import sys',
'db_path = sys.argv[1]',
'conn = sqlite3.connect(db_path)',
'conn.executescript("""',
'DROP TABLE IF EXISTS orders;',
'CREATE TABLE orders (',
' id INTEGER PRIMARY KEY,',
' status TEXT NOT NULL,',
' amount INTEGER NOT NULL',
');',
"INSERT INTO orders (status, amount) VALUES ('paid', 20), ('paid', 30), ('open', 10);",
'""")',
'conn.close()',
].join('\\n'),
join(projectDir, 'warehouse.db'),
]);
requireSuccess('create sqlite warehouse', createDb);
}
with:
async function writeSqliteWarehouse(projectDir) {
const database = new Database(join(projectDir, 'warehouse.db'));
try {
database.exec(`
DROP TABLE IF EXISTS orders;
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
status TEXT NOT NULL,
amount INTEGER NOT NULL
);
INSERT INTO orders (status, amount) VALUES ('paid', 20), ('paid', 30), ('open', 10);
`);
} finally {
database.close();
}
}
- Step 4: Assert the isolated runtime is initially missing
In npmRuntimeSmokeSource(), insert this block immediately after the public
package version assertion:
const runtimeStatusBefore = parseJsonResult(
'ktx runtime status missing',
await run('pnpm', ['exec', 'ktx', 'runtime', 'status', '--json']),
);
assert.equal(runtimeStatusBefore.kind, 'missing');
assert.equal(runtimeStatusBefore.layout.runtimeRoot, process.env.KTX_RUNTIME_ROOT);
process.stdout.write('ktx managed runtime starts missing in isolated root\\n');
- Step 5: Assert first
sl query --yesperforms lazy managed install
In npmRuntimeSmokeSource(), replace the current slQuery verification block:
const slQuery = await run('pnpm', ['exec', 'ktx', 'sl', 'query',
'--connection-id',
'warehouse',
'--measure',
'orders.order_count',
'--format',
'json',
'--yes',
'--project-dir',
projectDir,
]);
requireSuccess('ktx sl query', slQuery);
requireOutput('ktx sl query', slQuery, /"mode": "compile_only"/);
requireOutput('ktx sl query', slQuery, /orders/);
with:
const slQuery = await run('pnpm', ['exec', 'ktx', 'sl', 'query',
'--connection-id',
'warehouse',
'--measure',
'orders.order_count',
'--format',
'json',
'--yes',
'--project-dir',
projectDir,
]);
requireSuccessWithStderr(
'ktx sl query first managed runtime install',
slQuery,
/Installing KTX Python runtime \(core\) with uv[\s\S]*KTX Python runtime ready:/,
);
requireOutput('ktx sl query first managed runtime install', slQuery, /"mode": "compile_only"/);
requireOutput('ktx sl query first managed runtime install', slQuery, /orders/);
const runtimeStatusAfter = parseJsonResult(
'ktx runtime status ready',
await run('pnpm', ['exec', 'ktx', 'runtime', 'status', '--json']),
);
assert.equal(runtimeStatusAfter.kind, 'ready');
assert.deepEqual(runtimeStatusAfter.manifest.features, ['core']);
assert.equal(runtimeStatusAfter.layout.runtimeRoot, process.env.KTX_RUNTIME_ROOT);
process.stdout.write('ktx managed runtime lazy install verified\\n');
- Step 6: Add runtime doctor and daemon lifecycle smoke
In npmRuntimeSmokeSource(), insert this block immediately after the
sqliteSlQuery verification block:
const runtimeDoctor = await run('pnpm', ['exec', 'ktx', 'runtime', 'doctor']);
requireSuccess('ktx runtime doctor', runtimeDoctor);
requireOutput('ktx runtime doctor', runtimeDoctor, /PASS uv/);
requireOutput('ktx runtime doctor', runtimeDoctor, /PASS Bundled Python wheel/);
requireOutput('ktx runtime doctor', runtimeDoctor, /PASS Managed Python runtime/);
process.stdout.write('ktx runtime doctor verified\\n');
const runtimeStart = await run('pnpm', ['exec', 'ktx', 'runtime', 'start']);
requireSuccess('ktx runtime start', runtimeStart);
daemonStarted = true;
requireOutput('ktx runtime start', runtimeStart, /Started KTX Python daemon/);
requireOutput('ktx runtime start', runtimeStart, /url: http:\/\/127\.0\.0\.1:\d+/);
requireOutput('ktx runtime start', runtimeStart, /features: core/);
const runtimeStartReuse = await run('pnpm', ['exec', 'ktx', 'runtime', 'start']);
requireSuccess('ktx runtime start reuse', runtimeStartReuse);
requireOutput('ktx runtime start reuse', runtimeStartReuse, /Using existing KTX Python daemon/);
requireOutput('ktx runtime start reuse', runtimeStartReuse, /features: core/);
const runtimeStop = await run('pnpm', ['exec', 'ktx', 'runtime', 'stop']);
requireSuccess('ktx runtime stop', runtimeStop);
daemonStarted = false;
requireOutput('ktx runtime stop', runtimeStop, /Stopped KTX Python daemon/);
process.stdout.write('ktx runtime daemon lifecycle verified\\n');
- Step 7: Remove npm-smoke Python preparation from artifact verification
In scripts/package-artifacts.mjs, replace verifyNpmArtifacts() with this
implementation:
async function verifyNpmArtifacts(layout, tmpRoot) {
for (const packageInfo of NPM_ARTIFACT_PACKAGES) {
await assertPathExists(layout.npmTarballs[packageInfo.name], `${packageInfo.name} tarball`);
}
const projectDir = join(tmpRoot, 'npm-clean-install');
await mkdir(projectDir, { recursive: true });
await writeFile(
join(projectDir, 'package.json'),
`${JSON.stringify(npmSmokePackageJson(layout), null, 2)}\n`,
);
await writeFile(join(projectDir, 'verify-npm.mjs'), npmVerifySource());
await writeFile(join(projectDir, 'verify-installed-cli.mjs'), npmRuntimeSmokeSource());
await writeFile(join(projectDir, 'verify-installed-demo.mjs'), npmDemoSmokeSource());
await runCommand('pnpm', ['install'], { cwd: projectDir });
await runCommand('pnpm', ['rebuild', 'better-sqlite3'], { cwd: projectDir });
await runCommand('node', ['verify-npm.mjs'], { cwd: projectDir });
await runCommand('pnpm', ['exec', 'ktx', '--version'], { cwd: projectDir });
await runCommand('node', ['verify-installed-cli.mjs'], { cwd: projectDir });
await runCommand('node', ['verify-installed-demo.mjs'], { cwd: projectDir });
}
- Step 8: Run the focused package artifact tests
Run:
node --test scripts/package-artifacts.test.mjs
Expected: PASS.
- Step 9: Commit the release-smoke implementation
Run:
git add scripts/package-artifacts.mjs scripts/package-artifacts.test.mjs
git commit -m "test: verify managed runtime in public package smoke"
Task 3: Verify the release-smoke surface
Files:
-
Test:
scripts/package-artifacts.test.mjs -
Test:
scripts/package-artifacts.mjs -
Step 1: Run script unit tests that cover artifact packaging
Run:
node --test scripts/build-python-runtime-wheel.test.mjs scripts/build-public-npm-package.test.mjs scripts/package-artifacts.test.mjs scripts/published-package-smoke.test.mjs scripts/release-readiness.test.mjs
Expected: PASS.
- Step 2: Run the public package artifact smoke
Run:
pnpm run artifacts:verify
Expected: PASS. The verify-installed-cli.mjs output must include:
ktx managed runtime starts missing in isolated root
ktx managed runtime lazy install verified
ktx runtime doctor verified
ktx runtime daemon lifecycle verified
- Step 3: Run release readiness
Run:
pnpm run release:readiness
Expected: PASS. The report must still list @kaelio/ktx as the only npm
package and must still report registry publishing as disabled by
release-policy.json.
- Step 4: Run pre-commit for changed files
Run:
if [ -d .venv ]; then source .venv/bin/activate; fi
uv run pre-commit run --files scripts/package-artifacts.mjs scripts/package-artifacts.test.mjs
Expected: PASS. If pre-commit cannot run because the local environment lacks a
compatible hook version, record the exact failure and keep the passing
node --test and artifact smoke results.
- Step 5: Commit verification fixes if needed
If Step 1, Step 2, Step 3, or Step 4 required edits, run:
git add scripts/package-artifacts.mjs scripts/package-artifacts.test.mjs
git commit -m "test: finalize managed runtime release smoke"
If no files changed after Task 2, do not create an empty commit.
Acceptance criteria
verifyNpmArtifacts()no longer creates a Python.venv, no longer callspythonArtifactInstallArgs(), and no longer runs npm smoke scripts with a custom Python venv at the front ofPATH.- The installed public npm smoke creates its sqlite warehouse with
better-sqlite3and does not shell out topython. - The installed public npm smoke sets an isolated
KTX_RUNTIME_ROOTand confirms thatktx runtime status --jsonstarts asmissing. - The first installed
ktx sl query --yesinstalls thecoremanaged Python runtime from bundled npm package assets and still returns compile-only SQL. - A second semantic query executes against sqlite using the installed managed runtime.
ktx runtime doctorpasses after lazy install.ktx runtime startstarts a core daemon, a secondktx runtime startreuses the daemon, andktx runtime stopstops it.- The separate Python artifact verification still installs and tests the Python wheel directly.
- Focused script tests,
pnpm run artifacts:verify, release readiness, and pre-commit pass or have explicitly recorded environment blockers.
Self-review
- Spec coverage: the previous six plans cover the bundled wheel, runtime
installer,
sl querycommand integration, daemon lifecycle, local embeddings, and public npm package surface. This plan covers release-flow checks for clean install of the packed npm package, first-run managed runtime install from the bundled wheel, one-shot semantic-layer query through the managed runtime, runtime status and doctor output, and daemon start/reuse/stop. - Remaining intentional gap: optional
local-embeddingssmoke remains outside the default release artifact smoke because the spec permits it in a separate job or opt-in check and the dependency downloads are large. - Placeholder scan: no steps contain placeholder implementation language.
- Type consistency: runtime feature names remain
coreandlocal-embeddings; the public npm package name remains@kaelio/ktx; the runtime root environment variable isKTX_RUNTIME_ROOT.