ghostlab 0.2.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. ghostlab-0.3.0/CONTRIBUTING.md +114 -0
  2. {ghostlab-0.2.1 → ghostlab-0.3.0}/PKG-INFO +303 -43
  3. {ghostlab-0.2.1 → ghostlab-0.3.0}/README.md +297 -39
  4. {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/cli.md +199 -10
  5. ghostlab-0.3.0/docs/concepts.md +143 -0
  6. ghostlab-0.3.0/docs/configured-agent-lab.md +238 -0
  7. {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/datasets-evaluation.md +10 -5
  8. ghostlab-0.3.0/docs/getting-started.md +350 -0
  9. ghostlab-0.3.0/docs/ghostlab-vision-gap-and-roadmap.md +181 -0
  10. ghostlab-0.3.0/docs/index.md +36 -0
  11. {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/publishing.md +4 -2
  12. {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/README.md +26 -2
  13. ghostlab-0.3.0/examples/agent-lab/AGENTS.md +4 -0
  14. ghostlab-0.3.0/examples/agent-lab/agent.json +22 -0
  15. ghostlab-0.3.0/examples/agent-lab/mcp.json +5 -0
  16. ghostlab-0.3.0/examples/agent-lab/repo/CHANGELOG.md +4 -0
  17. ghostlab-0.3.0/examples/agent-lab/repo/README.md +3 -0
  18. ghostlab-0.3.0/examples/agent-lab/repo/src/app.py +2 -0
  19. ghostlab-0.3.0/examples/agent-lab/skills/release-notes/SKILL.md +7 -0
  20. ghostlab-0.3.0/examples/agent-lab/tiny-mcp.js +62 -0
  21. ghostlab-0.3.0/examples/agent.json +50 -0
  22. ghostlab-0.3.0/examples/demo-skill/SKILL.md +9 -0
  23. {ghostlab-0.2.1 → ghostlab-0.3.0}/llms.txt +21 -10
  24. {ghostlab-0.2.1 → ghostlab-0.3.0}/mkdocs.yml +2 -1
  25. {ghostlab-0.2.1 → ghostlab-0.3.0}/pyproject.toml +6 -3
  26. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/__init__.py +1 -1
  27. ghostlab-0.3.0/rehearsal/agent_profile.py +290 -0
  28. ghostlab-0.3.0/rehearsal/agent_sandbox.py +324 -0
  29. ghostlab-0.3.0/rehearsal/agents.py +251 -0
  30. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/cli.py +1333 -141
  31. ghostlab-0.3.0/rehearsal/cli_ui.py +118 -0
  32. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/codex_backend.py +50 -1
  33. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/config.py +15 -2
  34. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/dashboard.py +90 -26
  35. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/dataset.py +5 -1
  36. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/evaluate.py +26 -7
  37. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/generate.py +6 -4
  38. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/__init__.py +24 -3
  39. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/base.py +1 -1
  40. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/direct.py +17 -2
  41. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/runner.py +39 -14
  42. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/inspect.py +3 -2
  43. ghostlab-0.3.0/rehearsal/jobs.py +530 -0
  44. ghostlab-0.3.0/rehearsal/lab.py +296 -0
  45. ghostlab-0.3.0/rehearsal/llm_backend.py +90 -0
  46. ghostlab-0.3.0/rehearsal/opencode_backend.py +201 -0
  47. ghostlab-0.3.0/rehearsal/opencode_config.py +223 -0
  48. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/orchestrator.py +108 -8
  49. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/personas.py +3 -3
  50. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/plan.py +21 -13
  51. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/plan_generate.py +24 -4
  52. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/profile.py +12 -4
  53. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/prompts.py +111 -3
  54. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/report.py +7 -3
  55. ghostlab-0.3.0/rehearsal/resolved_config.py +131 -0
  56. ghostlab-0.3.0/rehearsal/rollout_report.py +327 -0
  57. ghostlab-0.3.0/rehearsal/runner_presets.py +246 -0
  58. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/runners.py +115 -0
  59. ghostlab-0.3.0/rehearsal/sandbox.py +527 -0
  60. ghostlab-0.3.0/rehearsal/skills.py +47 -0
  61. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/spec.py +136 -1
  62. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/testrun.py +66 -5
  63. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/tool_capture.py +144 -1
  64. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/ui/app.py +305 -59
  65. ghostlab-0.3.0/tests/test_agents.py +83 -0
  66. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_cli_spec_flow.py +159 -22
  67. ghostlab-0.3.0/tests/test_codex_backend_sandbox.py +47 -0
  68. ghostlab-0.3.0/tests/test_configured_agent.py +383 -0
  69. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_hosts_runner.py +2 -2
  70. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_jobs.py +49 -0
  71. ghostlab-0.3.0/tests/test_opencode_backend.py +286 -0
  72. ghostlab-0.3.0/tests/test_prompts.py +32 -0
  73. ghostlab-0.3.0/tests/test_sandbox.py +132 -0
  74. ghostlab-0.3.0/tests/test_sandbox_stdio.py +213 -0
  75. ghostlab-0.3.0/tests/test_skills.py +39 -0
  76. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_testrun.py +36 -0
  77. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_tool_capture.py +9 -0
  78. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_widgets_and_dashboard.py +5 -0
  79. ghostlab-0.2.1/CONTRIBUTING.md +0 -56
  80. ghostlab-0.2.1/docs/concepts.md +0 -56
  81. ghostlab-0.2.1/docs/getting-started.md +0 -126
  82. ghostlab-0.2.1/docs/ghostlab-vision-gap-and-roadmap.md +0 -963
  83. ghostlab-0.2.1/docs/index.md +0 -26
  84. ghostlab-0.2.1/rehearsal/jobs.py +0 -245
  85. ghostlab-0.2.1/rehearsal/runner_presets.py +0 -113
  86. {ghostlab-0.2.1 → ghostlab-0.3.0}/.gitignore +0 -0
  87. {ghostlab-0.2.1 → ghostlab-0.3.0}/LICENSE +0 -0
  88. {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/mcp-config.json +0 -0
  89. {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/scenario.json +0 -0
  90. {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/target.json +0 -0
  91. {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/__init__.py +0 -0
  92. {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/__main__.py +0 -0
  93. {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/cli.py +0 -0
  94. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/__main__.py +0 -0
  95. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/__init__.py +0 -0
  96. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/assertions.py +0 -0
  97. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/executor.py +0 -0
  98. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/live.py +0 -0
  99. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/protocol.py +0 -0
  100. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/renderer.py +0 -0
  101. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/report.py +0 -0
  102. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/compare.py +0 -0
  103. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/contract.py +0 -0
  104. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/critique.py +0 -0
  105. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/logging.py +0 -0
  106. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_apps.py +0 -0
  107. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_client.py +0 -0
  108. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_config.py +0 -0
  109. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_targets.py +0 -0
  110. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/readiness.py +0 -0
  111. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/review.py +0 -0
  112. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/sampling.py +0 -0
  113. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/scorecard.py +0 -0
  114. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/setup_runtime.py +0 -0
  115. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/__init__.py +0 -0
  116. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/db.py +0 -0
  117. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/hashing.py +0 -0
  118. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/ids.py +0 -0
  119. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/migrations/0001_initial.sql +0 -0
  120. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/redact.py +0 -0
  121. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/repository.py +0 -0
  122. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/termcolor.py +0 -0
  123. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/types.py +0 -0
  124. {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/ui/__init__.py +0 -0
  125. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/claude-process.example.json +0 -0
  126. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-aut.json +0 -0
  127. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-local-aut.json +0 -0
  128. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-local-session.json +0 -0
  129. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-process.example.json +0 -0
  130. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-user-emulator.json +0 -0
  131. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/mock-aut.json +0 -0
  132. {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/mock-user.json +0 -0
  133. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_apps_host.py +0 -0
  134. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_apps_live.py +0 -0
  135. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_compare.py +0 -0
  136. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_config.py +0 -0
  137. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_contract.py +0 -0
  138. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_critique.py +0 -0
  139. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_dataset.py +0 -0
  140. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_evaluate.py +0 -0
  141. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_generate.py +0 -0
  142. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_inspect_lint.py +0 -0
  143. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_apps.py +0 -0
  144. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_client.py +0 -0
  145. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_targets.py +0 -0
  146. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_orchestrator.py +0 -0
  147. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_personas.py +0 -0
  148. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_plan.py +0 -0
  149. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_plan_generate.py +0 -0
  150. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_profile.py +0 -0
  151. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_readiness.py +0 -0
  152. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_review.py +0 -0
  153. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_runner_presets.py +0 -0
  154. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_sampling.py +0 -0
  155. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_scorecard.py +0 -0
  156. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_session_runner.py +0 -0
  157. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_setup_runtime.py +0 -0
  158. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_spec.py +0 -0
  159. {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_storage.py +0 -0
@@ -0,0 +1,114 @@
1
+ # Contributing to Ghostlab
2
+
3
+ Thanks for helping improve Ghostlab! This guide is written to be friendly to both
4
+ humans and coding agents. For a machine-readable map of the project, see
5
+ [`llms.txt`](llms.txt).
6
+
7
+ ## Project shape
8
+
9
+ - Python package: `rehearsal` · installed CLI: `ghostlab` (alias `rehearsal`).
10
+ - Pipeline: **understand → generate → run → evaluate**, plus optional SQLite
11
+ persistence, a Streamlit UI, and an MCP Apps render layer.
12
+ - The MCP client uses only the standard library; coding-agent CLIs (Codex /
13
+ Claude) are the agent backends.
14
+ - NVIDIA OpenShell is the default execution backend for real runner sessions
15
+ and local stdio MCPs; `--sandbox local` is the explicit trusted-host opt-out.
16
+
17
+ ## Setup
18
+
19
+ ```bash
20
+ python3 -m venv .venv # Python 3.10+
21
+ .venv/bin/pip install -e '.[dev]' # add ',ui' and/or ',apps' for those features
22
+ .venv/bin/pytest # run the test suite
23
+ ```
24
+
25
+ Optional extras:
26
+
27
+ - `.[ui]` — the Streamlit pipeline UI (`ghostlab ui`).
28
+ - `.[apps]` — Playwright, for rendering MCP Apps `ui://` widgets
29
+ (`ghostlab apps-render`). After install: `playwright install chrome`.
30
+
31
+ OpenShell integration work also needs a supported compute driver (Docker
32
+ Desktop is the simplest local option) and a connected gateway:
33
+
34
+ ```bash
35
+ openshell status
36
+ ghostlab doctor
37
+ ```
38
+
39
+ For documentation work:
40
+
41
+ ```bash
42
+ .venv/bin/mkdocs serve # live-preview the wiki locally
43
+ .venv/bin/mkdocs build --strict # what CI enforces
44
+ ```
45
+
46
+ ## Conventions
47
+
48
+ - **Support Python 3.10–3.13.** Keep syntax and dependencies compatible with
49
+ the declared `requires-python` range and CI matrix.
50
+ - **Test your change.** Most logic is pure and unit-tested with `unittest` under
51
+ `tests/`. Browser/network-dependent paths should degrade gracefully and be
52
+ guarded so the suite passes without them.
53
+ - **Keep artifacts hybrid.** Commands write human-readable `.md` + machine
54
+ `.json`; SQLite is the system of record but never required for a run to work.
55
+ - **Keep commits focused** on one logical change, with tests or docs alongside
56
+ behavior changes. Don't commit generated output (`jobs/`, `runs/`, `datasets/`,
57
+ `dist/`, `site/`), caches, or `.venv` — they're gitignored.
58
+ - Match the surrounding style: small modules, docstrings that explain *why*, and
59
+ no new heavyweight dependencies in the core (use an optional extra instead).
60
+
61
+ ## Making a change
62
+
63
+ 1. Branch off `main` (e.g. `feat/…`, `fix/…`, `docs/…`).
64
+ 2. Make the change with tests.
65
+ 3. Open a PR against `main` with a clear description of what and why. Reference
66
+ the issue it addresses (`Closes #NN`).
67
+
68
+ When you **add or change a CLI command**, update all of:
69
+
70
+ - `rehearsal/cli.py` (the command)
71
+ - `tests/` (coverage)
72
+ - `README.md` (the command reference)
73
+ - `docs/cli.md` (the wiki page)
74
+
75
+ Use `ghostlab` (not `rehearsal`) in public examples.
76
+
77
+ ## Pull request checklist
78
+
79
+ Run the checks that match your change:
80
+
81
+ ```bash
82
+ .venv/bin/pytest # always
83
+ .venv/bin/mkdocs build --strict # if you touched docs/ or mkdocs.yml
84
+ .venv/bin/python -m build # if you touched packaging
85
+ .venv/bin/twine check dist/* # "
86
+ ```
87
+
88
+ Run the full set for release, packaging, workflow, or public-CLI changes.
89
+
90
+ ## Documentation site
91
+
92
+ The wiki lives in `docs/` and is built with MkDocs. The **Pages** workflow
93
+ (`.github/workflows/pages.yml`) deploys it to GitHub Pages on pushes to `main`,
94
+ release tags, and manual runs. Public docs: <https://sajjadgg.github.io/Ghostlab/>.
95
+
96
+ ## Releases
97
+
98
+ Publishing to PyPI is automated by `.github/workflows/publish.yml` via
99
+ [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (no tokens).
100
+ It runs when you **publish a GitHub Release** (or dispatch the workflow manually).
101
+ Version tags use `v*.*.*`.
102
+
103
+ To cut a release:
104
+
105
+ 1. Bump `__version__` in `rehearsal/__init__.py`.
106
+ 2. Validate locally: `.venv/bin/pytest && .venv/bin/python -m build && .venv/bin/twine check dist/*`.
107
+ 3. `gh release create v<x.y.z> --generate-notes` — this triggers `publish.yml`.
108
+
109
+ ## Where to start
110
+
111
+ Browse the [open issues](https://github.com/sajjadGG/Ghostlab/issues) — they are
112
+ labeled by pipeline stage (`pipeline:understand`, `pipeline:run`,
113
+ `pipeline:evaluate`, …). Good first contributions: a new target/scenario/runner
114
+ preset, an additional lint or assertion, or a per-widget MCP Apps assertion.
@@ -1,13 +1,13 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: ghostlab
3
- Version: 0.2.1
4
- Summary: Local end-to-end testing lab for any MCP server: coding agents role-play real users, drive your tools over multiple turns, score runs, and render/interact with MCP Apps ui:// widgets.
3
+ Version: 0.3.0
4
+ Summary: OpenShell-first end-to-end evaluation lab for configured AI agents, MCP servers, skills, and MCP Apps.
5
5
  Project-URL: Documentation, https://sajjadgg.github.io/Ghostlab/
6
6
  Project-URL: Homepage, https://github.com/sajjadGG/Ghostlab
7
7
  Project-URL: Repository, https://github.com/sajjadGG/Ghostlab
8
8
  Project-URL: Issues, https://github.com/sajjadGG/Ghostlab/issues
9
9
  Project-URL: Changelog, https://github.com/sajjadGG/Ghostlab/releases
10
- Author: Sajjad Gholamzadeh
10
+ Author: SajjadGG
11
11
  License: MIT
12
12
  License-File: LICENSE
13
13
  Keywords: agents,ai-agents,claude,cli,codex,end-to-end-testing,evaluation,llm,llm-evaluation,mcp,mcp-apps,model-context-protocol,testing
@@ -25,6 +25,8 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
25
25
  Classifier: Topic :: Software Development :: Quality Assurance
26
26
  Classifier: Topic :: Software Development :: Testing
27
27
  Requires-Python: >=3.10
28
+ Requires-Dist: questionary<3,>=2.1
29
+ Requires-Dist: rich<16,>=14
28
30
  Provides-Extra: apps
29
31
  Requires-Dist: playwright>=1.40; extra == 'apps'
30
32
  Provides-Extra: dev
@@ -40,7 +42,7 @@ Description-Content-Type: text/markdown
40
42
 
41
43
  # Ghostlab
42
44
 
43
- > A local, end-to-end **testing lab for any MCP server** — coding agents role-play
45
+ > A local, end-to-end **testing lab for configured AI agents** — coding agents role-play
44
46
  > real users, drive your tools over multiple turns, and the harness captures
45
47
  > traces, scores outcomes, and even **renders and clicks through MCP Apps UI
46
48
  > widgets**.
@@ -51,12 +53,13 @@ Description-Content-Type: text/markdown
51
53
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
52
54
  [![llms.txt](https://img.shields.io/badge/llms.txt-✓-purple)](llms.txt)
53
55
 
54
- **Test your MCP server the way it's actually used** — not with unit tests against
56
+ **Test an agent the way it is actually used** — not only with unit tests against
55
57
  the protocol, but with a real coding agent (Codex / Claude) that picks tools,
56
58
  makes mistakes, and tries to accomplish goals, while a second agent plays the
57
59
  user. Protocol-level checks (schema errors, a tool call that 500s) are useful
58
60
  sanity checks, but they aren't the real test — the real test is whether an
59
- agent can actually get a task done through your MCP, end to end.
61
+ agent can actually get a task done with its configured MCPs, skills, workspace,
62
+ instructions, and runner, end to end.
60
63
 
61
64
  📖 **Docs wiki:** https://sajjadgg.github.io/Ghostlab/ · 🤖 **For agents:** [`llms.txt`](llms.txt) · 🛠 **Contributing:** [`CONTRIBUTING.md`](CONTRIBUTING.md)
62
65
 
@@ -74,21 +77,67 @@ agent can actually get a task done through your MCP, end to end.
74
77
  python3 -m venv .venv # Python 3.10+
75
78
  .venv/bin/pip install -e . # add '.[ui]' for the web UI, '.[apps]' for widget rendering
76
79
 
77
- ghostlab create
80
+ ghostlab create # evaluate an MCP server
81
+ ghostlab lab # evaluate a configured agent (model, skills, MCPs, code)
78
82
  ```
79
83
 
80
- That's the whole flow. `ghostlab create` walks you through everything, end to end:
84
+ Pick `create` when the thing under test is an **MCP server**, and
85
+ [`lab`](#evaluate-a-configured-agent-ghostlab-lab) when it is an **agent** — a
86
+ model plus instructions, skills, MCPs, permissions, and a codebase.
81
87
 
82
- 1. **Name + target** — the only two prompts. A target is an MCP URL, or a path
83
- to a target JSON / standard `mcpServers` config.
88
+ Ghostlab uses [NVIDIA OpenShell](https://docs.nvidia.com/openshell/latest/)
89
+ as its default execution boundary. Install OpenShell, start a supported compute
90
+ driver (Docker Desktop is the simplest local option), and confirm the gateway:
91
+
92
+ ```bash
93
+ openshell status
94
+ ghostlab doctor
95
+ ```
96
+
97
+ `openshell status` must say `Connected`. On a Homebrew installation, a refused
98
+ connection commonly means Docker is stopped or the gateway needs restarting:
99
+
100
+ ```bash
101
+ open -a Docker # macOS, when Docker Desktop is installed
102
+ brew services restart openshell
103
+ openshell status
104
+ ```
105
+
106
+ OpenShell is the default; there is no `--local` flag. Use the explicit
107
+ `--sandbox local` escape hatch only for trusted code that you intentionally
108
+ want to execute directly on the host:
109
+
110
+ ```bash
111
+ ghostlab create --name trusted --agent agent.yaml --sandbox local --yes
112
+ ghostlab discover --job trusted --sandbox local
113
+ ghostlab test --job trusted --sandbox local
114
+ ghostlab run ... --sandbox local
115
+ ```
116
+
117
+ With OpenShell, Ghostlab creates separate sandboxes for the agent under test
118
+ and user emulator, stages only declared files, forwards only allowlisted
119
+ environment variables, attaches named OpenShell providers, captures sandbox
120
+ logs with the run artifacts, and deletes the sandboxes at teardown. Local stdio
121
+ MCP processes in the job pipeline are routed through the same boundary. OpenShell failures remain
122
+ `harness_error`s and never silently fall back to host execution.
123
+
124
+ That's the whole flow. Interactive `ghostlab create` guides you through the
125
+ evaluation subject (agent/MCP/skill), OpenShell image/providers, generation
126
+ size, four model roles (AUT, user emulator, generation, and judge), Codex
127
+ approval/sandbox policy, runner lifecycle/timeout, release gate, and whether to
128
+ run immediately. The Questionary/Rich terminal UI provides arrow-key selection,
129
+ multi-select suite picking, color, and numbered progress. The same choices
130
+ remain available as flags for scripts and CI.
131
+
132
+ `ghostlab create` walks through everything, end to end:
133
+
134
+ 1. **Name + agent/target** — an agent JSON/YAML can compose a runner, MCPs,
135
+ skills, workspace, and assets. `--target` and `--skill` remain simple shorthands.
84
136
  2. **Discover** — connects to the target, lints its contract (schema errors,
85
137
  risk labels), and probes any MCP Apps `ui://` widgets.
86
- 3. **Configure semantic testing** — if `codex` is on your `$PATH`, offers to
87
- wire it up as the **agent-under-test**: a real coding-agent session with
88
- your MCP's tools available, so the dual-agent conversations below have
89
- something to actually drive. (No codex? The wizard still finishes —
90
- protocol-level suites still run, semantic/security just skip until a host
91
- is configured; see [Runner Configs](#runner-configs).)
138
+ 3. **Configure semantic testing** — wires the configured runner (Codex by
139
+ default) as the **agent-under-test** and displays its exact command, model,
140
+ approval mode, nested sandbox, parser, and timeout.
92
141
  4. **Generate a test plan** — personas × scenarios for the semantic/security
93
142
  suites, plus deterministic coverage for every discovered tool
94
143
  (`test-plan.yaml`), all editable afterward.
@@ -104,15 +153,44 @@ repeating the whole wizard:
104
153
 
105
154
  ```bash
106
155
  ghostlab discover --job <name> # re-inspect after the target changes
156
+ ghostlab config --job <name> # exact resolved runner/models/sandbox config
107
157
  ghostlab plan --job <name> # regenerate/curate the test plan
108
158
  ghostlab test --job <name> # rerun (add --suite semantic to narrow it)
159
+ ghostlab test --job <name> --resume # keep completed cases; retry harness outages
160
+ ghostlab create --name <name> --resume --yes # continue the full job pipeline
109
161
  ghostlab review --job <name> # the readiness/gate report on its own
110
162
  ```
111
163
 
112
- A job is a self-contained folder: `jobs/<name>/job.yaml` (target, hosts,
164
+ The end-to-end creator has a strict semantic contract: it only prints
165
+ `Evaluation ready` after at least one semantic/security conversation actually
166
+ runs. Missing model access, an unavailable OpenShell provider, failed scenario
167
+ generation, and placeholder-only plans produce a non-zero exit with corrective
168
+ details. Standalone automation can opt into the same contract with
169
+ `ghostlab plan --require-semantic` and `ghostlab test --require-semantic`.
170
+
171
+ A job is a self-contained folder: `jobs/<name>/job.yaml` (agent, target, sandbox, hosts,
113
172
  generation/test defaults, gates — all editable), `test-plan.yaml`, `workspace/`
114
173
  (discover/generated/test artifacts + a local sqlite db), and `runs/`.
115
174
 
175
+ To evaluate a skill instead of an MCP server:
176
+
177
+ ```bash
178
+ ghostlab create --name release-notes-skill --skill ./skills/release-notes --yes
179
+ ```
180
+
181
+ Skill discovery reads `SKILL.md`; planning generates persona-grounded semantic
182
+ and adversarial cases; testing injects the skill instructions into the AUT and
183
+ judges observable compliance. MCP-only protocol and Apps suites are omitted.
184
+
185
+ To evaluate a composed agent:
186
+
187
+ ```bash
188
+ ghostlab create --name my-agent --agent examples/agent.json --yes
189
+ ```
190
+
191
+ The agent definition is the canonical evaluation subject. A one-MCP or
192
+ one-skill job is normalized into the same shape.
193
+
116
194
  ## What you get
117
195
 
118
196
  | Stage | What it produces |
@@ -121,6 +199,11 @@ generation/test defaults, gates — all editable), `test-plan.yaml`, `workspace/
121
199
  | **Plan** | A coverage-driven `test-plan.yaml`: deterministic protocol cases for every tool, plus generated persona/scenario cases for the semantic/security suites |
122
200
  | **Test** | Multi-host execution results (`results.json`/`results.md`), a standalone HTML dashboard, and — for conversational cases — full dual-agent transcripts with structured tool-call capture |
123
201
  | **Review** | A readiness report: pass/fail gate verdict, failure clusters, and prioritized repairs |
202
+ | **Rollout** | With `--pdf`, one document per run: configuration, inferred purpose, personas, transcript with tool calls, judge evidence, and critique |
203
+
204
+ For a configured agent, `ghostlab lab` adds an inferred **purpose profile** —
205
+ what the agent is for, its workflows, and its risk surface — and drives
206
+ generation from that instead of from the tool inventory.
124
207
 
125
208
  ## See it in action
126
209
 
@@ -150,8 +233,9 @@ reasoning, and the full dual-agent transcript with inline tool calls:
150
233
 
151
234
  Build a repeatable, sandboxed tester that can:
152
235
 
153
- - Run any target MCP app in an isolated environment.
154
- - Launch one coding-agent session as the **agent-under-test** (with target MCP injected).
236
+ - Run arbitrary configured agents inside NVIDIA OpenShell.
237
+ - Compose zero or more MCPs, skills, instructions, workspace files, and assets.
238
+ - Launch one coding-agent session as the **agent-under-test**.
155
239
  - Launch another coding-agent session as the **user emulator** (persona + goal driven).
156
240
  - Drive multi-turn interactions between them.
157
241
  - Capture full traces, tool activity, failures, and outcomes.
@@ -162,9 +246,11 @@ This lets you test with your existing Codex/Claude usage path, instead of wiring
162
246
 
163
247
  Ghostlab is intentionally **app-agnostic**:
164
248
 
165
- - Works with any MCP server reachable by stdio/SSE/streamable HTTP.
249
+ - Treats an agent configuration—not a single MCP—as the evaluation boundary.
250
+ - Works with MCP servers reachable by stdio/SSE/streamable HTTP and local skills.
166
251
  - Supports local or remote MCP endpoints.
167
- - Supports multiple coding-agent runners (Codex, Claude Code, and future adapters).
252
+ - Supports multiple coding-agent runners (Codex, OpenCode, Claude Code, and future adapters).
253
+ - Expresses an OpenCode agent's full configuration — model, instructions, skills, subagents, tool permissions, and any number of MCPs — and runs all of it inside the sandbox.
168
254
 
169
255
  No Cortex-specific assumptions are required in the core harness.
170
256
 
@@ -202,11 +288,12 @@ jobs/<name>/
202
288
 
203
289
  ### Core dual-harness architecture
204
290
 
205
- 1. **AUT Harness (Agent Under Test)** — starts a coding-agent session (Codex or
206
- Claude Code), injects the target MCP server config into it, and exposes a
291
+ 1. **AUT Harness (Agent Under Test)** — starts the configured runner (Codex,
292
+ Claude Code, or another process) inside OpenShell, supplies its complete
293
+ MCP/skill/workspace composition, and exposes a
207
294
  controlled I/O bridge so it can receive user messages and return
208
295
  replies/tool results.
209
- 2. **User Emulator Harness** — starts a second coding-agent session, gives it a
296
+ 2. **User Emulator Harness** — starts a second isolated coding-agent session, gives it a
210
297
  scenario file (persona, goals, constraints, success criteria), and asks it
211
298
  to act like a realistic user, sending messages turn-by-turn to the AUT.
212
299
  3. **Orchestrator** — coordinates turn-taking, timeouts, retries, and stop
@@ -215,18 +302,26 @@ jobs/<name>/
215
302
 
216
303
  ### Target configuration model
217
304
 
218
- Each test run points to a target definition:
305
+ Each test run points to an agent definition. Legacy target fields remain the
306
+ primary discovery input for one-MCP/one-skill jobs:
219
307
 
220
308
  - `target.id`: unique name (`filesystem-mcp-local`, `my-app-staging`)
221
- - `transport`: `stdio` | `sse` | `streamable-http`
309
+ - `transport`: `stdio` | `sse` | `streamable-http` | `skill`
222
310
  - `connection`: command+args+env (stdio) or URL+headers (network transports)
223
311
  - `capabilities`: optional expected tools/resources/prompts
224
312
  - `startup`: optional health checks and boot timeout
225
313
 
314
+ The canonical `agent` section contains `runner`, `instructions`, and composable
315
+ `inputs.mcps`, `inputs.skills`, and assets. The sibling `sandbox` section defaults
316
+ to OpenShell and controls the image, uploads, workdir, policy, resource limits,
317
+ network mode, environment allowlist, providers, logs, and cleanup.
318
+ `backend: local` is explicit unsandboxed compatibility—not a fallback.
319
+
226
320
  ### Commands
227
321
 
228
322
  The package installs two equivalent console scripts: `ghostlab` and `rehearsal`.
229
323
 
324
+ - `ghostlab lab` — guided setup for a **configured agent** (model, instructions, skills, MCPs, permissions, code), then generate scenarios from its inferred purpose and run them fully sandboxed.
230
325
  - `ghostlab create` — the end-to-end wizard described above.
231
326
  - `ghostlab init` — advanced: scaffold a standalone `ghostlab.yaml` **spec** from a target JSON (see [spec vs job](#spec-vs-job) — most users want `ghostlab create`).
232
327
  - `ghostlab discover` — inspect the job's target, lint its contract, refresh capabilities.
@@ -243,11 +338,125 @@ The package installs two equivalent console scripts: `ghostlab` and `rehearsal`.
243
338
  - `ghostlab scorecard` — roll run verdicts and critiques into a summary scorecard.
244
339
  - `ghostlab compare` — diff two dataset runs for regressions.
245
340
  - `ghostlab apps-probe` / `apps-render` — probe/render MCP Apps `ui://` widgets.
246
- - `ghostlab doctor` — check codex and validate runner presets.
341
+ - `ghostlab doctor` — check the sandbox and both LLM backends (`--probe` for a live check).
247
342
  - `ghostlab dashboard` — build a standalone HTML dashboard for a `ghostlab test` run.
248
343
  - `ghostlab ui` — launch the Streamlit pipeline UI.
249
344
  - `ghostlab db` — manage the SQLite persistence database.
250
345
 
346
+ ### Evaluate a configured agent: `ghostlab lab`
347
+
348
+ `ghostlab create` evaluates an **MCP server**. `ghostlab lab` evaluates an
349
+ **agent** — the thing you actually ship: a model plus instructions, skills, MCP
350
+ servers, tool permissions, subagents, and a codebase it operates on.
351
+
352
+ ```bash
353
+ ghostlab lab --name release-bot
354
+ ```
355
+
356
+ It walks ten steps, and nothing generated is used before you have seen it:
357
+
358
+ | Step | |
359
+ | --- | --- |
360
+ | 1 Source | An existing `opencode.json`, an agent config, or from scratch |
361
+ | 2 Purpose | Your description — authoritative over anything inferred |
362
+ | 3 Model | Only models your OpenCode install can actually reach |
363
+ | 4 Capabilities | Import from a standard `mcpServers` config, pick per server |
364
+ | 5 Instructions, skills, code | Instruction files, skill folders, the workspace |
365
+ | 6 Permissions | `read-only` / `edit-workspace` / `full-shell`, blast radius spelled out |
366
+ | 7 Sandbox | Image, and the explicit credential opt-in |
367
+ | 8 Profile | Review the inferred purpose, workflows, and risk surface |
368
+ | 9 Scenarios | Generated from that profile; drop any you do not want |
369
+ | 10 Run | Execute, judge, and report |
370
+
371
+ Every answer is written to `job.yaml`, so the result is a reproducible file
372
+ rather than a conversation that happened once.
373
+
374
+ #### Purpose-driven generation
375
+
376
+ Persona and scenario generation for an MCP job works from the tool inventory.
377
+ For an agent that is the wrong question: an agent whose purpose lives in its
378
+ prompt would get scenarios about tool families instead of about its job.
379
+
380
+ Ghostlab instead reads the agent's description, instruction files, skill
381
+ definitions, subagent prompts, permission posture, and MCP inventory, and infers
382
+ what it is *for* — purpose, audience, workflows, and a grounded **risk surface**
383
+ that seeds the adversarial scenarios. From a small release assistant it produced
384
+ risks like *"prompt injection through changelog contents"* and *"claiming a
385
+ release was published, violating the core instruction"*.
386
+
387
+ The result is written to `workspace/agent-profile.json` and shown for review
388
+ before anything is generated from it.
389
+
390
+ #### Everything runs in the sandbox
391
+
392
+ A configured agent is only worth testing with real permissions, and those are
393
+ exactly the ones you do not want on your machine. So the whole agent goes
394
+ inside OpenShell:
395
+
396
+ - the **CLI** comes from `docker/agent-sandbox.Dockerfile` (a Linux image with
397
+ OpenCode installed — the host binary is platform-specific and cannot be
398
+ uploaded), and runs over the SSH channel;
399
+ - its **MCPs** are launched by OpenCode inside that same container;
400
+ - its **code** is an uploaded copy at `/sandbox/workspace`, so `edit` and `bash`
401
+ act on a throwaway;
402
+ - **credentials** are an explicit opt-in, uploaded outside the workspace at mode
403
+ 600, and redacted from every report;
404
+ - **network** is default-deny, with a generated policy allowing only the model
405
+ provider and OpenCode's model catalog. Anything else the agent reaches for is
406
+ denied and shows up in the sandbox log — which is itself a finding.
407
+
408
+ #### Rollout report
409
+
410
+ `--pdf` assembles one document per run: the resolved configuration (secrets
411
+ redacted), the inferred purpose, personas and scenarios, the full transcript
412
+ with every tool call and its latency, the judge verdict with per-criterion
413
+ evidence, and the tool-usability critique.
414
+
415
+ ```bash
416
+ ghostlab test --job release-bot --pdf # rollout.html + rollout.pdf per run
417
+ ```
418
+
419
+ PDF rendering uses the browser the MCP Apps host already needs
420
+ (`pip install 'ghostlab[apps]'`); without it the HTML is still written.
421
+
422
+ See [Configured Agent Lab](docs/configured-agent-lab.md) for the full design.
423
+
424
+ ### Drive Ghostlab from a coding agent: the `ghostlab` skill
425
+
426
+ `skills/ghostlab/` packages Ghostlab as a skill, so Claude Code (or any harness
427
+ that loads `SKILL.md`) can set up an evaluation, run it, and read the results
428
+ without being handed the CLI surface each time.
429
+
430
+ ```bash
431
+ mkdir -p ~/.claude/skills
432
+ ln -s "$PWD/skills/ghostlab" ~/.claude/skills/ghostlab # or .claude/skills/ for one project
433
+ ```
434
+
435
+ Then just ask: *"test whether this MCP actually works with a real agent"* or
436
+ *"evaluate this agent config and tell me what breaks"*.
437
+
438
+ The skill steers toward the **file-driven path** rather than the interactive
439
+ wizard, because that is what a harness can actually drive and a reviewer can
440
+ actually diff:
441
+
442
+ ```bash
443
+ ghostlab create --name release-bot --agent ./agent.json --no-discover --yes
444
+ ghostlab discover --job release-bot
445
+ ghostlab plan --job release-bot --llm-backend opencode --model github-copilot/claude-sonnet-4.5
446
+ ghostlab test --job release-bot --llm-backend opencode --model github-copilot/claude-sonnet-4.5 --pdf
447
+ ghostlab review --job release-bot
448
+ ```
449
+
450
+ An `agent.json` carries the full declarative runtime — model, instructions,
451
+ skills, subagents, permissions, and any number of MCPs — with every path
452
+ resolved relative to the file. `examples/agent-lab/` is a complete working one.
453
+
454
+ It also encodes the judgement calls that are easy to get wrong: that a `fail` is
455
+ usually a real finding rather than a harness bug, that the deterministic
456
+ tool-call record outranks the judge's narrative when they disagree, and that
457
+ `--sandbox local` is *required* (not optional) for MCPs needing host-only
458
+ resources. See [`skills/README.md`](skills/README.md).
459
+
251
460
  ### The UI: `ghostlab ui`
252
461
 
253
462
  Run the whole pipeline from a browser instead of the CLI:
@@ -257,11 +466,12 @@ pip install 'ghostlab[ui]' # installs streamlit
257
466
  ghostlab ui # opens http://localhost:8501
258
467
  ```
259
468
 
260
- The app mirrors the same job-based flow as `ghostlab create`: pick or create a
261
- job, discover its target, configure the agent-under-test host, generate and
262
- curate the test plan, run selected suites, and review colored results and full
263
- conversation traces — the same `job.yaml`/`test-plan.yaml`/`results.json` a CLI
264
- run of the same job would produce.
469
+ The app mirrors the same job-based flow as `ghostlab create`. Its new-evaluation
470
+ screen accepts composed agents, MCPs, or skills and configures OpenShell,
471
+ providers, generation size, and gates in one place. An overview shows pipeline
472
+ completion and resolved configuration; long stages stream their CLI logs live;
473
+ results can be filtered and exported as the standalone dashboard. It reads and
474
+ writes the same `job.yaml`/`test-plan.yaml`/`results.json` artifacts as the CLI.
265
475
 
266
476
  ### Understand a new MCP: `inspect`
267
477
 
@@ -383,12 +593,15 @@ ghostlab run-dataset \
383
593
  --target target.json \
384
594
  --aut-runner runners/codex-cortex-aut.json \
385
595
  --user-runner runners/codex-user-emulator.json \
596
+ --provider openai \
386
597
  --limit 2
387
598
  ```
388
599
 
389
600
  Each case runs through the orchestrator (with its persona) into its own run
390
601
  directory, and a dataset-level `summary.md` + `results.json` capture per-case
391
- status and turn counts.
602
+ status and turn counts. `--provider` attaches an existing OpenShell provider to
603
+ the runner sandboxes (and judge when `--evaluate` is used); repeat it when the
604
+ composition needs more than one provider.
392
605
 
393
606
  ### Tool-call capture & output hygiene
394
607
 
@@ -469,26 +682,73 @@ ghostlab run --target target.json --scenario <scenario.json> \
469
682
  ```bash
470
683
  ghostlab doctor # validates runners/*.json
471
684
  ghostlab doctor --runners runners/codex-cortex-local-session.json
685
+ ghostlab doctor --sandbox local # trusted local mode; skips OpenShell checks
472
686
  ```
473
687
 
474
- Reports the codex binary + version and validates each runner's kind, command,
475
- and parser.
688
+ Reports both LLM backends (codex and opencode) with the selected one marked,
689
+ validates each runner's kind, command, and parser, and checks the OpenShell
690
+ CLI/gateway by default. Add `--probe` to verify a backend can actually answer
691
+ instead of only confirming its binary exists.
692
+
693
+ ### Coding-agent backends (codex or opencode)
694
+
695
+ Ghostlab drives a coding-agent CLI for generation, the agent-under-test, and
696
+ judging. `inspect` needs no agent — it is a direct MCP client.
697
+
698
+ | Backend | Select with | Models |
699
+ | --- | --- | --- |
700
+ | `codex` (default) | `--llm-backend codex` | Your ChatGPT/Codex plan |
701
+ | `opencode` | `--llm-backend opencode` | GitHub Copilot, Azure, and any other provider you have authenticated |
476
702
 
477
- ### Default agent backend
703
+ The codex binary is auto-detected from `$PATH`, then the macOS app bundle
704
+ (`/Applications/Codex.app/Contents/Resources/codex`); override with
705
+ `$REHEARSAL_CODEX_BIN` or `--codex-bin`. The opencode binary is auto-detected
706
+ from `$PATH` then `~/.opencode/bin/opencode`; override with
707
+ `$GHOSTLAB_OPENCODE_BIN`.
478
708
 
479
- `codex` is the default coding-agent backend for generation, the
480
- agent-under-test, and judging. `inspect` needs no agent — it is a direct MCP
481
- client. The codex binary is auto-detected from `$PATH`, then the macOS app
482
- bundle (`/Applications/Codex.app/Contents/Resources/codex`); override with
483
- `$REHEARSAL_CODEX_BIN` or `--codex-bin`.
709
+ Use opencode when codex is unavailable — no plan, exhausted quota, or a CLI too
710
+ old for the model your account is pinned to. With Copilot already authenticated
711
+ (`opencode auth login`), the whole loop runs on it:
712
+
713
+ ```bash
714
+ ghostlab plan --job my-job --llm-backend opencode --model github-copilot/claude-sonnet-4.5
715
+ ghostlab test --job my-job --llm-backend opencode --model github-copilot/claude-sonnet-4.5
716
+ ```
717
+
718
+ Set it once per job instead of per command via `generation.backend` in
719
+ `job.yaml`, or globally with `$GHOSTLAB_LLM_BACKEND`. Precedence is
720
+ `--llm-backend` > `job.yaml` > env var > `codex`. Pick any model
721
+ `opencode models github-copilot` lists; Ghostlab always pins one explicitly
722
+ rather than inheriting opencode's own default, which may not exist on your
723
+ provider.
724
+
725
+ Verify a backend can actually answer — not just that its binary exists —
726
+ with `ghostlab doctor --probe`. A `--version` check cannot detect an expired
727
+ quota or a CLI/model mismatch, and those otherwise surface much later as
728
+ `generation skipped`.
729
+
730
+ This is separate from the execution backend: Codex is the default agent
731
+ program, while OpenShell is the default sandbox in which agent programs run.
732
+ Standalone `ghostlab inspect` is a low-level direct protocol command; for an
733
+ untrusted local stdio MCP, create a job and use `ghostlab discover` so its
734
+ declared uploads and sandbox policy are applied.
484
735
 
485
736
  ### Colored output
486
737
 
487
- CLI output is colored automatically on a TTY (dual-agent transcripts,
738
+ Interactive `ghostlab create` uses Questionary for arrow-key choices and
739
+ checkbox multi-select, with Rich panels and progress presentation. The rest of
740
+ the CLI is colored automatically on a TTY (dual-agent transcripts,
488
741
  pass/fail/skip verdicts, gate failures). Set `NO_COLOR=1` (or
489
742
  `GHOSTLAB_COLOR=0`) to disable it, `GHOSTLAB_COLOR=1` to force it on (e.g.
490
743
  piping into a pager that groks ANSI).
491
744
 
745
+ Use `ghostlab config --job <name>` to see the exact effective Codex command,
746
+ model, approval policy, nested sandbox, runner parser/timeout, all four model
747
+ roles, composed MCP/skill inputs, and OpenShell configuration. Add `--json` for
748
+ machine-readable output. If a command omits `-m`, Ghostlab resolves the
749
+ top-level model from Codex's `config.toml` and identifies that source. The
750
+ Streamlit Overview and Configure tab expose the same values.
751
+
492
752
  ## Runner Configs
493
753
 
494
754
  Mock runner (no agent, free):