Problem
SpacePilot currently treats an importable package in a selected Python
interpreter as a runtime. This makes the pipx control plane, a configured Conda
environment, project environments, and inference dependencies accidentally
coupled.
PR #78 exposed the concrete failure mode: the released mlx-lm 0.31.3 allowed
transformers 5.13.0, but that combination failed during import. The runtime
installer also ignored .pluto_config.json's python_bin and inspected the
pipx interpreter instead. A temporary compatibility constraint makes the route
usable, but shared mutable environments remain the wrong boundary.
Outcome
Treat every inference runtime as an immutable, independently provisioned
execution capsule:
SpacePilot control plane -> exact runtime capsule -> pinned model snapshot
The control plane never imports ML runtimes. A capsule owns its exact Python,
complete dependency lock, platform identity, subprocess runner, and readiness
evidence. Package caches and model weights may be shared; import paths are not.
Required design
- Capsule identity includes runtime source/version, exact Python, full lock
digest, OS/architecture, accelerator backend, and runner protocol version.
- Provision with a committed platform-specific uv lock and artifact hashes.
- Build candidates in a temporary directory; promote atomically only after all
probes pass; retain the previous capsule for rollback.
- Readiness requires import, accelerator allocation, and a real canary
inference on the selected ship. Every result is timestamped.
- Runtime requests use a versioned JSON protocol over stdin/stdout. Prompts and
credentials never appear in argv.
- Measurements record
capsule_id, runtime ID, model revision, device ID, and
execution knobs.
- Candidate dependency updates are tested and quarantined; they never mutate
the active capsule in place.
- Stable and experimental channels are explicit. Experimental Git sources use
immutable full commits.
Delivery
- Add capsule identity, paths, protocol types, and atomic active/previous
pointers. Keep schema-v1 shared-interpreter routes readable as legacy.
- Implement uv provisioning for Darwin arm64 and migrate MLX-LM first.
- Run a tiny text canary, then fly the bounded Qwen3.8 27B 4-bit route and
record real peak memory, load time, and generation speed.
- Import MFLUX's existing isolated environment as a legacy capsule, then
rebuild it from a lock. Migrate Kokoro and native-binary runtimes next.
- Add automated candidate lock generation and hardware-backed compatibility
probes.
Acceptance criteria
- Installing or upgrading one runtime cannot change SpacePilot or another
runtime's environment.
- Two conflicting runtime dependency graphs can coexist on one ship.
- The pipx and project interpreters are irrelevant to inference execution.
- Reprovisioning a capsule lock produces the same package set.
- A failed candidate leaves the active capsule unchanged.
- Rollback requires no resolution or reinstall.
ready requires fresh import, accelerator, and canary evidence.
- Every flown measurement carries the exact capsule identity.
- Prompts and credentials are absent from process argv.
- The Qwen3.8 route runs without changing
iogpu.wired_limit_mb or a shared
Python environment.
Design draft
A local working draft has been prepared as docs/design/RUNTIME-CAPSULES.md.
It should be reviewed and added to the repository as part of this issue's
first implementation change.
Problem
SpacePilot currently treats an importable package in a selected Python
interpreter as a runtime. This makes the pipx control plane, a configured Conda
environment, project environments, and inference dependencies accidentally
coupled.
PR #78 exposed the concrete failure mode: the released
mlx-lm 0.31.3allowedtransformers 5.13.0, but that combination failed during import. The runtimeinstaller also ignored
.pluto_config.json'spython_binand inspected thepipx interpreter instead. A temporary compatibility constraint makes the route
usable, but shared mutable environments remain the wrong boundary.
Outcome
Treat every inference runtime as an immutable, independently provisioned
execution capsule:
The control plane never imports ML runtimes. A capsule owns its exact Python,
complete dependency lock, platform identity, subprocess runner, and readiness
evidence. Package caches and model weights may be shared; import paths are not.
Required design
digest, OS/architecture, accelerator backend, and runner protocol version.
probes pass; retain the previous capsule for rollback.
inference on the selected ship. Every result is timestamped.
credentials never appear in argv.
capsule_id, runtime ID, model revision, device ID, andexecution knobs.
the active capsule in place.
immutable full commits.
Delivery
pointers. Keep schema-v1 shared-interpreter routes readable as
legacy.record real peak memory, load time, and generation speed.
rebuild it from a lock. Migrate Kokoro and native-binary runtimes next.
probes.
Acceptance criteria
runtime's environment.
readyrequires fresh import, accelerator, and canary evidence.iogpu.wired_limit_mbor a sharedPython environment.
Design draft
A local working draft has been prepared as
docs/design/RUNTIME-CAPSULES.md.It should be reviewed and added to the repository as part of this issue's
first implementation change.