Skip to content

smolvm Backend Research

Status: Open — research and design proposal

Docker hardening and OrbStack isolated machines cover the two most practical near-term paths for jackin’: improve the runtime that works today, and use a macOS backend that many operators already have installed. smolvm is a third path worth researching because it changes the tradeoff: it is open source, Rust-heavy, true VM-per-workload oriented, OCI-image based, and potentially embeddable instead of only scriptable.

The question for jackin’ is:

Can smolvm become the small, open, Rust-native VM backend for workloads that need a stronger boundary than hardened Docker but should still keep jackin’ role/image ergonomics?

This item is not a commitment to implement smolvm support. It is the research track that decides whether smolvm is mature and compatible enough to become a jackin’ backend.

Primary source: smol-machines/smolvm.

Comparison sources:

Current repository signals as of May 24, 2026:

  • Apache-2.0 repository with roughly 3.4k GitHub stars and active releases.
  • Latest stable: smolvm v0.7.2 (2026-05-21), libkrun v1.18.1 (2026-05-20).
  • README describes smolvm as a CLI for portable, lightweight, self-contained virtual machines.
  • Public docs claim sub-second cold start, cross-platform macOS/Linux support, elastic memory, OCI image input, .smolmachine portable artifacts, network off by default, allow-host egress, SSH agent forwarding, persistent machines, and SDK access.
  • README says each workload gets its own kernel through Hypervisor.framework on macOS or KVM on Linux, using libkrun with a custom kernel.
  • README says Docker Hub, GHCR, and other OCI registry images can be booted as microVMs with no Docker daemon required.
  • Known limitations include opt-in TCP/UDP networking only, no ICMP, directory-only volume mounts, Hypervisor.framework signing entitlements on macOS, host SSH agent requirement for --ssh-agent, and GPU requirements.
  • Release notes for v0.7.0 mention “enabling docker within smolvm through TSI”, which is directly relevant to jackin’ Docker-workflow compatibility and needs hands-on validation.
  • Development docs show a Rust build with cargo-make, git-lfs, libkrun/libkrunfw binaries, a smolvm agent rootfs, and macOS codesigning.

A research pass through the smol-machines/smolvm repository established several facts that change the design surface jackin’ has to plan against:

AspectVerified factSource
PID 1 inside the VMsmolvm-agent runs as PID 1, not the OCI image’s ENTRYPOINT. The agent mounts essential filesystems, sets up overlayfs, opens a vsock listener on port 6000, then runs the OCI image’s entrypoint as a child of the agent under the embedded crun runtimecrates/smolvm-agent/src/main.rs, crates/smolvm-agent/src/oci.rs
Rust SDK / library crateWorkspace exposes smolvm as a library crate ([lib] name = "smolvm" path = "src/lib.rs"), but it is not on crates.io and not marketed as an SDK. The sdks/ directory ships only a Node N-API binding (smolvm-napi); Rust is conspicuously absentCargo.toml, sdks/README.md
Server transportHTTP via axum, default unix:///$XDG_RUNTIME_DIR/smolvm.sock, optional TCP via -l 127.0.0.1:8080. Routes: /api/v1/machines, /exec, /logs, /images, /files. OpenAPI 3.1 spec ships via utoipa and can be exported with smolvm serve openapi --output spec.jsonsrc/cli/serve.rs, src/api/mod.rs, src/cli/openapi.rs
libkrunfw distributionBundled as a pre-built dylib/so inside smolvm’s lib/ directory (lib/libkrun.dylib, lib/libkrunfw.5.dylib, lib/linux-x86_64/libkrun.so.1.17.3, lib/linux-x86_64/libkrunfw.so.5.3.0). Upstream containers/libkrunfw only distributes source tarballs — there is no stable artifact URL. smolvm builds + commits the dylib via git-LFS and ships it transparently in release tarballssdks/README.md
macOS code-signing entitlementSingle key: com.apple.security.hypervisor. NOT com.apple.vm.networkingcontainers/libkrun/hvf-entitlements.plist
TSI for credential proxyTSI cannot do HTTPS credential injection. It handles only AF_INET/AF_INET6/AF_UNIX, SOCK_STREAM/SOCK_DGRAM at the socket syscall layer, not TLS/HTTP. The VMM sees raw bytes after the guest establishes TLS; injecting Authorization headers would require MITMing TLS with a guest-trusted CA. A credential proxy needs a separate guest-side cooperating HTTP proxy + trusted CA, not TSI alonelibkrun README
Docker-in-smolvm via TSIPR #272 (in v0.7.0) added overlayfs index=on,redirect_dir=on,uuid=on flags + custom libkrunfw kernel with CONFIG_NETFILTER/NF_TABLES/NFT_COMPAT/BRIDGE/OVERLAY_FS. Documented recipe uses bare Alpine + dockerd (not an OCI image). Supports docker pull/run/build, bridge + host networking. Critical constraint: /var/lib/docker must be bind-mounted to ext4 — ramfs lacks file-handle support, breaking nested overlay2. Requires --net-backend virtio-net (TSI alone is insufficient for Docker’s bridge)examples/docker-in-vm/docker.smolfile
.smolmachine artifactzstd-compressed tar + JSON manifest + 64-byte binary footer (magic SMOLPACK, version 1). Contains agent-rootfs.tar, OCI layers, platform-specific libkrun, optional storage.ext4 + overlay.raw (VM snapshot mode). OCI-registry-pushable as config blob application/vnd.smolmachines.machine.config.v1+json + layer application/vnd.smolmachines.smolmachine.v1. Two execution modes: container (unpack + crun) or VM (restore overlay snapshot). On macOS, embedded in __SMOLVM,__smolvm Mach-O section for code-signing compatibilitycrates/smolvm-pack/src/format.rs
Multi-archYes via Rosetta 2 on Apple Silicon, but not on Linux. smolvm virtiofs-mounts the host Rosetta runtime at /mnt/rosetta, then registers it with binfmt_misc for x86_64 ELFs. CLI knob: --rosetta on machine and pack. Requires softwareupdate --install-rosetta, macOS 11+, Apple Silicon. Linux: not available (_rosetta: bool, // Ignored on Linux). No QEMU TCG fallbacksrc/vm/rosetta.rs

This research should compare only three post-Docker-hardening options:

  1. OrbStack isolated machines - pragmatic macOS backend for operators already using OrbStack.
  2. smolvm - open-source Rust/libkrun VM backend candidate.
  3. Docker Sandboxes - Docker’s productized microVM agent sandbox with a private Docker Engine, policy proxy, and credential proxy.

Do not expand this item into Firecracker research. Firecracker can remain a later server-side or hosted-runtime candidate if a separate problem demands it, but it is not the useful comparison for the current jackin’ local-backend decision.

Why smolvm Is Different From OrbStack And Docker Sandboxes

Section titled “Why smolvm Is Different From OrbStack And Docker Sandboxes”
ConcernOrbStack isolated machinesmolvmDocker Sandboxes
Product shapePolished macOS app and CLIOpen-source CLI/library-oriented runtimeProductized Docker CLI/service for agent sandboxes
License/controlProprietaryApache-2.0Commercial Docker product surface around a proprietary service/runtime
Implementation fitShell out to orbShell out first; SDK/server or Rust embedding requires validationShell out to sbx or integrate around Docker’s sandbox workflow if APIs allow
Boundary wordingIsolated machine, shared kernel per OrbStack docsVM per workload with its own kernel per smolvm READMEDedicated microVM per sandbox per Docker docs
PlatformmacOS onlymacOS and Linux with KVMmacOS, Windows, and Linux per Docker docs
Docker compatibilityInstall/start Docker inside machineOCI images boot without Docker daemon; Docker-in-guest needs researchPrivate Docker Engine is a core feature
File sharingOrbStack selective sharesDirectory volume mountsWorkspace mounted directly at the same absolute host path
Network policyIsolated-machine host/machine blocking plus future jackin policyNetwork off by default, --allow-host allowlistHost-side proxy, allow/deny policy, raw TCP/UDP/ICMP blocked by default per docs
Credential posturejackin must provide its own credential modeljackin must provide its own credential modelHost-side credential proxy injects selected outbound API auth per docs
Maturity riskMature operator productPre-1.0 fast-moving runtimeNew product surface but backed by Docker’s ecosystem
Strategic valueBest macOS user experienceBest open Rust-native backend candidateBest benchmark for the private-Docker-in-VM agent UX

All three are useful, but they solve different problems. OrbStack is the practical macOS path, Docker Sandboxes is the polished reference for “agent gets a private Docker daemon inside a VM boundary”, and smolvm is the open Rust-native path jackin’ can study, prototype, and maybe integrate more deeply.

Docker Sandboxes is the most important product benchmark for smolvm, because it targets the same agent problem jackin’ cares about:

  • each agent session runs in a dedicated microVM
  • each sandbox has its own filesystem, network, and private Docker daemon
  • the agent can run docker build, docker run, and docker compose without touching the host Docker daemon
  • workspace access is explicit, same-path, and live back to the host
  • HTTP/HTTPS traffic goes through a host-side policy and credential proxy
  • raw TCP, UDP, ICMP, private network access, host localhost, and non-allowed domains are blocked by default per Docker docs
  • organization governance can centrally manage network and filesystem policy on paid plans

For jackin’, Docker Sandboxes answers the “what should excellent look like?” question:

agent freedom inside boundary:
sudo + packages + Docker Engine + writable workspace
host boundary:
no host Docker socket
no broad host filesystem access
no raw network by default
credentials mediated outside the VM

smolvm should be compared against that shape, not against generic “microVM” claims.

What smolvm Could Do Better Than Docker Sandboxes

Section titled “What smolvm Could Do Better Than Docker Sandboxes”

Potential advantages to validate:

  • Open-source runtime that can be audited, patched, forked, and discussed in jackin’ roadmap terms without depending on vendor APIs.
  • Rust-heavy implementation and libkrun foundation, which may eventually fit jackin’ better than a black-box CLI integration if a stable Rust-consumable API exists.
  • Direct OCI-image boot without requiring Docker as the outer runtime.
  • Network-off-by-default posture that maps naturally to jackin’ deny-by-default egress goals.
  • Linux/KVM and macOS Hypervisor.framework support in one project, giving jackin’ a possible non-OrbStack local VM backend beyond macOS.
  • .smolmachine artifacts might become a portable, inspectable snapshot primitive if they map cleanly to jackin’ eject/purge semantics.

What Docker Sandboxes Currently Does Better

Section titled “What Docker Sandboxes Currently Does Better”

Expected advantages unless smolvm proves otherwise:

  • Private Docker Engine is a product-level feature, not a research question.
  • Network policy and credential proxy are documented first-class controls.
  • Same-path workspace mount behavior aligns strongly with jackin’ existing same-path design.
  • Agent workflow is explicit: agents get a real development environment, including package installation and Docker workflows.
  • Team/enterprise governance has a built-in story.
  • Cross-platform story includes Windows, where smolvm is not currently a jackin’ candidate.

Expected advantages unless smolvm proves otherwise:

  • Best macOS developer experience for operators already using OrbStack as their Docker backend.
  • Full Linux machine lifecycle with orb commands, cloud-init, and polished file/network integration.
  • Easier operator mental model for long-lived machines.
  • Selective shares and host/machine blocking are already in the product surface.
  • Docker inside an OrbStack machine should be straightforward Linux-machine work, though jackin’ must still validate the full role flow.

The comparison should produce separate conclusions, not a single winner:

Desired capabilityLikely best first path
Improve today’s local defaultDocker runtime hardening
macOS isolated backend with strong UXOrbStack isolated machine
Open source Rust-native VM backendsmolvm
Private Docker daemon inside a VM with policy proxyDocker Sandboxes as benchmark, smolvm/OrbStack as prototypes
Team-managed policy and paid enterprise controlsDocker Sandboxes benchmark only unless jackin’ builds its own governance
Cross-platform local VM backend beyond macOSsmolvm research
Hosted hostile multi-tenant executionOut of scope for this item

Research whether smolvm can support one or more jackin’ backend modes:

  1. Ephemeral command sandbox: run one agent/tool command in a short-lived microVM for high-risk operations.
  2. Docker-free role backend: boot a role OCI image directly as a smolvm workload without a Docker daemon.
  3. Persistent machine backend: create one smolvm machine per jackin’ instance, preserve agent state, and reconnect later.
  4. Docker-capable VM backend: run Docker-compatible workflows inside the smolvm boundary if the v0.7.0 Docker-in-smolvm work is usable.
  5. Embedded backend: eventually integrate through a stable SDK, server, or library boundary instead of shelling out to the CLI.

The research should produce a go/no-go recommendation for each mode.

  • Do not replace Docker runtime hardening with smolvm research.
  • Do not block OrbStack isolated-machine work on smolvm.
  • Do not claim smolvm can run current jackin’ roles until Docker workflow compatibility is tested.
  • Do not vendor or fork smolvm unless the operator explicitly chooses that maintenance burden.
  • Do not require smolvm for normal local jackin’ usage.
  • Do not silently install smolvm or its host dependencies.

Use a name that distinguishes this from OrbStack:

smolvm

Possible future CLI:

Terminal window
jackin load reviewer . --backend smolvm
jackin load reviewer . --backend smolvm --vm-mode ephemeral
jackin load the-architect . --backend smolvm --vm-mode persistent

Possible future config:

[runtime.smolvm]
enabled = false
mode = "persistent" # ephemeral | direct-image | persistent | docker-capable
network = "deny" # deny | allowlist | open
allow_hosts = ["github.com", "api.openai.com"]
ssh_agent = "ask" # off | ask | on
cpus = 4
memory = "8 GiB"

This schema is intentionally speculative. If it lands in versioned config, it must follow the migration rules.

Run a single command or classified high-risk operation inside smolvm:

jackin role container -> asks host/capsule bridge for sandboxed command
host jackin -> smolvm machine run --image <tool-image> -- <command>
smolvm -> exits and deletes state

Best for:

  • untrusted scripts
  • package install probes
  • generated code execution
  • quick network-denied checks

Risk:

  • Integrating per-command smolvm from inside an existing agent session may need a host bridge, not only the current container runtime.
  • It overlaps with Process-level sandboxing, which is likely lower overhead for routine commands.

Boot the role OCI image directly as the smolvm workload. Important reshape from initial design: the verified architecture above shows smolvm-agent runs as PID 1 inside the VM, not the OCI image’s ENTRYPOINT. The role image’s entrypoint executes as a child of the agent under crun. jackin-capsule therefore cannot be PID 1 inside a smolvm-booted role image.

Two options for handling this:

OptionShapeTrade-off
B.1 — capsule as PID 2 under smolvm-agentjackin-capsule runs as the OCI image’s entrypoint, sees itself as PID 2 (or higher) under smolvm-agent. Capsule’s session/control channel speaks over the vsock port 6000 that smolvm-agent already opens, or over a side channelLoses PID-1 reaping semantics (smolvm-agent handles SIGCHLD). Capsule’s existing assumption of being init has to be relaxed for this backend. The lift is contained in jackin-capsule itself
B.2 — patch smolvm-agent or forkSubmit upstream patch (or fork) to let smolvm pass through an OCI-image PID-1 entrypoint without inserting the agent. Or accept the agent as PID 1 and treat capsule as a sibling daemon launched by smolvm-agentUpstream coordination cost; jackin’ becomes a smolvm contributor. Highest control over the runtime contract but largest commitment

Recommended: B.1. Modify jackin-capsule (see crates/jackin-capsule/src/main.rs, current PID==1 detection at crates/jackin-capsule/src/daemon.rs) so the daemon-mode path no longer requires PID 1. Daemon mode currently triggers on process::id() == 1; the smolvm path would set an env var (JACKIN_CAPSULE_FORCE_DAEMON=1 or similar) to opt in regardless of PID. Reaping responsibilities stay with smolvm-agent.

Best for:

  • Docker-free roles
  • read-only review roles
  • short-lived agent tasks
  • cases where Docker-in-Docker is unnecessary

Risk:

  • Current jackin’ roles assume a container entrypoint and Docker-style mounts, not necessarily a VM init model.
  • Capsule reaping/signal model under smolvm-agent needs validation (does SIGTERM to the role process work normally? does Ctrl+C propagate?).
  • smolvm volume mounts are directory-only; single-file mounts the role expects (e.g. ~/.gitconfig) need parent-directory mounts or staging.

Create one smolvm persistent machine per jackin’ instance:

smolvm machine create --net? <instance>
smolvm machine start --name <instance>
smolvm machine exec --name <instance> -- <jackin bootstrap>

Best for:

  • agent sessions that need reconnect
  • durable package installs inside the VM
  • .smolmachine export/import experiments

Risk:

  • Persistence can become invisible bloat unless jackin’ owns cleanup and disk reporting.
  • Current jackin’ state model deliberately separates agent state from mutable runtime filesystems.

Validate whether Docker inside smolvm is good enough for current jackin’ roles. This is the important compatibility gate.

Documented baseline (May 2026): smolvm v0.7.0 added Docker support via TSI through PR #272. The known-good recipe at examples/docker-in-vm/docker.smolfile starts from bare Alpine + dockerd (not from an OCI image). Critical constraints from the recipe:

  • /var/lib/docker must be bind-mounted to ext4 (/storage/docker); ramfs lacks file-handle support for nested overlay2.
  • Custom libkrunfw kernel with CONFIG_NETFILTER, CONFIG_NF_TABLES, CONFIG_NFT_COMPAT, CONFIG_BRIDGE, CONFIG_OVERLAY_FS is required.
  • --net-backend virtio-net is required; TSI alone is insufficient for Docker’s bridge networking.
  • Supports docker pull, docker run, docker build, bridge + host networking.

Open compatibility questions for jackin’ specifically:

  • Can a jackin’ construct/role image be substituted for the Alpine base in the recipe, or does the role image have to stay outside the smolvm-via-TSI Docker boundary?
  • Does Docker Compose work inside the smolfile shape?
  • Does Java Testcontainers work? Reaper (testcontainers/ryuk) has historically had issues with non-default Docker contexts.
  • How does jackin’ inspect and clean the inner Docker state from outside the VM?
  • How are Docker images cached across machine restarts? .smolmachine persistence interacts with /storage/docker lifecycle.

Decision rule:

  • If Docker workflows (build + run + Compose + Testcontainers) all pass inside the smolfile shape, smolvm can compete with OrbStack as an open cross-platform VM backend.
  • If only docker build/docker run pass but Compose or Testcontainers fail, smolvm is positioned as the Docker-free / lightweight-role backend; OrbStack remains the recommendation for full-fidelity Docker workflows.
  • If Docker workflows do not pass at all, smolvm is still valuable for Docker-free roles and ephemeral high-risk operations, but not as a default replacement for the current Docker backend.

smolvm’s network posture is interesting because the README says network is off by default and egress can be limited with --allow-host.

Mapping to jackin’:

jackin policysmolvm mapping to validate
denyomit --net
allowlist--net --allow-host <host> for each allowed host
open--net without allow-host restriction
private network blockedvalidate default host/machine reachability and add explicit denial if supported

TSI Limits and the Credential-Proxy Question

Section titled “TSI Limits and the Credential-Proxy Question”

The earlier intuition that libkrun’s TSI could implement jackin’s brokered-credential proxy directly was wrong. Confirmed from the libkrun README:

The VMM acts as a proxy for AF_INET, AF_INET6 and AF_UNIX sockets, for both incoming and outgoing connections.

TSI operates at the socket syscall layer, not the TLS/HTTP layer. It transparently redirects guest TCP/UDP syscalls to a host-side vsock proxy. The VMM sees raw bytes after the guest has established its TLS session. Injecting an Authorization header into HTTPS would require terminating TLS with a guest-trusted CA — which TSI alone does not do.

What TSI does give jackin’ for credentials:

  • per-guest network policy enforcement at the syscall level (block, allow, redirect)
  • visibility into which destinations the guest is contacting (for audit/log)
  • no virtual NIC to harden

What TSI does not give jackin’:

  • TLS termination + header injection (needed for the Docker Sandboxes credential-proxy shape)
  • HTTP/2 or HTTP/3 protocol awareness
  • raw bytes are already TLS-encrypted by the guest

A real jackin’ credential proxy on smolvm needs a cooperating in-guest HTTP proxy with a trusted CA cert installed inside the role environment. The HTTP proxy can speak vsock to the host-side credential daemon (host-bridge) which holds the raw token. TSI’s role narrows to “enforce that all outbound HTTPS routes through the proxy and nothing else escapes” — a useful primitive, but it is complementary to the credential broker, not a replacement. | connection logs | not provided by README; jackin may need its own proxy/log layer |

This may make smolvm a useful implementation path for early network egress policy, but only after confirming how DNS, redirects, package managers, and registry auth behave under --allow-host.

Known limitation: README says volume mounts are directories only, not single files.

Implications for jackin’:

  • Workspace and global directory mounts fit.
  • Single-file secret/config mounts would need a parent directory mount, a generated staging directory, or a different credential mechanism.
  • Mount destination control must be validated: jackin’ supports arbitrary dst, while smolvm examples use -v /host/dir:/workspace.
  • Read-only mount support must be checked.
  • Directory mount confinement must be tested with symlinks, bind-mount escape attempts, nested filesystems, and parent-directory access assumptions.
  • Worktree/clone isolation can still materialize on the host before the directory is mounted into smolvm.

The README says --ssh-agent can forward the host SSH agent so private keys do not enter the guest.

Rules for jackin’:

  • SSH agent forwarding must default to off or ask.
  • The launch contract must show whether SSH agent forwarding is enabled.
  • This does not solve API-token forwarding for Claude, Codex, Amp, Kimi, OpenCode, or gh.
  • Future brokered credential work should remain backend-neutral.

smolvm is attractive because it is Rust-heavy and exposes more than a one-off CLI story. That creates a possible sequence:

  1. Shell out to smolvm CLI for research and prototypes.
  2. Build a backend adapter around stable CLI output and instance handles.
  3. Evaluate the public SDK/server path only after the CLI prototype proves the product value.
  4. Evaluate lower-level Rust/libkrun embedding only if it materially improves launch latency, logs, lifecycle control, or packaging.

Embedding risks:

  • smolvm is pre-1.0 and moving quickly.
  • Public SDK shape may not match jackin’ Rust integration needs.
  • libkrun/libkrunfw binaries and git-lfs assets complicate distribution.
  • macOS Hypervisor.framework entitlements require signing.
  • Linux requires KVM.
  • Owning a library integration makes jackin’ part of the VM-runtime update path.
QuestionDocker hardeningOrbStack isolatedsmolvm
Best near-term default?YesNoNo
Keeps current role Docker workflows?YesLikely, via machine-local DockerUnknown, must test
Stronger kernel boundary than Docker?NoShared OrbStack kernel, not true per-agent VMYes per README
Works on macOS?Yes through Docker backendYesYes
Works on Linux?YesNoYes with KVM
Open source?Docker stack mostly open; Desktop/OrbStack contexts varyNoYes
Rust-native integration potential?LowLowHigh
Mature operator UX?HighHigh on macOSUnknown
Network deny by default?NoDepends on isolated settingsYes per README
  • Install smolvm explicitly in a disposable test environment.
  • Run smolvm machine run --image alpine -- uname -a without network.
  • Run --net --allow-host tests for package registries and blocked hosts.
  • Mount a jackin’ workspace directory and validate read/write behavior.
  • Test read-only mount behavior if available.
  • Test SSH agent forwarding with a non-sensitive key.
  • Record the same smoke matrix against Docker Sandboxes where licensing/access permits: workspace path, network deny/allow, private Docker Engine, credential behavior, attach/restart, and cleanup.
  • Build a jackin’ role image with the current Docker path.
  • Try to boot that OCI image directly through smolvm.
  • Verify jackin-capsule can run, expose a control channel, and attach.
  • Document entrypoint, init, UID/GID, and /jackin/ path gaps.
  • Validate the v0.7.0 Docker-in-smolvm capability.
  • Run docker build, docker run, Compose, and Testcontainers inside smolvm.
  • Compare with current DinD behavior.
  • Compare with Docker Sandboxes as the benchmark for a private Docker daemon inside a VM boundary.
  • Decide whether smolvm can support normal jackin’ roles or only Docker-free roles.
  • Prototype network-deny, allow-host, package-manager, and registry-auth behavior.
  • Decide whether jackin’ can add a host-side proxy layer comparable to Docker Sandboxes without making smolvm support too complex.
  • Prototype credential delivery without raw token files or environment variables where possible.
  • Decide whether SSH agent forwarding is enough for Git-only workflows and how model-provider credentials should be brokered.
  • Add an experimental smolvm backend behind a feature flag or hidden config.
  • Shell out to smolvm.
  • Persist smolvm machine handles in the backend-neutral instance registry.
  • Implement inspect/eject/purge before general launch support.
  • Keep the adapter honest about whether it is direct-image, persistent, or docker-capable.
  • Evaluate CLI, public SDK/server, and lower-level Rust/libkrun integration stability separately.
  • Decide whether any embedding path beats shell-out.
  • Document distribution requirements for macOS signing and Linux KVM.
  • Keep CLI shell-out if embedding would make jackin’ own too much VM-runtime maintenance.

Backend operations should emit debug_log!("smolvm", …) (the existing macro in src/tui/mod.rs). Minimum required lines:

  • smolvm version=<smolvm --version> libkrun=<v> libkrunfw=<v>
  • entitlement_present hypervisor=<yes|no> (macOS)
  • kvm_available=<yes|no> (Linux)
  • machine_create name=<id> image=<ref> rosetta=<yes|no> mode=<ephemeral|persistent|docker-capable>
  • mount source=<host> guest=<path> mode=<rw|ro|tmpfs> validated=<yes|no>
  • network mode=<deny|allowlist|open> allow_hosts=<count>
  • image_pull source=<registry|local> bytes=<n> elapsed_ms=<n>
  • capsule_boot pid=<n> daemon_mode=<forced|inferred> (Mode B PID-2 path)
  • attach transport=<vsock-6000|api-/exec|ssh-via-net> pty=<yes|no>

Compact line per launch:

smolvm launch mode=direct-image image=jackin-the-architect rosetta=no net=allowlist allow_hosts=3 boot_ms=420

This backend introduces these versioned-config additions; each lands with a CURRENT_*_VERSION bump per AGENTS.md:

SurfaceFile kindType touchedAction
[runtime.smolvm] enabled / mode / network / allow_hosts / ssh_agent / cpus / memoryconfig.tomlAppConfigbump CURRENT_CONFIG_VERSION, add fixture.
[workspaces.X.runtime] backend = "smolvm"~/.config/jackin/workspaces/<name>.tomlWorkspaceConfigbump CURRENT_WORKSPACE_VERSION.
[runtime.smolvm] mode = "..." per-role overridejackin.role.tomlRoleManifestbump CURRENT_MANIFEST_VERSION.

Additionally jackin-capsule needs a non-versioned env-var contract: JACKIN_CAPSULE_FORCE_DAEMON=1 to allow daemon mode regardless of PID (see Mode B.1).

  • Integration shape: shell out to smolvm CLI for V1; consume HTTP+OpenAPI via Unix socket if/when richer lifecycle control is needed. No dependency on the workspace’s smolvm library crate (not published, not marketed as stable). No dependency on the Node-only smolvm-napi SDK.
  • macOS distribution: jackin’ bundles or recommends the official smolvm CLI release tarball. Direct libkrun embedding requires com.apple.security.hypervisor entitlement + Apple Developer ID re-signing of the jackin’ binary — too much packaging surface to take on under V1.
  • Linux distribution: smolvm CLI requires KVM. Hosts without KVM fall back to Docker backend with a clear debug_log!("smolvm", "kvm unavailable, falling back") message.
  • TSI cannot do HTTPS credential injection. The credential broker on smolvm needs an in-guest cooperating HTTP proxy + trusted CA, coordinated with the host-bridge daemon. TSI’s role is “enforce all egress routes through the proxy”.
  • Mode B (direct role image) accepts capsule as PID 2 under smolvm-agent (B.1). jackin-capsule gets a JACKIN_CAPSULE_FORCE_DAEMON=1 opt-in for non-PID-1 daemon mode. No upstream patch path under V1.
  • .smolmachine artifacts are not used as jackin’ state primitives. They are a smolvm-internal packaging concern; jackin’ uses smolvm’s machine create/start/exec/delete lifecycle and stores its own per-instance metadata under ~/.jackin/data/<instance>/ per the host-path convention.
  • Multi-arch: on Apple Silicon, jackin’ supports amd64 role images via smolvm --rosetta. Operator gets a debug_log!("smolvm", "running amd64 image under Rosetta, expect slower exec") warning. On Linux/aarch64, amd64 images fail-closed with a clear message — no QEMU TCG fallback.
  • Docker workflows inside smolvm follow the v0.7.0 TSI recipe (Alpine + bind-mounted ext4 + virtio-net), not “OCI role image + Docker layered inside”. Mode B and Mode D therefore stay distinct backends, not a single composable layer.

These need answers before Phase 0 hands-on work converts to design commitments:

  1. JACKIN_CAPSULE_FORCE_DAEMON patch shape: implement the opt-in in crates/jackin-capsule/src/main.rs PID detection. Confirm reaping (SIGCHLD propagation), exit-code visibility, and Ctrl+C behavior all still work when capsule is PID 2 under smolvm-agent. Hands-on test.
  2. smolvm OpenAPI schema shape: export smolvm serve openapi --output spec.json from the v0.7.2 CLI and confirm it covers the endpoints jackin’ would need (/machines, /exec, /logs, /images, /files). If gaps exist, decide whether shell-out is sufficient long-term or whether contributing back to the OpenAPI spec is worth it.
  3. Docker-in-smolvm role-image substitution: try replacing the Alpine base in the docker.smolfile example with a jackin’ role image. If dockerd cannot start because the role’s init differs from Alpine’s, jackin’s “Mode D” is locked to a separate VM running Alpine + Docker, not to the role’s own VM. That reshapes Mode D from “all-in-one” to “sidecar VM”.
  4. Apple Developer ID signing for jackin’ itself: if jackin’ ships smolvm bundled (not just recommended), the bundle needs to be re-signed under the operator’s signing identity (or jackin’s). Establish a CI signing flow before any release that ships smolvm.
  5. Network allowlist coverage (Phase 0): does --allow-host cover DNS resolution, HTTP redirects, registry auth flows (S3-presigned URLs from package mirrors), and CDN failovers? A package manager that hits 4 hosts in one npm install could fail unpredictably under a too-strict allowlist.
  6. .smolmachine interaction with jackin’ purge: even though jackin’ will not create .smolmachine artifacts, if a role baker uses smolvm directly and ships one to operators, does jackin’ know to delete it cleanly on purge? Decide whether smolvm’s image cache under ~/Library/Application Support/smolvm/ becomes part of jackin purge --smolvm or stays smolvm-owned.
  1. Can smolvm boot current jackin’ role OCI images without rebuilding them into a special VM image shape?
  2. Does Docker inside smolvm support Compose and Testcontainers?
  3. Can smolvm expose a stable attach channel for long-running interactive TUI sessions?
  4. Does smolvm’s network allowlist cover DNS, redirects, registry auth, and package-manager mirrors predictably?
  5. How close can smolvm get to Docker Sandboxes’ host-side policy and credential proxy model without jackin’ building a full proxy subsystem first?
  6. Is Docker Sandboxes an integration backend jackin’ should support directly, or only a reference model for what smolvm and OrbStack should approximate?
  7. Does Docker Sandboxes expose enough local API/CLI surface for jackin’ lifecycle control, or is it intentionally agent-runner focused rather than backend-provider focused?
  • Treating a promising README as implementation proof before running jackin’ roles inside it.
  • Letting embeddability distract from the product question: does it run agent sessions better?
  • Shipping a pre-1.0 runtime as a default dependency.
  • Building a Docker-free VM backend that cannot run the roles operators already use.
  • Hiding macOS signing and Linux KVM requirements until launch time.
  • Creating a second persistence model that conflicts with jackin’ purge/eject/recovery semantics.
  • Claiming Docker Sandboxes parity without a host-side credential proxy and auditable network logs.
  • Treating Docker Sandboxes as a reason to stop improving the Docker backend. It is a benchmark and possible later integration target, not a replacement for the near-term Docker hardening contract.
  • Collapsing smolvm, OrbStack, and Docker Sandboxes into one generic “microVM” label. Their boundaries, APIs, product shape, and integration risks are different.
ItemRelationship
Docker runtime hardening contractNear-term default and compatibility baseline.
OrbStack isolated machine backendmacOS polished provider track to compare against smolvm.
Selectable sandbox backendsUmbrella for backend selection.
Network egress policysmolvm allow-host behavior may implement part of the policy.
Session contract and explain modeNeeded to report whether smolvm, OrbStack, or Docker Sandboxes is enforcing each boundary.
Process-level sandboxingLower-overhead alternative for per-operation isolation inside existing Docker sessions.