Getting Started
Getting Started
From a fresh `git clone` to a running agent in ~15 minutes (longer if the first Rust build is cold).
This guide walks you through the single fastest path: start the management server, attach via the dashboard, run a container-runtime agent. Once that works, you can graduate to full KVM VMs (VM path below) or skip the dashboard entirely (direct CLI path).
Already know what you want?
- Container agent in 2 minutes -> Quick path: container runtime
- Full KVM-isolated VM -> VM path: full isolation
- No dashboard, scripted -> Direct CLI path
- Integrate with `aiwg serve` → AIWG Executor docs
0. Verify prerequisites
Run this one-liner to check everything at once. It's read-only and won't change anything:
echo "KVM: $(egrep -c '(vmx|svm)' /proc/cpuinfo 2>/dev/null) (need >0 for VM runtime)" && \
echo "libvirt: $(systemctl is-active libvirtd 2>/dev/null || echo missing)" && \
echo "Docker: $(docker info >/dev/null 2>&1 && echo running || echo missing)" && \
echo "Rust: $(rustc --version 2>/dev/null || echo missing)" && \
echo "protoc: $(protoc --version 2>/dev/null || echo missing)" && \
echo "make: $(make --version 2>/dev/null | head -1 || echo missing)"
Expected for the container path (fastest first run):
- Rust 1.75+, protoc, make, Docker running
Expected for the VM path (full isolation):
- All of the above plus KVM count > 0 and `libvirtd active`
If any are missing, install them:
# Ubuntu/Debian
sudo apt update && sudo apt install -y \
qemu-kvm libvirt-daemon-system protobuf-compiler build-essential
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add yourself to libvirt + kvm groups (for VM runtime)
sudo usermod -aG libvirt,kvm "$USER"
# Log out and back in for group membership to apply
# Docker (skip if not using container runtime)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker "$USER"
1. Clone and build
git clone https://github.com/jmagly/agentic-sandbox.git
cd agentic-sandbox
make build # builds all three crates: management, agent-rs, cli
First-build time: 10–25 minutes on cold caches (Rust + many crates). Subsequent builds are cached.
You'll get three release binaries:
- `management/target/release/agentic-mgmt` — the control plane
- `cli/target/release/sandboxctl` — the CLI (also aliased `agentic-sandbox`)
- `agent-rs/target/release/agent-client` — the in-VM/in-container agent
Optional: symlink the CLI onto your PATH:
ln -sf "$(pwd)/cli/target/release/sandboxctl" ~/.local/bin/
2. Quick path: container runtime
The container path is the fastest way to verify your install works. Container instances start in seconds and don't need KVM.
# Start the management server (foreground; use a second terminal or screen/tmux).
# dev.sh also starts a Docker-reachable gRPC mTLS listener for agents.
cd management && ./dev.sh
# In a second terminal:
# Open the dashboard
xdg-open http://localhost:8122 # or just open this URL in any browser
By default `dev.sh` keeps the dashboard on `http://localhost:8122`, starts plaintext gRPC on loopback for local diagnostics, and starts the agent gRPC mTLS listener on `0.0.0.0:8123`. Container provisioning injects `MANAGEMENT_SERVER=host.docker.internal:8123` and an explicit `AGENT_BOOTSTRAP_ENROLLMENT_URL=http://host.docker.internal:8122/api/v1/bootstrap-enrollment/consume`, so bootstrap enrollment and mTLS registration do not depend on fixed port offsets.
If Docker containers cannot reach `host.docker.internal:8122`, bootstrap will fail before the mTLS handshake. Start the Docker-agent dev recipe with a Docker-reachable HTTP bind and explicit plaintext acknowledgement:
cd management
LISTEN_ADDR=0.0.0.0:8120 AGENTIC_ALLOW_PLAINTEXT_TCP=1 ./dev.sh start
Without `AGENTIC_ALLOW_PLAINTEXT_TCP=1`, `dev.sh` refuses this bind before launching management so the failure is actionable instead of surfacing as a generic health timeout. You can also keep `LISTEN_ADDR=127.0.0.1:8120` and override `AGENTIC_CONTAINER_BOOTSTRAP_ENROLLMENT_URL` to an HTTP origin reachable from the container. The long-lived control stream still uses the mTLS listener and the enrolled SPIFFE client identity.
In the dashboard:
1. Click + Create Instance (top of sidebar). 2. Runtime: select Container. 3. Image: pick `agentic/claude:latest` (or `codex`, `opencode`). 4. Name: anything matching `[a-z0-9-]+` (e.g. `agent-01`). 5. Click Create. The instance appears in the sidebar within ~2 seconds. 6. Click the row → click 📺 Pane to attach a live terminal.
You now have a sandboxed agent process. The dashboard shows live PTY output, lets you submit tasks, and reports HITL prompts.
Same flow from the CLI
sandboxctl config set-context local --server http://localhost:8122
sandboxctl container create agent-01 --image agentic/claude:latest
sandboxctl agent list
sandboxctl session list --agent agent-01
sandboxctl session attach <session-id> --write # Ctrl-A d to detach
3. VM path: full isolation
If you want hardware-level isolation (each agent gets its own kernel), use the VM runtime.
Additional prerequisite: an Ubuntu 24.04 base image. Build it once:
cd images/qemu
./build-base-image.sh 24.04 # ~5–15 min, depending on network speed
This downloads the Ubuntu cloud image, verifies its checksum, and stages it for fast cloning.
Then from the dashboard:
1. + Create Instance → Runtime: VM → pick a loadout (`claude-only`, `dual-review`, `full-suite`). 2. Create. VM provision time: 30 s – 10 min depending on loadout (loadouts that install Claude Code / Codex CLI take longer). 3. The VM appears with a `[VM]` badge. Attach via the Pane button. Direct runtime SSH is reserved for dev/break-glass use because it bypasses the gateway policy and audit model described in `ADR-029`.
The VM agent connects back to the management server automatically on boot.
Same flow from the CLI
sandboxctl vm create agent-02 --loadout profiles/claude-only.yaml --agentshare --start
See LOADOUTS.md for the full loadout reference and container-runtime.md for the container variant.
4. Direct CLI path
Want to provision a single VM without the management server? The provisioner runs standalone:
./images/qemu/provision-vm.sh agent-01 \
--loadout profiles/claude-only.yaml \
--agentshare \
--start
# Agent inside the VM will try to dial host.internal:8120. Direct runtime SSH
# is only a dev/break-glass bypass path; managed access uses the
# gateway-mediated SSH model from ADR-029 — now available via the SSH
# certificate lease API (POST /api/v2/gateway/ssh/leases) and `sandboxctl ssh`.
Useful flags: `--profile basic`, `--cpus 8 --memory 16G --disk 100G`, `--network-mode isolated|allowlist|full`. Full reference: images/qemu/README.md.
5. Submit your first task
Once an agent is running, submit a task via the dashboard, the CLI, or REST.
Dashboard
Click your agent → Tasks tab → + New Task → paste a prompt → Submit.
CLI
cat > task.yaml <<'EOF'
version: "1"
kind: Task
metadata:
id: ""
name: "Workspace summary"
repository:
url: "https://github.com/example/repo.git"
branch: "main"
claude:
prompt: "List the files in /workspace and summarize what you see."
model: "claude-sonnet-4-5-20250929"
lifecycle:
timeout: "5m"
EOF
sandboxctl task submit --file task.yaml --wait
REST
curl -X POST http://localhost:8122/api/v1/tasks \
-H "Content-Type: application/json" \
-d '{
"manifest": {
"version": "1",
"kind": "Task",
"metadata": {
"id": "",
"name": "Workspace summary"
},
"repository": {
"url": "https://github.com/example/repo.git",
"branch": "main"
},
"claude": {
"prompt": "List the files in /workspace and summarize what you see.",
"model": "claude-sonnet-4-5-20250929"
},
"lifecycle": {
"timeout": "5m"
}
}
}'
Task lifecycle, HITL prompts, and event streaming are covered in task-orchestration-api.md.
6. What's next?
You have a working install. Pick the path that matches what you want to do next:
| If you want to… | Go to… |
|---|---|
| Understand the surfaces (admin / A2A / observability) | concepts.md, v2-migration-guide.md |
| Run AIWG missions on this executor | aiwg-executor.md |
| Tune VM/container resource limits | DEPLOYMENT.md, OPERATIONS.md |
| Build custom loadouts | LOADOUTS.md |
| Hook the dashboard into monitoring | monitoring.md, observability/ |
| Troubleshoot a stuck install | TROUBLESHOOTING.md, crash-loop.md |
| Understand the API surface in depth | API.md, ws-protocol.md |
| See the full architecture | ARCHITECTURE.md, ECOSYSTEM.md |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| `./dev.sh` fails with "binary not found" | `make build` not run yet | Run `make build` from repo root first |
| Dashboard loads but instance creation fails | Docker not running (container path) or libvirtd not running (VM path) | `systemctl start docker` or `systemctl start libvirtd` |
| VM provision hangs at "waiting for cloud-init" | First boot is slow; SSH not yet ready | Wait ~60 s, then retry; check `virsh console <vm-name>` |
| "Agent transport identity required" in agent logs | Agent connected without UDS, vsock, or mTLS identity | Reprovision with secure transport or bootstrap enrollment |
| Browser shows "connection refused" | Management server not listening on 8122 | `cd management && ./dev.sh logs` to see startup errors |
| `protoc` missing during build | Protocol Buffers compiler not installed | `sudo apt install protobuf-compiler` or `brew install protobuf` |
For anything not in this table, check TROUBLESHOOTING.md or open an issue at https://github.com/jmagly/agentic-sandbox/issues.