Add use-case recipes and smoke packs

Turn the stable workspace surface into five documented, runnable stories with a shared guest-backed smoke runner, new docs/use-cases recipes, and Make targets for cold-start validation, repro/fix loops, parallel workspaces, untrusted inspection, and review/eval workflows.

Bump the package and catalog surface to 3.6.0, update the main docs to point users from the stable workspace walkthrough into the recipe index and smoke packs, and mark the 3.6.0 roadmap milestone done.

Fix a regression uncovered by the real parallel-workspaces smoke: workspace_file_read must not bump last_activity_at. Verified with uv lock, UV_CACHE_DIR=.uv-cache make check, UV_CACHE_DIR=.uv-cache make dist-check, and USE_CASE_ENVIRONMENT=debian:12 UV_CACHE_DIR=.uv-cache make smoke-use-cases.
This commit is contained in:
Thales Maciel 2026-03-13 10:27:38 -03:00
parent 21a88312b6
commit 894706af50
22 changed files with 1310 additions and 16 deletions

31
docs/use-cases/README.md Normal file
View file

@ -0,0 +1,31 @@
# Workspace Use-Case Recipes
These recipes turn the stable workspace surface into five concrete agent flows.
They are the canonical next step after the quickstart in [install.md](../install.md)
or [first-run.md](../first-run.md).
Run all real guest-backed scenarios locally with:
```bash
make smoke-use-cases
```
Recipe matrix:
| Use case | Recommended profile | Smoke target | Recipe |
| --- | --- | --- | --- |
| Cold-start repo validation | `workspace-full` | `make smoke-cold-start-validation` | [cold-start-repo-validation.md](cold-start-repo-validation.md) |
| Repro plus fix loop | `workspace-core` | `make smoke-repro-fix-loop` | [repro-fix-loop.md](repro-fix-loop.md) |
| Parallel isolated workspaces | `workspace-core` | `make smoke-parallel-workspaces` | [parallel-workspaces.md](parallel-workspaces.md) |
| Unsafe or untrusted code inspection | `workspace-core` | `make smoke-untrusted-inspection` | [untrusted-inspection.md](untrusted-inspection.md) |
| Review and evaluation workflows | `workspace-full` | `make smoke-review-eval` | [review-eval-workflows.md](review-eval-workflows.md) |
All five recipes use the same real Firecracker-backed smoke runner:
```bash
uv run python scripts/workspace_use_case_smoke.py --scenario all --environment debian:12
```
That runner generates its own host fixtures, creates real guest-backed workspaces,
verifies the intended flow, exports one concrete result when relevant, and cleans
up on both success and failure.

View file

@ -0,0 +1,38 @@
# Cold-Start Repo Validation
Recommended profile: `workspace-full`
Smoke target:
```bash
make smoke-cold-start-validation
```
Use this flow when an agent needs to treat a fresh repo like a new user would:
seed it into a workspace, run the validation script, keep one long-running
process alive, probe it from another command, and export a validation report.
Canonical SDK flow:
```python
from pyro_mcp import Pyro
pyro = Pyro()
created = pyro.create_workspace(environment="debian:12", seed_path="./repo")
workspace_id = str(created["workspace_id"])
pyro.exec_workspace(workspace_id, command="sh validate.sh")
pyro.start_service(
workspace_id,
"app",
command="sh serve.sh",
readiness={"type": "file", "path": ".app-ready"},
)
pyro.exec_workspace(workspace_id, command="sh -lc 'test -f .app-ready && cat service-state.txt'")
pyro.export_workspace(workspace_id, "validation-report.txt", output_path="./validation-report.txt")
pyro.delete_workspace(workspace_id)
```
This recipe is intentionally guest-local and deterministic. It proves startup,
service readiness, validation, and host-out report capture without depending on
external networks or private registries.

View file

@ -0,0 +1,43 @@
# Parallel Isolated Workspaces
Recommended profile: `workspace-core`
Smoke target:
```bash
make smoke-parallel-workspaces
```
Use this flow when the agent needs one isolated workspace per issue, branch, or
review thread and must rediscover the right one later.
Canonical SDK flow:
```python
from pyro_mcp import Pyro
pyro = Pyro()
alpha = pyro.create_workspace(
environment="debian:12",
seed_path="./repo",
name="parallel-alpha",
labels={"branch": "alpha", "issue": "123"},
)
beta = pyro.create_workspace(
environment="debian:12",
seed_path="./repo",
name="parallel-beta",
labels={"branch": "beta", "issue": "456"},
)
pyro.write_workspace_file(alpha["workspace_id"], "branch.txt", text="alpha\n")
pyro.write_workspace_file(beta["workspace_id"], "branch.txt", text="beta\n")
pyro.update_workspace(alpha["workspace_id"], labels={"branch": "alpha", "owner": "alice"})
pyro.list_workspaces()
pyro.delete_workspace(alpha["workspace_id"])
pyro.delete_workspace(beta["workspace_id"])
```
The important proof here is operational, not syntactic: names, labels, list
ordering, and file contents stay isolated even when multiple workspaces are
active at the same time.

View file

@ -0,0 +1,42 @@
# Repro Plus Fix Loop
Recommended profile: `workspace-core`
Smoke target:
```bash
make smoke-repro-fix-loop
```
Use this flow when the agent has to reproduce a bug, patch files without shell
quoting tricks, rerun the failing command, diff the result, export the fix, and
reset back to baseline.
Canonical SDK flow:
```python
from pyro_mcp import Pyro
pyro = Pyro()
created = pyro.create_workspace(environment="debian:12", seed_path="./broken-repro")
workspace_id = str(created["workspace_id"])
pyro.exec_workspace(workspace_id, command="sh check.sh")
pyro.read_workspace_file(workspace_id, "message.txt")
pyro.apply_workspace_patch(
workspace_id,
patch="--- a/message.txt\n+++ b/message.txt\n@@ -1 +1 @@\n-broken\n+fixed\n",
)
pyro.exec_workspace(workspace_id, command="sh check.sh")
pyro.diff_workspace(workspace_id)
pyro.export_workspace(workspace_id, "message.txt", output_path="./message.txt")
pyro.reset_workspace(workspace_id)
pyro.delete_workspace(workspace_id)
```
Canonical MCP/chat example:
- [examples/openai_responses_workspace_core.py](../../examples/openai_responses_workspace_core.py)
This is the main `workspace-core` story: model-native file ops, repeatable exec,
structured diff, explicit export, and reset-over-repair.

View file

@ -0,0 +1,41 @@
# Review And Evaluation Workflows
Recommended profile: `workspace-full`
Smoke target:
```bash
make smoke-review-eval
```
Use this flow when an agent needs to read a checklist interactively, run an
evaluation script, checkpoint or reset its changes, and export the final report.
Canonical SDK flow:
```python
from pyro_mcp import Pyro
pyro = Pyro()
created = pyro.create_workspace(environment="debian:12", seed_path="./review-fixture")
workspace_id = str(created["workspace_id"])
pyro.create_snapshot(workspace_id, "pre-review")
shell = pyro.open_shell(workspace_id)
pyro.write_shell(workspace_id, shell["shell_id"], input="cat CHECKLIST.md")
pyro.read_shell(
workspace_id,
shell["shell_id"],
plain=True,
wait_for_idle_ms=300,
)
pyro.close_shell(workspace_id, shell["shell_id"])
pyro.exec_workspace(workspace_id, command="sh review.sh")
pyro.export_workspace(workspace_id, "review-report.txt", output_path="./review-report.txt")
pyro.reset_workspace(workspace_id, snapshot="pre-review")
pyro.delete_workspace(workspace_id)
```
This is the stable shell-facing story: readable PTY output for chat loops,
checkpointed evaluation, explicit export, and reset when a review branch goes
sideways.

View file

@ -0,0 +1,34 @@
# Unsafe Or Untrusted Code Inspection
Recommended profile: `workspace-core`
Smoke target:
```bash
make smoke-untrusted-inspection
```
Use this flow when the agent needs to inspect suspicious code or an unfamiliar
repo without granting more capabilities than necessary.
Canonical SDK flow:
```python
from pyro_mcp import Pyro
pyro = Pyro()
created = pyro.create_workspace(environment="debian:12", seed_path="./suspicious-repo")
workspace_id = str(created["workspace_id"])
pyro.list_workspace_files(workspace_id, path="/workspace", recursive=True)
pyro.read_workspace_file(workspace_id, "suspicious.sh")
pyro.exec_workspace(
workspace_id,
command="sh -lc \"grep -n 'curl' suspicious.sh > inspection-report.txt\"",
)
pyro.export_workspace(workspace_id, "inspection-report.txt", output_path="./inspection-report.txt")
pyro.delete_workspace(workspace_id)
```
This recipe stays offline-by-default, uses only explicit file reads and execs,
and exports only the inspection report the agent chose to materialize.