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:
parent
6433847185
commit
999fe1b23a
15 changed files with 608 additions and 1613 deletions
|
|
@ -1,164 +1,141 @@
|
|||
# Integration Targets
|
||||
# Chat Host Integrations
|
||||
|
||||
These are the main ways to integrate `pyro-mcp` into an LLM application.
|
||||
This page documents the intended product path for `pyro-mcp`:
|
||||
|
||||
Use this page after you have already validated the host and guest execution through the
|
||||
CLI path in [install.md](install.md) or [first-run.md](first-run.md).
|
||||
- validate the host with the CLI
|
||||
- run `pyro mcp serve`
|
||||
- connect a chat host
|
||||
- let the agent work inside disposable workspaces
|
||||
|
||||
`pyro-mcp` currently has no users. Expect breaking changes while this chat-host
|
||||
path is still being shaped.
|
||||
|
||||
Use this page after you have already validated the host and guest execution
|
||||
through [install.md](install.md) or [first-run.md](first-run.md).
|
||||
|
||||
## Recommended Default
|
||||
|
||||
Bare `pyro mcp serve` now starts `workspace-core`. Use `vm_run` only for one-shot
|
||||
integrations, and promote the chat surface to `workspace-full` only when it
|
||||
truly needs shells, services, snapshots, secrets, network policy, or disk
|
||||
tools.
|
||||
Bare `pyro mcp serve` starts `workspace-core`. That is the product path.
|
||||
|
||||
That keeps the model-facing contract small:
|
||||
```bash
|
||||
pyro mcp serve
|
||||
```
|
||||
|
||||
- one tool
|
||||
- one command
|
||||
- one ephemeral VM
|
||||
- automatic cleanup
|
||||
Use `--profile workspace-full` only when the chat truly needs shells, services,
|
||||
snapshots, secrets, network policy, or disk tools.
|
||||
|
||||
Profile progression:
|
||||
## Claude Code
|
||||
|
||||
- `workspace-core`: default and recommended first profile for persistent chat editing
|
||||
- `vm-run`: one-shot only
|
||||
- `workspace-full`: the full stable workspace surface, including shells, services, snapshots, secrets, network policy, and disk tools
|
||||
Package without install:
|
||||
|
||||
## OpenAI Responses API
|
||||
```bash
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
claude mcp list
|
||||
```
|
||||
|
||||
Best when:
|
||||
Already installed:
|
||||
|
||||
- your agent already uses OpenAI models directly
|
||||
- you want a normal tool-calling loop instead of MCP transport
|
||||
- you want the smallest amount of integration code
|
||||
```bash
|
||||
claude mcp add pyro -- pyro mcp serve
|
||||
claude mcp list
|
||||
```
|
||||
|
||||
Recommended surface:
|
||||
Reference:
|
||||
|
||||
- `vm_run` for one-shot loops
|
||||
- the `workspace-core` tool set for the normal persistent chat loop
|
||||
- the `workspace-full` tool set only when the host explicitly needs advanced workspace capabilities
|
||||
- [claude_code_mcp.md](../examples/claude_code_mcp.md)
|
||||
|
||||
Canonical example:
|
||||
## Codex
|
||||
|
||||
- [examples/openai_responses_vm_run.py](../examples/openai_responses_vm_run.py)
|
||||
- [examples/openai_responses_workspace_core.py](../examples/openai_responses_workspace_core.py)
|
||||
- [docs/use-cases/repro-fix-loop.md](use-cases/repro-fix-loop.md)
|
||||
Package without install:
|
||||
|
||||
## MCP Clients
|
||||
```bash
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
codex mcp list
|
||||
```
|
||||
|
||||
Best when:
|
||||
Already installed:
|
||||
|
||||
- your host application already supports MCP
|
||||
- you want `pyro` to run as an external stdio server
|
||||
- you want tool schemas to be discovered directly from the server
|
||||
```bash
|
||||
codex mcp add pyro -- pyro mcp serve
|
||||
codex mcp list
|
||||
```
|
||||
|
||||
Recommended entrypoint:
|
||||
Reference:
|
||||
|
||||
- `pyro mcp serve`
|
||||
- [codex_mcp.md](../examples/codex_mcp.md)
|
||||
|
||||
Profile progression:
|
||||
## OpenCode
|
||||
|
||||
- `pyro mcp serve --profile vm-run` for the smallest one-shot surface
|
||||
- `pyro mcp serve` for the normal persistent chat loop
|
||||
- `pyro mcp serve --profile workspace-full` only when the model truly needs advanced workspace tools
|
||||
Use the local MCP config shape from:
|
||||
|
||||
Host-specific onramps:
|
||||
- [opencode_mcp_config.json](../examples/opencode_mcp_config.json)
|
||||
|
||||
- Claude Code: [examples/claude_code_mcp.md](../examples/claude_code_mcp.md)
|
||||
- Codex: [examples/codex_mcp.md](../examples/codex_mcp.md)
|
||||
- OpenCode: [examples/opencode_mcp_config.json](../examples/opencode_mcp_config.json)
|
||||
- Generic MCP config: [examples/mcp_client_config.md](../examples/mcp_client_config.md)
|
||||
- Claude Desktop fallback: [examples/claude_desktop_mcp_config.json](../examples/claude_desktop_mcp_config.json)
|
||||
- Cursor fallback: [examples/cursor_mcp_config.json](../examples/cursor_mcp_config.json)
|
||||
- Use-case recipes: [docs/use-cases/README.md](use-cases/README.md)
|
||||
Minimal `opencode.json` snippet:
|
||||
|
||||
## Direct Python SDK
|
||||
```json
|
||||
{
|
||||
"mcp": {
|
||||
"pyro": {
|
||||
"type": "local",
|
||||
"enabled": true,
|
||||
"command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Best when:
|
||||
If `pyro-mcp` is already installed, replace `uvx --from pyro-mcp pyro` with
|
||||
`pyro` in the same config shape.
|
||||
|
||||
- your application owns orchestration itself
|
||||
- you do not need MCP transport
|
||||
- you want direct access to `Pyro`
|
||||
## Generic MCP Fallback
|
||||
|
||||
Recommended default:
|
||||
Use this only when the host expects a plain `mcpServers` JSON config and does
|
||||
not already have a dedicated example in the repo:
|
||||
|
||||
- `Pyro.run_in_vm(...)`
|
||||
- `Pyro.create_server()` for most chat hosts now that `workspace-core` is the default profile
|
||||
- `Pyro.create_workspace(name=..., labels=...)` + `Pyro.list_workspaces()` + `Pyro.update_workspace(...)` when repeated workspaces need human-friendly discovery metadata
|
||||
- `Pyro.create_workspace(seed_path=...)` + `Pyro.push_workspace_sync(...)` + `Pyro.exec_workspace(...)` when repeated workspace commands are required
|
||||
- `Pyro.list_workspace_files(...)` / `Pyro.read_workspace_file(...)` / `Pyro.write_workspace_file(...)` / `Pyro.apply_workspace_patch(...)` when the agent needs model-native file inspection and text edits inside one live workspace
|
||||
- `Pyro.create_workspace(..., secrets=...)` + `Pyro.exec_workspace(..., secret_env=...)` when the workspace needs private tokens or authenticated setup
|
||||
- `Pyro.create_workspace(..., network_policy="egress+published-ports")` + `Pyro.start_service(..., published_ports=[...])` when the host must probe one workspace service
|
||||
- `Pyro.diff_workspace(...)` + `Pyro.export_workspace(...)` when the agent needs baseline comparison or host-out file transfer
|
||||
- `Pyro.start_service(..., secret_env=...)` + `Pyro.list_services(...)` + `Pyro.logs_service(...)` when the agent needs long-running background processes in one workspace
|
||||
- `Pyro.open_shell(..., secret_env=...)` + `Pyro.write_shell(...)` + `Pyro.read_shell(..., plain=True, wait_for_idle_ms=300)` when the agent needs an interactive PTY inside the workspace
|
||||
- [mcp_client_config.md](../examples/mcp_client_config.md)
|
||||
|
||||
Lifecycle note:
|
||||
Generic `mcpServers` shape:
|
||||
|
||||
- `Pyro.exec_vm(...)` runs one command and auto-cleans the VM afterward
|
||||
- use `create_vm(...)` + `start_vm(...)` only when you need pre-exec inspection or status before
|
||||
that final exec
|
||||
- use `create_workspace(seed_path=...)` when the agent needs repeated commands in one persistent
|
||||
`/workspace` that starts from host content
|
||||
- use `create_workspace(name=..., labels=...)`, `list_workspaces()`, and `update_workspace(...)`
|
||||
when the agent or operator needs to rediscover the right workspace later without external notes
|
||||
- use `push_workspace_sync(...)` when later host-side changes need to be imported into that
|
||||
running workspace without recreating it
|
||||
- use `list_workspace_files(...)`, `read_workspace_file(...)`, `write_workspace_file(...)`, and
|
||||
`apply_workspace_patch(...)` when the agent should inspect or edit workspace files without shell
|
||||
quoting tricks
|
||||
- use `create_workspace(..., secrets=...)` plus `secret_env` on exec, shell, or service start when
|
||||
the agent needs private tokens or authenticated startup inside that workspace
|
||||
- use `create_workspace(..., network_policy="egress+published-ports")` plus
|
||||
`start_service(..., published_ports=[...])` when the host must probe one service from that
|
||||
workspace
|
||||
- use `diff_workspace(...)` when the agent needs a structured comparison against the immutable
|
||||
create-time baseline
|
||||
- use `export_workspace(...)` when the agent needs one file or directory copied back to the host
|
||||
- use `stop_workspace(...)` plus `list_workspace_disk(...)`, `read_workspace_disk(...)`, or
|
||||
`export_workspace_disk(...)` when the agent needs offline inspection or one raw ext4 copy from
|
||||
a stopped guest-backed workspace
|
||||
- use `start_service(...)` when the agent needs long-running processes and typed readiness inside
|
||||
one workspace
|
||||
- use `open_shell(...)` when the agent needs interactive shell state instead of one-shot execs
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"pyro": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Examples:
|
||||
## When To Use `workspace-full`
|
||||
|
||||
- [examples/python_run.py](../examples/python_run.py)
|
||||
- [examples/python_lifecycle.py](../examples/python_lifecycle.py)
|
||||
- [examples/python_workspace.py](../examples/python_workspace.py)
|
||||
- [examples/python_shell.py](../examples/python_shell.py)
|
||||
- [docs/use-cases/README.md](use-cases/README.md)
|
||||
Stay on bare `pyro mcp serve` unless the chat host truly needs:
|
||||
|
||||
## Agent Framework Wrappers
|
||||
- persistent PTY shell sessions
|
||||
- long-running services and readiness probes
|
||||
- secrets
|
||||
- guest networking and published ports
|
||||
- stopped-workspace disk inspection or raw ext4 export
|
||||
|
||||
Examples:
|
||||
When that is necessary:
|
||||
|
||||
- LangChain tools
|
||||
- PydanticAI tools
|
||||
- custom in-house orchestration layers
|
||||
```bash
|
||||
pyro mcp serve --profile workspace-full
|
||||
```
|
||||
|
||||
Best when:
|
||||
## Recipe-Backed Workflows
|
||||
|
||||
- you already have an application framework that expects a Python callable tool
|
||||
- you want to wrap `vm_run` behind framework-specific abstractions
|
||||
Once the host is connected, move to the five real workflows in
|
||||
[use-cases/README.md](use-cases/README.md):
|
||||
|
||||
Recommended pattern:
|
||||
- cold-start repo validation
|
||||
- repro plus fix loops
|
||||
- parallel isolated workspaces
|
||||
- unsafe or untrusted code inspection
|
||||
- review and evaluation workflows
|
||||
|
||||
- keep the framework wrapper thin
|
||||
- map one-shot framework tool input directly onto `vm_run`
|
||||
- expose `workspace_*` only when the framework truly needs repeated commands in one workspace
|
||||
Validate the whole story with:
|
||||
|
||||
Concrete example:
|
||||
|
||||
- [examples/langchain_vm_run.py](../examples/langchain_vm_run.py)
|
||||
|
||||
## Selection Rule
|
||||
|
||||
Choose the narrowest integration that matches the host environment:
|
||||
|
||||
1. OpenAI Responses API if you want a direct provider tool loop.
|
||||
2. MCP if your host already speaks MCP.
|
||||
3. Python SDK if you own orchestration and do not need transport.
|
||||
4. Framework wrappers only as thin adapters over the same `vm_run` contract.
|
||||
```bash
|
||||
make smoke-use-cases
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue