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

@ -24,6 +24,11 @@ Top-level commands:
- `pyro workspace exec`
- `pyro workspace export`
- `pyro workspace diff`
- `pyro workspace service start`
- `pyro workspace service list`
- `pyro workspace service status`
- `pyro workspace service logs`
- `pyro workspace service stop`
- `pyro workspace shell open`
- `pyro workspace shell read`
- `pyro workspace shell write`
@ -58,10 +63,12 @@ Behavioral guarantees:
- `pyro workspace sync push WORKSPACE_ID SOURCE_PATH [--dest WORKSPACE_PATH]` imports later host-side directory or archive content into a started workspace.
- `pyro workspace export WORKSPACE_ID PATH --output HOST_PATH` exports one file or directory from `/workspace` back to the host.
- `pyro workspace diff WORKSPACE_ID` compares the current `/workspace` tree to the immutable create-time baseline.
- `pyro workspace service *` manages long-running named services inside one started workspace with typed readiness probes.
- `pyro workspace exec` runs in the persistent `/workspace` for that workspace and does not auto-clean.
- `pyro workspace shell *` manages persistent PTY sessions inside a started workspace.
- `pyro workspace logs` returns persisted command history for that workspace until `pyro workspace delete`.
- Workspace create/status results expose `workspace_seed` metadata describing how `/workspace` was initialized.
- `pyro workspace status` includes aggregate `service_count` and `running_service_count` fields.
## Python SDK Contract
@ -82,6 +89,11 @@ Supported public entrypoints:
- `Pyro.push_workspace_sync(workspace_id, source_path, *, dest="/workspace")`
- `Pyro.export_workspace(workspace_id, path, *, output_path)`
- `Pyro.diff_workspace(workspace_id)`
- `Pyro.start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500)`
- `Pyro.list_services(workspace_id)`
- `Pyro.status_service(workspace_id, service_name)`
- `Pyro.logs_service(workspace_id, service_name, *, tail_lines=200, all=False)`
- `Pyro.stop_service(workspace_id, service_name)`
- `Pyro.open_shell(workspace_id, *, cwd="/workspace", cols=120, rows=30)`
- `Pyro.read_shell(workspace_id, shell_id, *, cursor=0, max_chars=65536)`
- `Pyro.write_shell(workspace_id, shell_id, *, input, append_newline=True)`
@ -112,6 +124,11 @@ Stable public method names:
- `push_workspace_sync(workspace_id, source_path, *, dest="/workspace")`
- `export_workspace(workspace_id, path, *, output_path)`
- `diff_workspace(workspace_id)`
- `start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500)`
- `list_services(workspace_id)`
- `status_service(workspace_id, service_name)`
- `logs_service(workspace_id, service_name, *, tail_lines=200, all=False)`
- `stop_service(workspace_id, service_name)`
- `open_shell(workspace_id, *, cwd="/workspace", cols=120, rows=30)`
- `read_shell(workspace_id, shell_id, *, cursor=0, max_chars=65536)`
- `write_shell(workspace_id, shell_id, *, input, append_newline=True)`
@ -140,6 +157,8 @@ Behavioral defaults:
- `Pyro.push_workspace_sync(...)` imports later host-side directory or archive content into a started workspace.
- `Pyro.export_workspace(...)` exports one file or directory from `/workspace` to an explicit host path.
- `Pyro.diff_workspace(...)` compares the current `/workspace` tree to the immutable create-time baseline.
- `Pyro.start_service(...)` starts one named long-running process in a started workspace and waits for its typed readiness probe when configured.
- `Pyro.list_services(...)`, `Pyro.status_service(...)`, `Pyro.logs_service(...)`, and `Pyro.stop_service(...)` manage those persisted workspace services.
- `Pyro.exec_vm(...)` runs one command and auto-cleans that VM after the exec completes.
- `Pyro.exec_workspace(...)` runs one command in the persistent workspace and leaves it alive.
- `Pyro.open_shell(...)` opens a persistent PTY shell attached to one started workspace.
@ -171,6 +190,11 @@ Persistent workspace tools:
- `workspace_exec`
- `workspace_export`
- `workspace_diff`
- `service_start`
- `service_list`
- `service_status`
- `service_logs`
- `service_stop`
- `shell_open`
- `shell_read`
- `shell_write`
@ -190,6 +214,7 @@ Behavioral defaults:
- `workspace_sync_push` imports later host-side directory or archive content into a started workspace, with an optional `dest` under `/workspace`.
- `workspace_export` exports one file or directory from `/workspace` to an explicit host path.
- `workspace_diff` compares the current `/workspace` tree to the immutable create-time baseline.
- `service_start`, `service_list`, `service_status`, `service_logs`, and `service_stop` manage persistent named services inside a started workspace.
- `vm_exec` runs one command and auto-cleans that VM after the exec completes.
- `workspace_exec` runs one command in a persistent `/workspace` and leaves the workspace alive.
- `shell_open`, `shell_read`, `shell_write`, `shell_signal`, and `shell_close` manage persistent PTY shells inside a started workspace.