Add opinionated MCP modes for workspace workflows

Introduce explicit repro-fix, inspect, cold-start, and review-eval modes across the MCP server, CLI, and host helpers, with canonical mode-to-tool mappings, narrowed schemas, and mode-specific tool descriptions on top of the existing workspace runtime.

Reposition the docs, host onramps, and use-case recipes so named modes are the primary user-facing startup story while the generic no-mode workspace-core path remains the escape hatch, and update the shared smoke runner to validate repro-fix and cold-start through mode-backed servers.

Validation: UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache uv run pytest --no-cov tests/test_api.py tests/test_server.py tests/test_host_helpers.py tests/test_public_contract.py tests/test_cli.py tests/test_workspace_use_case_smokes.py; UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make check; UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed make smoke-repro-fix-loop smoke-cold-start-validation outside the sandbox.
This commit is contained in:
Thales Maciel 2026-03-13 20:00:35 -03:00
parent dc86d84e96
commit d0cf6d8f21
33 changed files with 1034 additions and 274 deletions

View file

@ -3101,7 +3101,7 @@ def test_cli_workspace_shell_open_prints_id_only(
assert captured.err == ""
def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
def test_chat_host_docs_and_examples_recommend_modes_first() -> None:
readme = Path("README.md").read_text(encoding="utf-8")
install = Path("docs/install.md").read_text(encoding="utf-8")
first_run = Path("docs/first-run.md").read_text(encoding="utf-8")
@ -3110,19 +3110,24 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
claude_code = Path("examples/claude_code_mcp.md").read_text(encoding="utf-8")
codex = Path("examples/codex_mcp.md").read_text(encoding="utf-8")
opencode = json.loads(Path("examples/opencode_mcp_config.json").read_text(encoding="utf-8"))
claude_helper = "pyro host connect claude-code"
codex_helper = "pyro host connect codex"
opencode_helper = "pyro host print-config opencode"
claude_cmd = "claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve"
codex_cmd = "codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve"
claude_helper = "pyro host connect claude-code --mode cold-start"
codex_helper = "pyro host connect codex --mode repro-fix"
inspect_helper = "pyro host connect codex --mode inspect"
review_helper = "pyro host connect claude-code --mode review-eval"
opencode_helper = "pyro host print-config opencode --mode repro-fix"
claude_cmd = "claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --mode cold-start"
codex_cmd = "codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --mode repro-fix"
assert "## Chat Host Quickstart" in readme
assert claude_helper in readme
assert codex_helper in readme
assert inspect_helper in readme
assert review_helper in readme
assert opencode_helper in readme
assert "examples/opencode_mcp_config.json" in readme
assert "pyro host doctor" in readme
assert "bare `pyro mcp serve` starts `workspace-core`" in readme
assert "pyro mcp serve --mode repro-fix" in readme
assert "generic no-mode path" in readme
assert "auto-detects the current Git checkout" in readme.replace("\n", " ")
assert "--project-path /abs/path/to/repo" in readme
assert "--repo-url https://github.com/example/project.git" in readme
@ -3130,44 +3135,54 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
assert "## 5. Connect a chat host" in install
assert claude_helper in install
assert codex_helper in install
assert inspect_helper in install
assert review_helper in install
assert opencode_helper in install
assert "workspace-full" in install
assert "--project-path /abs/path/to/repo" in install
assert "pyro mcp serve --mode cold-start" in install
assert claude_helper in first_run
assert codex_helper in first_run
assert inspect_helper in first_run
assert review_helper in first_run
assert opencode_helper in first_run
assert "--project-path /abs/path/to/repo" in first_run
assert "pyro mcp serve --mode review-eval" in first_run
assert claude_helper in integrations
assert codex_helper in integrations
assert inspect_helper in integrations
assert review_helper in integrations
assert opencode_helper in integrations
assert "Bare `pyro mcp serve` starts `workspace-core`." in integrations
assert "## Recommended Modes" in integrations
assert "pyro mcp serve --mode inspect" in integrations
assert "auto-detects the current Git checkout" in integrations
assert "examples/claude_code_mcp.md" in integrations
assert "examples/codex_mcp.md" in integrations
assert "examples/opencode_mcp_config.json" in integrations
assert "That is the product path." in integrations
assert "generic no-mode path" in integrations
assert "--project-path /abs/path/to/repo" in integrations
assert "--repo-url https://github.com/example/project.git" in integrations
assert "Default for most chat hosts in `4.x`: `workspace-core`." in mcp_config
assert "Recommended named modes for most chat hosts in `4.x`:" in mcp_config
assert "Use the host-specific examples first when they apply:" in mcp_config
assert "claude_code_mcp.md" in mcp_config
assert "codex_mcp.md" in mcp_config
assert "opencode_mcp_config.json" in mcp_config
assert '"serve", "--mode", "repro-fix"' in mcp_config
assert claude_helper in claude_code
assert claude_cmd in claude_code
assert "claude mcp list" in claude_code
assert "pyro host repair claude-code" in claude_code
assert "pyro host repair claude-code --mode cold-start" in claude_code
assert "workspace-full" in claude_code
assert "--project-path /abs/path/to/repo" in claude_code
assert codex_helper in codex
assert codex_cmd in codex
assert "codex mcp list" in codex
assert "pyro host repair codex" in codex
assert "pyro host repair codex --mode repro-fix" in codex
assert "workspace-full" in codex
assert "--project-path /abs/path/to/repo" in codex
@ -3183,6 +3198,8 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
"pyro",
"mcp",
"serve",
"--mode",
"repro-fix",
],
}
}
@ -4349,12 +4366,14 @@ def test_cli_mcp_runs_stdio_transport(monkeypatch: pytest.MonkeyPatch) -> None:
self,
*,
profile: str,
mode: str | None,
project_path: str | None,
repo_url: str | None,
repo_ref: str | None,
no_project_source: bool,
) -> Any:
observed["profile"] = profile
observed["mode"] = mode
observed["project_path"] = project_path
observed["repo_url"] = repo_url
observed["repo_ref"] = repo_ref
@ -4367,21 +4386,23 @@ def test_cli_mcp_runs_stdio_transport(monkeypatch: pytest.MonkeyPatch) -> None:
class StubParser:
def parse_args(self) -> argparse.Namespace:
return argparse.Namespace(
command="mcp",
mcp_command="serve",
profile="workspace-core",
project_path="/repo",
repo_url=None,
repo_ref=None,
no_project_source=False,
)
return argparse.Namespace(
command="mcp",
mcp_command="serve",
profile="workspace-core",
mode=None,
project_path="/repo",
repo_url=None,
repo_ref=None,
no_project_source=False,
)
monkeypatch.setattr(cli, "_build_parser", lambda: StubParser())
monkeypatch.setattr(cli, "Pyro", StubPyro)
cli.main()
assert observed == {
"profile": "workspace-core",
"mode": None,
"project_path": "/repo",
"repo_url": None,
"repo_ref": None,