smolvm Backend Research
Status: Open — research and design proposal
Problem
Section titled “Problem”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.
Source Material
Section titled “Source Material”Primary source: smol-machines/smolvm.
Comparison sources:
- smol machines product/docs site - positioning, usage examples, network defaults,
.smolmachine, platform matrix, and comparison table. - smolvm SDK overview - current SDK shape, language bindings, server requirement, and machine API surface.
- Docker Sandboxes - Docker’s productized agent sandbox runtime.
- Docker Sandboxes architecture - workspace mounting, persistence, networking, lifecycle, and alternatives.
- Docker Sandboxes security model and isolation layers - hypervisor, network, private Docker Engine, and credential proxy boundaries.
- OrbStack architecture, machines, and release notes - shared-kernel machine model, isolated machines, selective sharing, and host/machine network controls.
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,
.smolmachineportable 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.0mention “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.
Verified architecture (May 2026)
Section titled “Verified architecture (May 2026)”A research pass through the smol-machines/smolvm repository established several facts that change the design surface jackin’ has to plan against:
| Aspect | Verified fact | Source |
|---|---|---|
| PID 1 inside the VM | smolvm-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 runtime | crates/smolvm-agent/src/main.rs, crates/smolvm-agent/src/oci.rs |
| Rust SDK / library crate | Workspace 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 absent | Cargo.toml, sdks/README.md |
| Server transport | HTTP 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.json | src/cli/serve.rs, src/api/mod.rs, src/cli/openapi.rs |
libkrunfw distribution | Bundled 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 tarballs | sdks/README.md |
| macOS code-signing entitlement | Single key: com.apple.security.hypervisor. NOT com.apple.vm.networking | containers/libkrun/hvf-entitlements.plist |
| TSI for credential proxy | TSI 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 alone | libkrun README |
| Docker-in-smolvm via TSI | PR #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 artifact | zstd-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 compatibility | crates/smolvm-pack/src/format.rs |
| Multi-arch | Yes 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 fallback | src/vm/rosetta.rs |
Comparison Target
Section titled “Comparison Target”This research should compare only three post-Docker-hardening options:
- OrbStack isolated machines - pragmatic macOS backend for operators already using OrbStack.
- smolvm - open-source Rust/libkrun VM backend candidate.
- 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”| Concern | OrbStack isolated machine | smolvm | Docker Sandboxes |
|---|---|---|---|
| Product shape | Polished macOS app and CLI | Open-source CLI/library-oriented runtime | Productized Docker CLI/service for agent sandboxes |
| License/control | Proprietary | Apache-2.0 | Commercial Docker product surface around a proprietary service/runtime |
| Implementation fit | Shell out to orb | Shell out first; SDK/server or Rust embedding requires validation | Shell out to sbx or integrate around Docker’s sandbox workflow if APIs allow |
| Boundary wording | Isolated machine, shared kernel per OrbStack docs | VM per workload with its own kernel per smolvm README | Dedicated microVM per sandbox per Docker docs |
| Platform | macOS only | macOS and Linux with KVM | macOS, Windows, and Linux per Docker docs |
| Docker compatibility | Install/start Docker inside machine | OCI images boot without Docker daemon; Docker-in-guest needs research | Private Docker Engine is a core feature |
| File sharing | OrbStack selective shares | Directory volume mounts | Workspace mounted directly at the same absolute host path |
| Network policy | Isolated-machine host/machine blocking plus future jackin policy | Network off by default, --allow-host allowlist | Host-side proxy, allow/deny policy, raw TCP/UDP/ICMP blocked by default per docs |
| Credential posture | jackin must provide its own credential model | jackin must provide its own credential model | Host-side credential proxy injects selected outbound API auth per docs |
| Maturity risk | Mature operator product | Pre-1.0 fast-moving runtime | New product surface but backed by Docker’s ecosystem |
| Strategic value | Best macOS user experience | Best open Rust-native backend candidate | Best 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 Baseline
Section titled “Docker Sandboxes Baseline”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, anddocker composewithout 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 VMsmolvm 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.
.smolmachineartifacts 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.
What OrbStack Currently Does Better
Section titled “What OrbStack Currently Does Better”Expected advantages unless smolvm proves otherwise:
- Best macOS developer experience for operators already using OrbStack as their Docker backend.
- Full Linux machine lifecycle with
orbcommands, 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.
Decision Frame
Section titled “Decision Frame”The comparison should produce separate conclusions, not a single winner:
| Desired capability | Likely best first path |
|---|---|
| Improve today’s local default | Docker runtime hardening |
| macOS isolated backend with strong UX | OrbStack isolated machine |
| Open source Rust-native VM backend | smolvm |
| Private Docker daemon inside a VM with policy proxy | Docker Sandboxes as benchmark, smolvm/OrbStack as prototypes |
| Team-managed policy and paid enterprise controls | Docker Sandboxes benchmark only unless jackin’ builds its own governance |
| Cross-platform local VM backend beyond macOS | smolvm research |
| Hosted hostile multi-tenant execution | Out of scope for this item |
Research whether smolvm can support one or more jackin’ backend modes:
- Ephemeral command sandbox: run one agent/tool command in a short-lived microVM for high-risk operations.
- Docker-free role backend: boot a role OCI image directly as a smolvm workload without a Docker daemon.
- Persistent machine backend: create one smolvm machine per jackin’ instance, preserve agent state, and reconnect later.
- Docker-capable VM backend: run Docker-compatible workflows inside the smolvm boundary if the
v0.7.0Docker-in-smolvm work is usable. - 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.
Non-Goals
Section titled “Non-Goals”- 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.
Backend Vocabulary
Section titled “Backend Vocabulary”Use a name that distinguishes this from OrbStack:
smolvmPossible future CLI:
jackin load reviewer . --backend smolvmjackin load reviewer . --backend smolvm --vm-mode ephemeraljackin load the-architect . --backend smolvm --vm-mode persistentPossible future config:
[runtime.smolvm]enabled = falsemode = "persistent" # ephemeral | direct-image | persistent | docker-capablenetwork = "deny" # deny | allowlist | openallow_hosts = ["github.com", "api.openai.com"]ssh_agent = "ask" # off | ask | oncpus = 4memory = "8 GiB"This schema is intentionally speculative. If it lands in versioned config, it must follow the migration rules.
Implementation Hypotheses
Section titled “Implementation Hypotheses”Mode A — ephemeral operation sandbox
Section titled “Mode A — ephemeral operation sandbox”Run a single command or classified high-risk operation inside smolvm:
jackin role container -> asks host/capsule bridge for sandboxed commandhost jackin -> smolvm machine run --image <tool-image> -- <command>smolvm -> exits and deletes stateBest 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.
Mode B — direct role image backend
Section titled “Mode B — direct role image backend”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:
| Option | Shape | Trade-off |
|---|---|---|
| B.1 — capsule as PID 2 under smolvm-agent | jackin-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 channel | Loses 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 fork | Submit 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-agent | Upstream 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.
Mode C — persistent smolvm instance
Section titled “Mode C — persistent smolvm instance”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
.smolmachineexport/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.
Mode D — Docker-capable smolvm backend
Section titled “Mode D — Docker-capable smolvm backend”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/dockermust 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_FSis required. --net-backend virtio-netis 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?
.smolmachinepersistence interacts with/storage/dockerlifecycle.
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 runpass 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.
Network Policy
Section titled “Network Policy”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 policy | smolvm mapping to validate |
|---|---|
| deny | omit --net |
| allowlist | --net --allow-host <host> for each allowed host |
| open | --net without allow-host restriction |
| private network blocked | validate 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.
Filesystem And Mounts
Section titled “Filesystem And Mounts”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.
Authentication
Section titled “Authentication”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.
Packaging And Embedding
Section titled “Packaging And Embedding”smolvm is attractive because it is Rust-heavy and exposes more than a one-off CLI story. That creates a possible sequence:
- Shell out to
smolvmCLI for research and prototypes. - Build a backend adapter around stable CLI output and instance handles.
- Evaluate the public SDK/server path only after the CLI prototype proves the product value.
- 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.
Comparison With The Other Two Tracks
Section titled “Comparison With The Other Two Tracks”| Question | Docker hardening | OrbStack isolated | smolvm |
|---|---|---|---|
| Best near-term default? | Yes | No | No |
| Keeps current role Docker workflows? | Yes | Likely, via machine-local Docker | Unknown, must test |
| Stronger kernel boundary than Docker? | No | Shared OrbStack kernel, not true per-agent VM | Yes per README |
| Works on macOS? | Yes through Docker backend | Yes | Yes |
| Works on Linux? | Yes | No | Yes with KVM |
| Open source? | Docker stack mostly open; Desktop/OrbStack contexts vary | No | Yes |
| Rust-native integration potential? | Low | Low | High |
| Mature operator UX? | High | High on macOS | Unknown |
| Network deny by default? | No | Depends on isolated settings | Yes per README |
Implementation Phases
Section titled “Implementation Phases”Phase 0 — hands-on smoke
Section titled “Phase 0 — hands-on smoke”- Install smolvm explicitly in a disposable test environment.
- Run
smolvm machine run --image alpine -- uname -awithout network. - Run
--net --allow-hosttests 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.
Phase 1 — role-image compatibility
Section titled “Phase 1 — role-image compatibility”- Build a jackin’ role image with the current Docker path.
- Try to boot that OCI image directly through smolvm.
- Verify
jackin-capsulecan run, expose a control channel, and attach. - Document entrypoint, init, UID/GID, and
/jackin/path gaps.
Phase 2 — Docker workflow compatibility
Section titled “Phase 2 — Docker workflow compatibility”- Validate the
v0.7.0Docker-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.
Phase 3 — policy and credential parity
Section titled “Phase 3 — policy and credential parity”- 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.
Phase 4 — backend adapter prototype
Section titled “Phase 4 — backend adapter prototype”- Add an experimental
smolvmbackend 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, ordocker-capable.
Phase 5 — SDK and packaging decision
Section titled “Phase 5 — SDK and packaging decision”- 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.
Telemetry Surface
Section titled “Telemetry Surface”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=420Schema Migration Footprint
Section titled “Schema Migration Footprint”This backend introduces these versioned-config additions; each lands with a CURRENT_*_VERSION bump per AGENTS.md:
| Surface | File kind | Type touched | Action |
|---|---|---|---|
[runtime.smolvm] enabled / mode / network / allow_hosts / ssh_agent / cpus / memory | config.toml | AppConfig | bump CURRENT_CONFIG_VERSION, add fixture. |
[workspaces.X.runtime] backend = "smolvm" | ~/.config/jackin/workspaces/<name>.toml | WorkspaceConfig | bump CURRENT_WORKSPACE_VERSION. |
[runtime.smolvm] mode = "..." per-role override | jackin.role.toml | RoleManifest | bump 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).
Decided In This Pass
Section titled “Decided In This Pass”- Integration shape: shell out to
smolvmCLI for V1; consume HTTP+OpenAPI via Unix socket if/when richer lifecycle control is needed. No dependency on the workspace’ssmolvmlibrary crate (not published, not marketed as stable). No dependency on the Node-onlysmolvm-napiSDK. - macOS distribution: jackin’ bundles or recommends the official smolvm CLI release tarball. Direct
libkrunembedding requirescom.apple.security.hypervisorentitlement + 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-capsulegets aJACKIN_CAPSULE_FORCE_DAEMON=1opt-in for non-PID-1 daemon mode. No upstream patch path under V1. .smolmachineartifacts are not used as jackin’ state primitives. They are a smolvm-internal packaging concern; jackin’ uses smolvm’smachine create/start/exec/deletelifecycle 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 adebug_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.
Open Before Implementation Can Start
Section titled “Open Before Implementation Can Start”These need answers before Phase 0 hands-on work converts to design commitments:
JACKIN_CAPSULE_FORCE_DAEMONpatch shape: implement the opt-in incrates/jackin-capsule/src/main.rsPID 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.- smolvm OpenAPI schema shape: export
smolvm serve openapi --output spec.jsonfrom 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. - Docker-in-smolvm role-image substitution: try replacing the Alpine base in the
docker.smolfileexample with a jackin’ role image. Ifdockerdcannot 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”. - 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.
- Network allowlist coverage (Phase 0): does
--allow-hostcover DNS resolution, HTTP redirects, registry auth flows (S3-presigned URLs from package mirrors), and CDN failovers? A package manager that hits 4 hosts in onenpm installcould fail unpredictably under a too-strict allowlist. .smolmachineinteraction with jackin’ purge: even though jackin’ will not create.smolmachineartifacts, 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 ofjackin purge --smolvmor stays smolvm-owned.
Open Questions
Section titled “Open Questions”- Can smolvm boot current jackin’ role OCI images without rebuilding them into a special VM image shape?
- Does Docker inside smolvm support Compose and Testcontainers?
- Can smolvm expose a stable attach channel for long-running interactive TUI sessions?
- Does smolvm’s network allowlist cover DNS, redirects, registry auth, and package-manager mirrors predictably?
- How close can smolvm get to Docker Sandboxes’ host-side policy and credential proxy model without jackin’ building a full proxy subsystem first?
- Is Docker Sandboxes an integration backend jackin’ should support directly, or only a reference model for what smolvm and OrbStack should approximate?
- 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?
Risks and Design Traps
Section titled “Risks and Design Traps”- 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.
Related Files
Section titled “Related Files”src/runtime/launch.rs- launch orchestration that needs a backend split.src/runtime/image.rs- role image build path and OCI artifact source.src/instance/manifest.rs- future backend/provider handles.docker/runtime/entrypoint.sh- capsule startup assumptions.docker/construct/Dockerfile- role base image to test as a smolvm workload.
Related Roadmap Items
Section titled “Related Roadmap Items”| Item | Relationship |
|---|---|
| Docker runtime hardening contract | Near-term default and compatibility baseline. |
| OrbStack isolated machine backend | macOS polished provider track to compare against smolvm. |
| Selectable sandbox backends | Umbrella for backend selection. |
| Network egress policy | smolvm allow-host behavior may implement part of the policy. |
| Session contract and explain mode | Needed to report whether smolvm, OrbStack, or Docker Sandboxes is enforcing each boundary. |
| Process-level sandboxing | Lower-overhead alternative for per-operation isolation inside existing Docker sessions. |