Finish the 3.1.0 secondary disk-tools milestone so stable workspaces can be stopped, inspected offline, exported as raw ext4 images, and started again without changing the primary workspace-first interaction model. Add workspace stop/start plus workspace disk export/list/read across the CLI, SDK, and MCP, backed by a new offline debugfs inspection helper and guest-only validation. Scrub runtime-only guest state before disk inspection/export, and fix the real guest reliability gaps by flushing the filesystem on stop and removing stale Firecracker socket files before restart. Update the docs, examples, changelog, and roadmap to mark 3.1.0 done, and cover the new lifecycle/disk paths with API, CLI, manager, contract, and package-surface tests. Validation: uv lock; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed smoke for create, shell/service activity, stop, workspace disk list/read/export, start, exec, and delete.
290 lines
11 KiB
Markdown
290 lines
11 KiB
Markdown
# Install
|
|
|
|
## Support Matrix
|
|
|
|
Supported today:
|
|
|
|
- Linux x86_64
|
|
- Python 3.12+
|
|
- `uv`
|
|
- `/dev/kvm`
|
|
|
|
Optional for outbound guest networking:
|
|
|
|
- `ip`
|
|
- `nft` or `iptables`
|
|
- privilege to create TAP devices and configure NAT
|
|
|
|
Not supported today:
|
|
|
|
- macOS
|
|
- Windows
|
|
- Linux hosts without working KVM at `/dev/kvm`
|
|
|
|
If you do not already have `uv`, install it first:
|
|
|
|
```bash
|
|
python -m pip install uv
|
|
```
|
|
|
|
Use these command forms consistently:
|
|
|
|
- published package without install: `uvx --from pyro-mcp pyro ...`
|
|
- installed package: `pyro ...`
|
|
- source checkout: `uv run pyro ...`
|
|
|
|
## Fastest Evaluation Path
|
|
|
|
Use either of these equivalent evaluator paths:
|
|
|
|
```bash
|
|
# Package without install
|
|
uvx --from pyro-mcp pyro doctor
|
|
uvx --from pyro-mcp pyro env list
|
|
uvx --from pyro-mcp pyro env pull debian:12
|
|
uvx --from pyro-mcp pyro run debian:12 -- git --version
|
|
```
|
|
|
|
```bash
|
|
# Already installed
|
|
pyro doctor
|
|
pyro env list
|
|
pyro env pull debian:12
|
|
pyro run debian:12 -- git --version
|
|
```
|
|
|
|
If you are running from a repo checkout instead, replace `pyro` with `uv run pyro`.
|
|
|
|
After that one-shot proof works, continue into the stable workspace path with `pyro workspace ...`.
|
|
|
|
### 1. Check the host first
|
|
|
|
```bash
|
|
uvx --from pyro-mcp pyro doctor
|
|
```
|
|
|
|
Expected success signals:
|
|
|
|
```bash
|
|
Platform: linux-x86_64
|
|
Runtime: PASS
|
|
KVM: exists=yes readable=yes writable=yes
|
|
Environment cache: /home/you/.cache/pyro-mcp/environments
|
|
Capabilities: vm_boot=yes guest_exec=yes guest_network=yes
|
|
Networking: tun=yes ip_forward=yes
|
|
```
|
|
|
|
If `Runtime: FAIL`, stop here and use [troubleshooting.md](troubleshooting.md).
|
|
|
|
### 2. Inspect the catalog
|
|
|
|
```bash
|
|
uvx --from pyro-mcp pyro env list
|
|
```
|
|
|
|
Expected output:
|
|
|
|
```bash
|
|
Catalog version: 3.1.0
|
|
debian:12 [installed|not installed] Debian 12 environment with Git preinstalled for common agent workflows.
|
|
debian:12-base [installed|not installed] Minimal Debian 12 environment for shell and core Unix tooling.
|
|
debian:12-build [installed|not installed] Debian 12 environment with Git and common build tools preinstalled.
|
|
```
|
|
|
|
### 3. Pull the default environment
|
|
|
|
```bash
|
|
uvx --from pyro-mcp pyro env pull debian:12
|
|
```
|
|
|
|
The first pull downloads an OCI environment from public Docker Hub, requires outbound HTTPS
|
|
access to `registry-1.docker.io`, and needs local cache space for the guest image. See
|
|
[host-requirements.md](host-requirements.md) for the full host requirements.
|
|
|
|
Expected success signals:
|
|
|
|
```bash
|
|
[pull] phase=install environment=debian:12
|
|
[pull] phase=ready environment=debian:12
|
|
Pulled: debian:12
|
|
...
|
|
```
|
|
|
|
### 4. Run one command in a guest
|
|
|
|
```bash
|
|
uvx --from pyro-mcp pyro run debian:12 -- git --version
|
|
```
|
|
|
|
Expected success signals:
|
|
|
|
```bash
|
|
[run] phase=create environment=debian:12
|
|
[run] phase=start vm_id=...
|
|
[run] phase=execute vm_id=...
|
|
[run] environment=debian:12 execution_mode=guest_vsock exit_code=0 duration_ms=...
|
|
git version ...
|
|
```
|
|
|
|
The guest command output and the `[run] ...` summary are written to different streams, so they
|
|
may appear in either order in terminals or capture tools. Use `--json` if you need a
|
|
deterministic structured result.
|
|
|
|
If guest execution is unavailable, the command fails unless you explicitly pass
|
|
`--allow-host-compat`.
|
|
|
|
## 5. Continue into the stable workspace path
|
|
|
|
The commands below use plain `pyro ...`. Run the same flow with `uvx --from pyro-mcp pyro ...`
|
|
for the published package, or `uv run pyro ...` from a source checkout.
|
|
|
|
```bash
|
|
uv tool install pyro-mcp
|
|
WORKSPACE_ID="$(pyro workspace create debian:12 --seed-path ./repo --json | python -c 'import json,sys; print(json.load(sys.stdin)["workspace_id"])')"
|
|
pyro workspace sync push "$WORKSPACE_ID" ./changes
|
|
pyro workspace exec "$WORKSPACE_ID" -- cat note.txt
|
|
pyro workspace snapshot create "$WORKSPACE_ID" checkpoint
|
|
pyro workspace service start "$WORKSPACE_ID" web --ready-file .web-ready -- sh -lc 'touch .web-ready && while true; do sleep 60; done'
|
|
pyro workspace reset "$WORKSPACE_ID" --snapshot checkpoint
|
|
pyro workspace export "$WORKSPACE_ID" note.txt --output ./note.txt
|
|
pyro workspace delete "$WORKSPACE_ID"
|
|
```
|
|
|
|
This is the stable persistent-workspace contract:
|
|
|
|
- `workspace create` seeds `/workspace`
|
|
- `workspace sync push` imports later host-side changes
|
|
- `workspace exec` and `workspace shell *` keep work inside one sandbox
|
|
- `workspace service *` manages long-running processes with typed readiness
|
|
- `workspace snapshot *` and `workspace reset` make reset-over-repair explicit
|
|
- `workspace diff` compares against the immutable create-time baseline
|
|
- `workspace export` copies results back to the host
|
|
- `workspace stop|start` and `workspace disk *` add secondary stopped-workspace inspection and raw ext4 export
|
|
|
|
## 6. Optional demo proof point
|
|
|
|
```bash
|
|
uvx --from pyro-mcp pyro demo
|
|
```
|
|
|
|
`pyro demo` proves the one-shot create/start/exec/delete VM lifecycle works end to end.
|
|
|
|
Example output:
|
|
|
|
```json
|
|
{
|
|
"cleanup": {
|
|
"deleted": true,
|
|
"reason": "post_exec_cleanup",
|
|
"vm_id": "..."
|
|
},
|
|
"command": "git --version",
|
|
"environment": "debian:12",
|
|
"execution_mode": "guest_vsock",
|
|
"exit_code": 0,
|
|
"stdout": "git version ...\n"
|
|
}
|
|
```
|
|
|
|
For a fuller copy-pasteable transcript, see [first-run.md](first-run.md).
|
|
When you are done evaluating and want to remove stale cached environments, run `pyro env prune`.
|
|
|
|
## Installed CLI
|
|
|
|
If you already installed the package, the same evaluator path works with plain `pyro ...`:
|
|
|
|
```bash
|
|
uv tool install pyro-mcp
|
|
pyro --version
|
|
pyro doctor
|
|
pyro env list
|
|
pyro env pull debian:12
|
|
pyro run debian:12 -- git --version
|
|
```
|
|
|
|
After the CLI path works, you can move on to:
|
|
|
|
- persistent workspaces: `pyro workspace create debian:12 --seed-path ./repo`
|
|
- live workspace updates: `pyro workspace sync push WORKSPACE_ID ./changes`
|
|
- guest networking policy: `pyro workspace create debian:12 --network-policy egress`
|
|
- workspace secrets: `pyro workspace create debian:12 --secret API_TOKEN=expected --secret-file PIP_TOKEN=./token.txt`
|
|
- baseline diff: `pyro workspace diff WORKSPACE_ID`
|
|
- snapshots and reset: `pyro workspace snapshot create WORKSPACE_ID checkpoint` and `pyro workspace reset WORKSPACE_ID --snapshot checkpoint`
|
|
- host export: `pyro workspace export WORKSPACE_ID note.txt --output ./note.txt`
|
|
- stopped-workspace inspection: `pyro workspace stop WORKSPACE_ID`, `pyro workspace disk list WORKSPACE_ID`, `pyro workspace disk read WORKSPACE_ID note.txt`, and `pyro workspace disk export WORKSPACE_ID --output ./workspace.ext4`
|
|
- interactive shells: `pyro workspace shell open WORKSPACE_ID`
|
|
- long-running services: `pyro workspace service start WORKSPACE_ID app --ready-file .ready -- sh -lc 'touch .ready && while true; do sleep 60; done'`
|
|
- localhost-published ports: `pyro workspace create debian:12 --network-policy egress+published-ports` and `pyro workspace service start WORKSPACE_ID app --ready-http http://127.0.0.1:8080/ --publish 18080:8080 -- ./start-app`
|
|
- MCP: `pyro mcp serve`
|
|
- Python SDK: `from pyro_mcp import Pyro`
|
|
- Demos: `pyro demo` or `pyro demo --network`
|
|
|
|
## Stable Workspace
|
|
|
|
Use `pyro workspace ...` when you need repeated commands in one sandbox instead of one-shot `pyro run`.
|
|
|
|
```bash
|
|
pyro workspace create debian:12 --seed-path ./repo
|
|
pyro workspace create debian:12 --network-policy egress
|
|
pyro workspace create debian:12 --seed-path ./repo --secret API_TOKEN=expected
|
|
pyro workspace create debian:12 --network-policy egress+published-ports
|
|
pyro workspace sync push WORKSPACE_ID ./changes --dest src
|
|
pyro workspace exec WORKSPACE_ID -- cat src/note.txt
|
|
pyro workspace exec WORKSPACE_ID --secret-env API_TOKEN -- sh -lc 'test "$API_TOKEN" = "expected"'
|
|
pyro workspace diff WORKSPACE_ID
|
|
pyro workspace snapshot create WORKSPACE_ID checkpoint
|
|
pyro workspace reset WORKSPACE_ID --snapshot checkpoint
|
|
pyro workspace reset WORKSPACE_ID
|
|
pyro workspace export WORKSPACE_ID src/note.txt --output ./note.txt
|
|
pyro workspace shell open WORKSPACE_ID --secret-env API_TOKEN
|
|
pyro workspace shell write WORKSPACE_ID SHELL_ID --input 'pwd'
|
|
pyro workspace shell read WORKSPACE_ID SHELL_ID
|
|
pyro workspace shell close WORKSPACE_ID SHELL_ID
|
|
pyro workspace service start WORKSPACE_ID web --secret-env API_TOKEN --ready-file .web-ready -- sh -lc 'touch .web-ready && while true; do sleep 60; done'
|
|
pyro workspace service start WORKSPACE_ID worker --ready-file .worker-ready -- sh -lc 'touch .worker-ready && while true; do sleep 60; done'
|
|
pyro workspace service start WORKSPACE_ID app --ready-http http://127.0.0.1:8080/ --publish 18080:8080 -- ./start-app
|
|
pyro workspace service list WORKSPACE_ID
|
|
pyro workspace service status WORKSPACE_ID web
|
|
pyro workspace service logs WORKSPACE_ID web --tail-lines 50
|
|
pyro workspace service stop WORKSPACE_ID web
|
|
pyro workspace service stop WORKSPACE_ID worker
|
|
pyro workspace stop WORKSPACE_ID
|
|
pyro workspace disk list WORKSPACE_ID
|
|
pyro workspace disk read WORKSPACE_ID src/note.txt
|
|
pyro workspace disk export WORKSPACE_ID --output ./workspace.ext4
|
|
pyro workspace start WORKSPACE_ID
|
|
pyro workspace logs WORKSPACE_ID
|
|
pyro workspace delete WORKSPACE_ID
|
|
```
|
|
|
|
Workspace commands default to the persistent `/workspace` directory inside the guest. If you need
|
|
the identifier programmatically, use `--json` and read the `workspace_id` field. Use `--seed-path`
|
|
when the workspace should start from a host directory or a local `.tar` / `.tar.gz` / `.tgz`
|
|
archive. Use `pyro workspace sync push` for later host-side changes to a started workspace. Sync
|
|
is non-atomic in `3.1.0`; if it fails partway through, prefer `pyro workspace reset` to recover
|
|
from `baseline` or one named snapshot. Use `pyro workspace diff` to compare the current workspace
|
|
tree to its immutable create-time baseline, `pyro workspace snapshot *` to capture named
|
|
checkpoints, and `pyro workspace export` to copy one changed file or directory back to the host. Use
|
|
`pyro workspace exec` for one-shot commands and `pyro workspace shell *` when you need an
|
|
interactive PTY that survives across separate calls. Use `pyro workspace service *` when the
|
|
workspace needs long-running background processes with typed readiness probes. Service metadata and
|
|
logs stay outside `/workspace`, so the service runtime itself does not show up in workspace diff or
|
|
export results. Use `--network-policy egress` when the workspace needs outbound guest networking,
|
|
and `--network-policy egress+published-ports` plus `workspace service start --publish` when one
|
|
service must be reachable from the host on `127.0.0.1`. Use `--secret` and `--secret-file` at
|
|
workspace creation when the sandbox needs private tokens or config, and
|
|
`--secret-env SECRET_NAME[=ENV_VAR]` when one exec, shell, or service call needs that secret as an
|
|
environment variable. Persisted secret files are available in the guest at
|
|
`/run/pyro-secrets/<name>`. Use `pyro workspace stop` plus `pyro workspace disk list|read|export`
|
|
when you need offline inspection or one raw ext4 copy from a stopped guest-backed workspace, then
|
|
`pyro workspace start` to resume it.
|
|
|
|
## Contributor Clone
|
|
|
|
```bash
|
|
git lfs install
|
|
git clone <repo>
|
|
cd pyro
|
|
git lfs pull
|
|
make setup
|
|
```
|