Reframe pyro around the chat-host path

Make the docs and help text unapologetically teach  as the product path for Claude Code, Codex, and OpenCode on Linux KVM.

Rewrite the README, install/first-run/integration guides, public contract, vision, and use-case docs around the zero-to-hero chat flow, and explicitly note that there are no users yet so breaking changes are acceptable while the interface is still being shaped.

Update package metadata, CLI help, and the docs/help expectation tests to match the new positioning. Validate the reframe with usage: pyro [-h] [--version] COMMAND ...

Validate the host and serve disposable MCP workspaces for chat-based coding agents on supported Linux x86_64 KVM hosts.

positional arguments:
  COMMAND
    env        Inspect and manage curated environments.
    mcp        Run the MCP server.
    run        Run one command inside an ephemeral VM.
    workspace  Manage persistent workspaces.
    doctor     Inspect runtime and host diagnostics.
    demo       Run built-in demos.

options:
  -h, --help   show this help message and exit
  --version    show program's version number and exit

Suggested zero-to-hero path:
  pyro doctor
  pyro env list
  pyro env pull debian:12
  pyro run debian:12 -- git --version
  pyro mcp serve

Connect a chat host after that:
  claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
  codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve

If you want terminal-level visibility into the workspace model:
  pyro workspace create debian:12 --seed-path ./repo --id-only
  pyro workspace sync push WORKSPACE_ID ./changes
  pyro workspace exec WORKSPACE_ID -- cat note.txt
  pyro workspace diff WORKSPACE_ID
  pyro workspace snapshot create WORKSPACE_ID checkpoint
  pyro workspace reset WORKSPACE_ID --snapshot checkpoint
  pyro workspace shell open WORKSPACE_ID --id-only
  pyro workspace service start WORKSPACE_ID app --ready-file .ready --                 sh -lc 'touch .ready && while true; do sleep 60; done'
  pyro workspace export WORKSPACE_ID note.txt --output ./note.txt, usage: pyro mcp serve [-h] [--profile {vm-run,workspace-core,workspace-full}]

Expose pyro tools over stdio for an MCP client. Bare `pyro mcp serve` now starts `workspace-core`, the recommended first profile for most chat hosts.

options:
  -h, --help            show this help message and exit
  --profile {vm-run,workspace-core,workspace-full}
                        Expose only one model-facing tool profile. `workspace-
                        core` is the default and recommended first profile for
                        most chat hosts; `workspace-full` is the larger opt-in
                        profile. (default: workspace-core)

Default and recommended first start:
  pyro mcp serve

Profiles:
  workspace-core: default for normal persistent chat editing
  vm-run: smallest one-shot-only surface
  workspace-full: larger opt-in surface for shells, services,
    snapshots, secrets, network policy, and disk tools

Use --profile workspace-full only when the host truly needs those
extra workspace capabilities., and uv run ruff check .
All checks passed!
uv run mypy
Success: no issues found in 61 source files
uv run pytest -n auto
============================= test session starts ==============================
platform linux -- Python 3.12.10, pytest-9.0.2, pluggy-1.6.0
rootdir: /home/thales/projects/personal/pyro
configfile: pyproject.toml
testpaths: tests
plugins: anyio-4.12.1, xdist-3.8.0, cov-7.0.0
created: 32/32 workers
32 workers [393 items]

........................................................................ [ 18%]
........................................................................ [ 36%]
........................................................................ [ 54%]
........................................................................ [ 73%]
........................................................................ [ 91%]
.................................                                        [100%]
=============================== warnings summary ===============================
../../../.local/share/uv/python/cpython-3.12.10-linux-x86_64-gnu/lib/python3.12/importlib/metadata/__init__.py:467: 32 warnings
  /home/thales/.local/share/uv/python/cpython-3.12.10-linux-x86_64-gnu/lib/python3.12/importlib/metadata/__init__.py:467: DeprecationWarning: Implicit None on return values is deprecated and will raise KeyErrors.
    return self.metadata['Version']

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.12.10-final-0 _______________

Name                                        Stmts   Miss  Cover   Missing
-------------------------------------------------------------------------
src/pyro_mcp/__init__.py                       25      0   100%
src/pyro_mcp/api.py                           307      7    98%   37-38, 63, 69, 72, 75, 548
src/pyro_mcp/cli.py                          1132    141    88%   288-289, 332-333, 336, 344, 367-368, 394-395, 398, 406, 450, 460-461, 464, 477, 483-484, 498-499, 502, 566-575, 592-593, 596, 635, 2180, 2182, 2226, 2236, 2280, 2284-2285, 2295, 2302, 2344-2351, 2392, 2409-2414, 2459-2461, 2470-2472, 2483-2485, 2494-2496, 2503-2505, 2510-2512, 2523-2528, 2530, 2541-2546, 2567-2572, 2574, 2589-2594, 2596, 2608, 2623, 2637, 2655-2660, 2669-2674, 2676, 2683-2688, 2690, 2701-2706, 2708, 2719-2724, 2726, 2737-2742, 2764, 2787, 2806, 2824, 2841, 2899, 3017
src/pyro_mcp/contract.py                       52      0   100%
src/pyro_mcp/demo.py                           16      0   100%
src/pyro_mcp/doctor.py                         12      0   100%
src/pyro_mcp/ollama_demo.py                   245      6    98%   289, 294, 299, 318, 439, 550
src/pyro_mcp/runtime.py                       142     14    90%   80, 84, 88, 92, 120, 130, 144, 173, 182, 194, 230-232, 262
src/pyro_mcp/runtime_boot_check.py             33      0   100%
src/pyro_mcp/runtime_build.py                 546     47    91%   92, 127, 181, 189, 238-240, 263-265, 300, 325, 331, 340-341, 343, 392, 396, 413, 416, 492-494, 497-499, 522, 525, 578, 615, 620, 646-647, 649, 686, 688, 694, 697, 725, 765, 779, 791, 805, 808, 1002, 1009, 1198
src/pyro_mcp/runtime_bundle/__init__.py         0      0   100%
src/pyro_mcp/runtime_network_check.py          15      0   100%
src/pyro_mcp/server.py                          8      0   100%
src/pyro_mcp/vm_environments.py               386     55    86%   128, 131, 267, 274, 281, 304-306, 329-331, 352-353, 355, 380, 382, 392-394, 415, 418, 421, 429, 431, 436-437, 446-448, 488, 495-496, 502, 515, 526, 539, 546, 549, 570, 596, 599, 608-609, 613, 617, 626, 629, 636, 644, 647, 659, 667, 676, 682, 685
src/pyro_mcp/vm_firecracker.py                 47      0   100%
src/pyro_mcp/vm_guest.py                      206     22    89%   139, 142, 173, 176, 202, 205, 208, 211, 217, 239, 262-279, 291, 313, 633-634, 643
src/pyro_mcp/vm_manager.py                   2846    355    88%   625, 642, 650-657, 677, 684, 688, 712-715, 795-796, 818, 828, 830, 845, 853-855, 858, 870, 872, 881, 889, 892, 901-902, 910, 913, 919, 926, 929, 933, 951-955, 1010-1011, 1050, 1096, 1102, 1114, 1150, 1156, 1159, 1168, 1170, 1173-1177, 1230, 1236, 1239, 1248, 1250, 1253-1257, 1268, 1277, 1280, 1284-1290, 1319, 1322-1324, 1326, 1333, 1335, 1345, 1347, 1349, 1352-1353, 1361, 1377, 1379, 1381, 1391, 1403-1404, 1408, 1424, 1440-1441, 1443, 1447, 1450-1451, 1469, 1476, 1488, 1505, 1508-1509, 1511, 1582-1583, 1586-1588, 1599, 1602, 1605, 1617, 1638, 1649-1650, 1657-1658, 1669-1671, 1781, 1792-1798, 1808, 1860, 1870, 1891, 1894-1895, 1901-1904, 1910, 1922-1962, 1991-1993, 2034, 2046-2047, 2077, 2146, 2175, 2524-2528, 2598-2602, 2614, 2720, 3563, 3577, 3580, 3583, 3648-3653, 3720, 3802, 3842-3843, 3846-3847, 3862-3863, 3914, 4194, 4229, 4232, 4237, 4250, 4254, 4263, 4277, 4316, 4349, 4444, 4472-4473, 4477-4478, 4504, 4530-4531, 4576, 4578, 4600-4601, 4629, 4631, 4661-4662, 4681-4682, 4734, 4738, 4741-4743, 4745, 4747, 4776-4777, 4809-4845, 4863-4864, 4903, 4905, 4934, 4954-4955, 4977, 4988-4990, 5036, 5049-5050, 5059-5061, 5104-5105, 5171-5178, 5189-5192, 5203, 5208, 5216-5230, 5240, 5473-5476, 5485-5490, 5498-5503, 5513, 5557, 5577, 5601-5602, 5678-5680, 5706-5725, 5784, 5789, 5804, 5832, 5836, 5848, 5884-5886, 5946, 5950, 6079, 6111, 6155, 6170, 6189, 6201, 6242, 6251, 6256, 6269, 6274, 6296, 6394, 6422-6423
src/pyro_mcp/vm_network.py                    134     22    84%   65-66, 139, 201, 203, 205, 226, 317-331, 350-351, 360, 362, 372-384
src/pyro_mcp/workspace_disk.py                164      0   100%
src/pyro_mcp/workspace_files.py               293      0   100%
src/pyro_mcp/workspace_ports.py                79      1    99%   116
src/pyro_mcp/workspace_shell_output.py         88      2    98%   16, 61
src/pyro_mcp/workspace_shells.py              235     26    89%   105-118, 193-194, 226-227, 230-235, 251, 257-259, 263, 270-271, 299, 301, 303, 306-307
src/pyro_mcp/workspace_use_case_smokes.py     216      8    96%   131, 134-135, 423-426, 490
-------------------------------------------------------------------------
TOTAL                                        7227    706    90%
Required test coverage of 90% reached. Total coverage: 90.23%
======================= 393 passed, 32 warnings in 5.60s =======================.
This commit is contained in:
Thales Maciel 2026-03-13 15:03:20 -03:00
parent 6433847185
commit 999fe1b23a
No known key found for this signature in database
GPG key ID: 33112E6833C34679
15 changed files with 608 additions and 1613 deletions

View file

@ -1,16 +1,19 @@
# Vision
`pyro-mcp` should become the disposable sandbox where an agent can do real
development work safely, repeatedly, and reproducibly.
`pyro-mcp` should become the disposable MCP workspace for chat-based coding
agents.
That is a different product from a generic VM wrapper, a secure CI runner, or a
task queue with better isolation.
That is a different product from a generic VM wrapper, a secure CI runner, or
an SDK-first platform.
`pyro-mcp` currently has no users. That means we can still make breaking
changes freely while we shape the chat-host path into the right product.
## Core Thesis
The goal is not just to run one command in a microVM.
The goal is to give an LLM or coding agent a bounded workspace where it can:
The goal is to give a chat-hosted coding agent a bounded workspace where it can:
- inspect a repo
- install dependencies
@ -23,6 +26,25 @@ The goal is to give an LLM or coding agent a bounded workspace where it can:
The sandbox is the execution boundary for agentic software work.
## Current Product Focus
The product path should be obvious and narrow:
- Claude Code
- Codex
- OpenCode
- Linux `x86_64` with KVM
The happy path is:
1. prove the host with the terminal companion commands
2. run `pyro mcp serve`
3. connect a chat host
4. work through one disposable workspace per task
The repo can contain lower-level building blocks, but they should not drive the
product story.
## What This Is Not
`pyro-mcp` should not drift into:
@ -32,9 +54,10 @@ The sandbox is the execution boundary for agentic software work.
- a generic CI job runner
- a scheduler or queueing platform
- a broad VM orchestration product
- an SDK product that happens to have an MCP server on the side
Those products optimize for queued work, throughput, retries, matrix builds, and
shared infrastructure.
Those products optimize for queued work, throughput, retries, matrix builds, or
library ergonomics.
`pyro-mcp` should optimize for agent loops:
@ -57,10 +80,15 @@ Any sandbox product starts to look like CI if the main abstraction is:
That shape is useful, but it is not the center of the vision.
To stay aligned, the primary abstraction should be a workspace the agent
inhabits, not a job the agent submits.
inhabits from a chat host, not a job the agent submits to a runner.
## Product Principles
### Chat Hosts First
The product should be shaped around the MCP path used from chat interfaces.
Everything else is there to support, debug, or build that path.
### Workspace-First
The default mental model should be "open a disposable workspace" rather than
@ -85,11 +113,6 @@ Anything that crosses the host boundary should be intentional and visible:
Agents should be able to checkpoint, reset, and retry cheaply. Disposable state
is a feature, not a limitation.
### Same Contract Across Surfaces
CLI, Python, and MCP should expose the same underlying workspace model so the
product feels coherent no matter how it is consumed.
### Agent-Native Observability
The sandbox should expose the things an agent actually needs to reason about:
@ -101,10 +124,16 @@ The sandbox should expose the things an agent actually needs to reason about:
- readiness
- exported results
## The Shape Of An LLM-First Sandbox
## The Shape Of The Product
The strongest future direction is a small, agent-native contract built around
workspaces, shells, files, services, and reset.
The strongest direction is a small chat-facing contract built around:
- one MCP server
- one disposable workspace model
- structured file inspection and edits
- repeated commands in the same sandbox
- service lifecycle when the workflow needs it
- reset as a first-class workflow primitive
Representative primitives:
@ -114,95 +143,57 @@ Representative primitives:
- `workspace.sync_push`
- `workspace.export`
- `workspace.diff`
- `workspace.snapshot`
- `workspace.reset`
- `workspace.exec`
- `shell.open`
- `shell.read`
- `shell.write`
- `shell.signal`
- `shell.close`
- `workspace.exec`
- `service.start`
- `service.status`
- `service.logs`
- `service.stop`
These names are illustrative, not a committed public API.
The important point is the interaction model:
- a shell session is interactive state inside the sandbox
- a workspace is durable for the life of the task
- services are first-class, not accidental background jobs
- reset is a core workflow primitive
These names are illustrative, not a promise that every lower-level repo surface
should be treated as equally stable or equally important.
## Interactive Shells And Disk Operations
Interactive shells are aligned with the vision because they make the agent feel
present inside the sandbox rather than reduced to one-shot job submission.
That does not mean `pyro-mcp` should become a raw SSH replacement. The shell
should sit inside a higher-level workspace model with structured file, service,
diff, and reset operations around it.
They should remain subordinate to the workspace model, not replace it with a
raw SSH story.
Disk-level operations are also useful, but they should remain supporting tools.
They are good for:
Disk-level operations are useful for:
- fast workspace seeding
- snapshotting
- offline inspection
- diffing
- export/import without a full boot
They should not become the primary product identity. If the center of the
product becomes "operate on VM disks", it will read as image tooling rather
than an agent workspace.
They should remain supporting tools rather than the product identity.
## What To Build Next
Features should be prioritized in this order:
Features should keep reinforcing the chat-host path in this order:
1. Repeated commands in one persistent workspace
2. Interactive shell sessions with PTY semantics
3. Structured workspace sync and export
4. Service lifecycle and readiness checks
5. Snapshot and reset workflows
6. Explicit secrets and network policy
7. Secondary disk-level import/export and inspection tools
1. make the first chat-host setup painfully obvious
2. make the recipe-backed workflows feel trivial from chat
3. keep the smoke pack trustworthy enough to gate the advertised stories
4. keep the terminal companion path good enough to debug what the chat sees
5. let lower-level repo surfaces move freely when the chat-host product needs it
The completed workspace GA roadmap lives in
[roadmap/task-workspace-ga.md](roadmap/task-workspace-ga.md).
The next implementation milestones that make those workflows feel natural from
chat-driven LLM interfaces live in
The follow-on milestones that make the chat-host path clearer live in
[roadmap/llm-chat-ergonomics.md](roadmap/llm-chat-ergonomics.md).
## Naming Guidance
Prefer language that reinforces the workspace model:
- `workspace`
- `sandbox`
- `shell`
- `service`
- `snapshot`
- `reset`
Avoid centering language that makes the product feel like CI infrastructure:
- `job`
- `runner`
- `pipeline`
- `worker`
- `queue`
- `build matrix`
## Litmus Test
When evaluating a new feature, ask:
"Does this help an agent inhabit a safe disposable workspace and do real
software work inside it?"
"Does this make Claude Code, Codex, or OpenCode feel more natural and powerful
when they work inside a disposable sandbox?"
If the better description is "it helps submit, schedule, and report jobs", the
feature is probably pushing the product in the wrong direction.
If the better description is "it helps build a broader VM toolkit or SDK", it
is probably pushing the product in the wrong direction.