Add workspace service lifecycle with typed readiness

Make persistent workspaces capable of running long-lived background processes instead of forcing everything through one-shot exec calls.

Add workspace service start/list/status/logs/stop across the CLI, Python SDK, and MCP server, with multiple named services per workspace, typed readiness probes (file, tcp, http, and command), and aggregate service counts on workspace status. Keep service state and logs outside /workspace so diff and export semantics stay workspace-scoped, and extend the guest agent plus backends to persist service records and logs across separate calls.

Update the 2.7.0 docs, examples, changelog, and roadmap milestone to reflect the shipped surface.

Validation: uv lock; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed Firecracker smoke for workspace create, two service starts, list/status/logs, diff unaffected, stop, and delete.
This commit is contained in:
Thales Maciel 2026-03-12 05:36:28 -03:00
parent 84a7e18d4d
commit f504f0a331
28 changed files with 4098 additions and 124 deletions

View file

@ -22,7 +22,7 @@ Networking: tun=yes ip_forward=yes
```bash
$ uvx --from pyro-mcp pyro env list
Catalog version: 2.6.0
Catalog version: 2.7.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.
@ -75,6 +75,7 @@ $ uvx --from pyro-mcp pyro workspace sync push WORKSPACE_ID ./changes
$ uvx --from pyro-mcp pyro workspace diff WORKSPACE_ID
$ uvx --from pyro-mcp pyro workspace export WORKSPACE_ID note.txt --output ./note.txt
$ uvx --from pyro-mcp pyro workspace shell open WORKSPACE_ID
$ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID app --ready-file .ready -- sh -lc 'touch .ready && while true; do sleep 60; done'
$ uvx --from pyro-mcp pyro mcp serve
```
@ -118,16 +119,52 @@ $ uvx --from pyro-mcp pyro workspace shell write WORKSPACE_ID SHELL_ID --input '
$ uvx --from pyro-mcp pyro workspace shell read WORKSPACE_ID SHELL_ID
/workspace
[workspace-shell-read] workspace_id=... shell_id=... state=running cursor=0 next_cursor=... truncated=False execution_mode=guest_vsock
$ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID web --ready-file .web-ready -- sh -lc 'touch .web-ready && while true; do sleep 60; done'
[workspace-service-start] workspace_id=... service=web state=running cwd=/workspace ready_type=file execution_mode=guest_vsock
$ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID worker --ready-file .worker-ready -- sh -lc 'touch .worker-ready && while true; do sleep 60; done'
[workspace-service-start] workspace_id=... service=worker state=running cwd=/workspace ready_type=file execution_mode=guest_vsock
$ uvx --from pyro-mcp pyro workspace service list WORKSPACE_ID
Workspace: ...
Services: 2 total, 2 running
- web [running] cwd=/workspace readiness=file
- worker [running] cwd=/workspace readiness=file
$ uvx --from pyro-mcp pyro workspace service status WORKSPACE_ID web
Workspace: ...
Service: web
State: running
Command: sh -lc 'touch .web-ready && while true; do sleep 60; done'
Cwd: /workspace
Readiness: file /workspace/.web-ready
Execution mode: guest_vsock
$ uvx --from pyro-mcp pyro workspace service logs WORKSPACE_ID web --tail-lines 50
Workspace: ...
Service: web
State: running
...
$ uvx --from pyro-mcp pyro workspace service stop WORKSPACE_ID web
[workspace-service-stop] workspace_id=... service=web state=stopped execution_mode=guest_vsock
$ uvx --from pyro-mcp pyro workspace service stop WORKSPACE_ID worker
[workspace-service-stop] workspace_id=... service=worker state=stopped execution_mode=guest_vsock
```
Use `--seed-path` when the workspace should start from a host directory or a local
`.tar` / `.tar.gz` / `.tgz` archive instead of an empty `/workspace`. Use
`pyro workspace sync push` when you need to import later host-side changes into a started
workspace. Sync is non-atomic in `2.6.0`; if it fails partway through, delete and recreate the
workspace. Sync is non-atomic in `2.7.0`; if it fails partway through, delete and recreate the
workspace. Use `pyro workspace diff` to compare the current `/workspace` tree to its immutable
create-time baseline, 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 a persistent interactive PTY session in that same workspace.
need a persistent interactive PTY session in that same workspace. Use `pyro workspace service *`
when the workspace needs long-running background processes with typed readiness checks. Internal
service state and logs stay outside `/workspace`, so service runtime data does not appear in
workspace diff or export results.
Example output: