Isolated Linux machines for agents. On your laptop, your servers, or our cloud.
This repo holds the dock CLI, with its built-in local engine, and the docklet, the host agent for Dock. One docklet runs on each machine that hosts docks. It boots, pauses, snapshots, resumes and destroys docks, and reports what the host actually has.
curl -fsSL https://usedock.io/install | sh # Linux, macOS
irm https://usedock.io/install.ps1 | iex # Windows (PowerShell)Both installers verify the release checksums and cosign signatures before installing the dock CLI.
With no account, dock runs docks on your own machine (the built-in local context). You need QEMU and KVM on Linux (x86_64 or arm64), or QEMU and Windows Hypervisor Platform on Windows x86_64; dock doctor tells you what is missing.
curl -fsSL https://usedock.io/install | sh
dock new demo
dock exec demo -- uname -aThe first dock new downloads the default ubuntu-24.04 Dockyard image once. On Windows, install with the PowerShell line above.
The first dock new downloads the image; the recording skips that wait.
Docs: quickstart, CLI, local docks, Windows, Dockyard images.
Questions and ideas: GitHub Discussions.
Status: the
dockCLI ships in signed releases (since v0.1.0). From v0.2.0 it runs docks locally with no account on Linux (x86_64, and arm64 from v0.3.0) with KVM and Windows x86_64 with Windows Hypervisor Platform, via QEMU; macOS builds but is untested. The docklet host agent is early, and Windows and macOS fleet hosts are planned.
- Runs docks as Firecracker microVMs (under
jailer) on Linux with KVM, or as gVisor (runsc) containers on Linux with Docker. - Enforces each dock's CPU and memory with cgroups, gives each dock a fixed-size disk (a sparse rootfs on microvm, a size-limited work volume at
/home/user/workon gVisor), and gives it a TAP or veth network on a host-local subnet. - Moves snapshot data to the object store over presigned URLs the control plane mints, or through its object proxy; the host never holds store credentials.
- Connects outbound only to the control plane fleet API: it registers, sends heartbeats with its inventory and stats, long-polls for commands and posts results. No inbound port, no per-host address.
- Serves its own HTTP API on loopback only.
- Fails closed: a host is not offered work until its readiness checks pass.
| Host | Engine | Status |
|---|---|---|
| Linux with KVM | Firecracker | Early, in signed releases |
| Linux with Docker | gVisor | Early, in signed releases |
| Windows x86_64 (fleet host) | docklet daemon on Windows | Planned |
| macOS, Apple silicon (fleet host) | docklet daemon on macOS | Planned |
A snapshot moves only between hosts with the same engine and CPU architecture.
The dock binary carries its own engine and runs docks on your own machine with QEMU. The engine needs QEMU and the machine's hardware accelerator; it never falls back to software emulation on its own.
| Machine | Accelerator | Status |
|---|---|---|
| Linux x86_64 | KVM (/dev/kvm) |
Available |
| Linux arm64 | KVM (/dev/kvm) |
Available from v0.3.0 (tested under emulation so far) |
| Windows x86_64 | Windows Hypervisor Platform (WHPX) | Available |
| macOS | Hypervisor.framework (HVF) | Untested, planned |
dock doctor checks what is missing. On Windows, enable the platform once (elevated PowerShell, then reboot) and install QEMU:
Enable-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform
winget install SoftwareFreedomConservancy.QEMUOn a Linux machine without usable KVM (for example a cloud VM without nested virtualization), local docks can run as gVisor (runsc) containers through Docker. It is opt-in: dock new --runtime gvisor or DOCK_LOCAL_RUNTIME=gvisor; without it local docks stay QEMU only. Setup, differences from QEMU docks, the host network block, --network off, dock branch and push and pull are in docs/gvisor.md.
cmd/docklet/- the daemon.cmd/gen-fast-agent/- guest agent generator.cmd/dock/+internal/cli/- the portabledockCLI.api/v1/- the versioned contract with the control plane.internal/-agent(fleet channel),fc(Firecracker),container(gVisor),host(orchestration),snapmgr(snapshots),net,egress,disk,store,serverand more.scripts/- host bootstrap, image and kernel builders.DEPLOY.md- the full host deploy guide.
One command per machine, run as root on Ubuntu from a checkout of this repo. It installs the runtime, the signature-verified docklet release and a systemd unit, then enrolls the host with your control plane (usedock/dock):
sudo bash scripts/bootstrap-host.sh \
--fleet-url https://dock.example.com \
--fleet-token "$FLEET_TOKEN" \
--runtime microvm # or gvisorPick microvm on Linux with KVM or gvisor on any Linux with Docker. The script is re-runnable. See DEPLOY.md for flags, base images and troubleshooting.
A microvm host boots from the signed Dockyard ubuntu-24.04 (pulled at bootstrap; --build-base or an unreachable Dockyard falls back to building it on the host), so a dock's whole disk can move between hosts and contexts. A snapshot with full: true writes a checksummed rootfs.ext4.zst, and restoring one verifies it. See DEPLOY.md.
cmd/dock runs docks locally (the built-in local context, no account) or talks to the Dock control plane /v1 API (the cloud context and added URLs; not this daemon). It builds on Linux, macOS and Windows; released binaries come from the installer above.
go build -o dock ./cmd/dock # or use the installed release
dock doctor # what local docks need: QEMU, accelerator, disk, Dockyard
dock images # Dockyard images; `dock images pull ubuntu-24.04` downloads one
dock new web # with no account this boots a local dock (downloads the image once)
dock login # prompts without echo; or: echo "$DOCK_API_KEY" | dock login
dock new web --cpus 4 --memory 8gb --disk 40gb --env staging # returns once the dock is ready
dock push web --to lab # copy a stopped local dock's disk to a control plane context (--name, --stop, --rm)
dock push gv --to lab --disk 20gb # a gVisor dock: pushes only /home/user/work (--image, --disk)
dock pull web --from lab --name web-local # copy a fleet dock's disk to a new stopped local dock (Dockyard-image docks only)
dock pull web --from lab --runtime gvisor # no KVM: copy only /home/user/work into a new stopped gVisor dock
dock ls
dock exec web -- uname -a # exits with the command's exit code
dock ssh web # runs ssh against the Dock SSH gateway (--print to show it)
dock port web 3000 # prints the public URL
dock branch web --count 2
dock stop web && dock resume web && dock rm web-
Every command accepts
--jsonand prints the API data. Errors printerror: <code>: <message>to stderr and exit 1; usage errors exit 2. -
Sizes:
8gb,8g,8192mb; a plain number is MiB for memory and GiB for disk. -
<dock>is a name or id.dock newreads./dock.toml(name,image,cpus,memory,disk,environment); flags override it and unknown keys are an error. -
Local context: the default until
dock loginstores a key orDOCK_API_KEY/DOCK_API_URLis set; switch withdock context use local|cloud. Local docks live under$XDG_DATA_HOME/dock(Linux),~/Library/Application Support/dock(macOS) or%LOCALAPPDATA%\dock(Windows) (DOCK_DATA_DIRoverrides): a qcow2 overlay on the cached Dockyard base image, the agent token, forwarded port and pid.--jsonkeeps the API's keys;runtimeisqemu(orgvisor, see docs/gvisor.md) and a stopped dock isarchived. Local differences:dock new --network offblocks the dock's network (QEMUrestrict=on; IPv6 is always disabled in the guest network),dock portforwards a dock port to127.0.0.1in the foreground (no public URL),dock sshopens a shell through the guest agent,dock branchcopies the stopped disk (a running dock is stopped, copied and resumed; there is no live fork), anddock stoppowers the guest off and keeps the disk.execreturns when the command ends. Settings:DOCK_QEMU(qemu-system binary),DOCK_DOCKYARD_URLandDOCK_DOCKYARD_SHA256(use another image index; it is unpinned and warned about, and verified only when the hash is given). The dock binary pins the images release tag and the sha256 of itsdockyard.json, and refuses an index that does not match.DOCK_LOCAL_ACCEL=tcgallows slow software emulation (tests only; local docks never fall back to it on their own). -
Local network isolation, trust properties: QEMU user-mode networking (slirp) maps the gateway
10.0.2.2to the host's127.0.0.1, and QEMU has no option to turn that off (itsrestrict=onis all or nothing). With--network on(the default) the dock therefore asks its guest to refuse connections to10.0.2.2(an iptables rule applied at boot from the dock's config; DNS, the internet and the agent forward are unaffected). This stops code that accidentally probeslocalhostservices,dock portforwards of other docks included, but it is a guest-side control: root inside the dock can remove the rule, and images released before this change ignore it. Each dock's agent forward needs that dock's random token, so one dock cannot run commands in another. Treat a network-on local dock as able to reach your localhost services if it is hostile; use--network offfor untrusted code. A user-space network stack indock(a host-enforced fix) is tracked in #98. -
Contexts:
dock context add|use|ls|rm. The built-incloudcontext points athttps://api.usedock.io. Config lives inos.UserConfigDir()/dock/config.toml(mode 0600).DOCK_API_URL,DOCK_API_KEYandDOCK_WORKSPACEoverride the active context. -
Workspace for
dock new:--workspace, thenDOCK_WORKSPACE, then the context default (dock context use <name> --workspace <id>), then your only workspace. With several workspaces and none chosen,dock newfails and lists them. -
Push and pull move the disk only (no memory, no running processes), between
localand a control plane context with a microVM host.dock pushflattens the stopped dock's disk, compresses it with zstd, checks it with sha256 and uploads it in retried parts;dock pullexports, downloads with resume, verifies, and registers a stopped local dock on the Dockyard image it came from. Runtime files are never sent. The flattened disk does hold the guest's own copy of the dock's local token, sodock pushrotates the local token (the copy that leaves stops working), and a pulled dock gets a new local token. A push or pull checks free space first, and staletmp/xfer-*leftovers from a crashed run are removed on the next one. gVisor docks push and pull only/home/user/work; see Push and pull. -
Not yet:
dock cp(the API has no file endpoint for live docks) and streamingexecoutput (the exec API returns the bounded result when the command ends).
Linux only, Go 1.25.
go build ./...
go vet ./...
go test ./...
go test ./internal/host/ # one packageOn Windows or macOS, GOOS=linux go vet ./... and go test -exec=true ./... check that everything compiles; CI runs the real tests. Every behavior change ships with go test coverage. Fakes live in *_test.go, never in production code. api/v1 is the versioned contract with the control plane; publishing JSON fixtures for every call is planned. Agents working in this repo: see AGENTS.md.
Contributions are welcome. Every contributor signs the CLA; the CLA bot asks on your first pull request in each repository. See CONTRIBUTING.md.
Report vulnerabilities to security@usedock.io, not in public issues. See SECURITY.md. Releases are signed with cosign (keyless, GitHub OIDC) and ship checksums.txt; the install script stops if the checksum or signature is missing or bad. See the release verification section of DEPLOY.md.
Copyright (C) 2026 Paranjay.
