The vsock control plane is now the ONLY container control plane — on
for shared control containers AND per-session sandbox containers; the
nucleic.container.vsockControlPlane defaults key, its getter, and the
legacy gateway-TCP fallback are retired (the Settings toggle was
already removed).
- SessionController sets controlSocketHostPath on every containerized
spec; per-session containers get their own socket under the app-owned
runtime dir, served by their backend's per-backend server.
- ClaudeCodeBackend refuses a containerized run whose spec lacks a
control socket (fail-loud, never a silent TCP fallback the guest
can't reach); TCP survives only as the host runs' loopback listener,
so no 0.0.0.0 bind — and no macOS local-network prompt — remains.
shutdown() now stops the per-backend server so per-session control
sockets are unlinked when the session ends.
- ContainerEngine probes each fresh clone that carries a control socket
for node + control-bridge.js and fails the start with an actionable
error, so a custom image without the bridge (base images must be
nucleic-sandbox:v4+) no longer surfaces as the CLI's opaque
"Available MCP tools: none".
Side effect (intended): Codex/Grok sessions in per-session sandbox
projects now exec inside their container — their isHostRun check keys
off the control socket, so they previously ran on the host despite the
sandbox setting.
Co-Authored-By: Claude Fable 5 <[email protected]>
Append a build-channel tag (-beta / -rc / -local; none for stable) to every
container name so release + beta + local-dev builds running against the shared
on-disk container store don't collide on per-container rootfs clones. Routes the
NUCLEIC_CHANNEL define into NucleicCore (ContainerManager.channelSuffix) and
scopes launch-time disk GC to the current channel (ownsContainer) so one build
never reaps another's clones.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Replace the Apple `container` CLI wrapper with Apple's `containerization`
Swift framework, driven in-process — no external CLI or daemon.
- ContainerEngine: in-process runtime (shared VZVirtualMachineManager from a
bundled kernel + runtime-pulled vminitd initfs, ImageStore, VmnetNetwork,
live-container registry, typed statistics for CPU/mem + OOM diagnosis).
Daemonless ⇒ ephemeral VMs; reconcile is on-disk GC.
- ContainerizedProcessHandle: bridges a guest LinuxProcess onto the existing
ProcessHandle contract (reusing LineSplitter), so backends stream NDJSON
identically in-container and on-host. Closes the stdio writers after wait()
to finish the line streams (the framework never calls Writer.close()).
- Sandbox image is built in CI (containers/nucleic-sandbox/Dockerfile +
.github/workflows/sandbox-image.yml) and pushed to GHCR; the app pulls +
unpacks it on first use (no on-device build, no user-installed tools). The
GHCR package may stay private — pulls authenticate with the user's GitHub
token via ContainerEngine.registryAuth (Settings → Sandbox, or
NUCLEIC_REGISTRY_USER/NUCLEIC_REGISTRY_TOKEN). vminitd is pulled from Apple's
public GHCR; only the kernel is bundled (scripts/fetch-kernel.sh, curl-only).
- ContainerManager rewired to the engine (policy preserved); ClaudeCodeBackend
execs in-container via the engine; Settings/ProviderAvailability use a static
capability check. Platform floor raised to macOS 26 (Apple silicon) + the
com.apple.security.virtualization entitlement (swift-tools 6.2).
- Verified end-to-end on macOS 27 / Apple silicon via Sources/container-spike:
pull vminitd + image, boot VM, exec, stream stdout. Builds clean; 21 tests pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>