Flip bare pyro mcp serve, create_server(), and Pyro.create_server() to default to workspace-core in 4.0.0 while keeping workspace-full as the explicit advanced opt-in surface. Rewrite the MCP-facing docs and host-specific examples around the bare default command, update package and catalog compatibility to 4.x, and move the public-contract wording from 3.x compatibility guidance to the new stable default. Adjust the server, API, and contract tests so bare server creation now asserts the workspace-core tool set, while explicit workspace-full coverage continues to prove shells, services, snapshots, and disk tools remain available. Validation: uv lock; .venv/bin/pytest --no-cov tests/test_cli.py tests/test_api.py tests/test_server.py tests/test_public_contract.py; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed smoke for bare Pyro.create_server() plus explicit profile="workspace-full".
164 lines
7.3 KiB
Markdown
164 lines
7.3 KiB
Markdown
# Integration Targets
|
|
|
|
These are the main ways to integrate `pyro-mcp` into an LLM application.
|
|
|
|
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).
|
|
|
|
## 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.
|
|
|
|
That keeps the model-facing contract small:
|
|
|
|
- one tool
|
|
- one command
|
|
- one ephemeral VM
|
|
- automatic cleanup
|
|
|
|
Profile progression:
|
|
|
|
- `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
|
|
|
|
## OpenAI Responses API
|
|
|
|
Best when:
|
|
|
|
- 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
|
|
|
|
Recommended surface:
|
|
|
|
- `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
|
|
|
|
Canonical example:
|
|
|
|
- [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)
|
|
|
|
## MCP Clients
|
|
|
|
Best when:
|
|
|
|
- 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
|
|
|
|
Recommended entrypoint:
|
|
|
|
- `pyro mcp serve`
|
|
|
|
Profile progression:
|
|
|
|
- `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
|
|
|
|
Host-specific onramps:
|
|
|
|
- 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)
|
|
|
|
## Direct Python SDK
|
|
|
|
Best when:
|
|
|
|
- your application owns orchestration itself
|
|
- you do not need MCP transport
|
|
- you want direct access to `Pyro`
|
|
|
|
Recommended default:
|
|
|
|
- `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
|
|
|
|
Lifecycle note:
|
|
|
|
- `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
|
|
|
|
Examples:
|
|
|
|
- [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)
|
|
|
|
## Agent Framework Wrappers
|
|
|
|
Examples:
|
|
|
|
- LangChain tools
|
|
- PydanticAI tools
|
|
- custom in-house orchestration layers
|
|
|
|
Best when:
|
|
|
|
- you already have an application framework that expects a Python callable tool
|
|
- you want to wrap `vm_run` behind framework-specific abstractions
|
|
|
|
Recommended pattern:
|
|
|
|
- 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
|
|
|
|
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.
|