Freeze the current workspace-first surface as the stable 3.0 contract and reposition the landing docs, CLI help, and public contract around the stable workspace path after the one-shot proof. Bump the package and catalog compatibility to 3.0.0, add a dedicated workspace walkthrough tape/GIF, and mark the 3.0.0 roadmap milestone done while keeping runtime capability unchanged in this release. Validation: uv lock; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; UV_CACHE_DIR=.uv-cache uv build; UV_CACHE_DIR=.uv-cache uvx --from twine twine check dist/*; built-wheel CLI smoke for pyro --help and pyro workspace --help; vhs validate plus rendered workspace-first-run.gif outside the sandbox because vhs crashes when sandboxed.
281 lines
10 KiB
Markdown
281 lines
10 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.0.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
|
|
|
|
## 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`
|
|
- 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 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.0.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>`.
|
|
|
|
## Contributor Clone
|
|
|
|
```bash
|
|
git lfs install
|
|
git clone <repo>
|
|
cd pyro
|
|
git lfs pull
|
|
make setup
|
|
```
|