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.
- ghostlab-0.3.0/CONTRIBUTING.md +114 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/PKG-INFO +303 -43
- {ghostlab-0.2.1 → ghostlab-0.3.0}/README.md +297 -39
- {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/cli.md +199 -10
- ghostlab-0.3.0/docs/concepts.md +143 -0
- ghostlab-0.3.0/docs/configured-agent-lab.md +238 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/datasets-evaluation.md +10 -5
- ghostlab-0.3.0/docs/getting-started.md +350 -0
- ghostlab-0.3.0/docs/ghostlab-vision-gap-and-roadmap.md +181 -0
- ghostlab-0.3.0/docs/index.md +36 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/docs/publishing.md +4 -2
- {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/README.md +26 -2
- ghostlab-0.3.0/examples/agent-lab/AGENTS.md +4 -0
- ghostlab-0.3.0/examples/agent-lab/agent.json +22 -0
- ghostlab-0.3.0/examples/agent-lab/mcp.json +5 -0
- ghostlab-0.3.0/examples/agent-lab/repo/CHANGELOG.md +4 -0
- ghostlab-0.3.0/examples/agent-lab/repo/README.md +3 -0
- ghostlab-0.3.0/examples/agent-lab/repo/src/app.py +2 -0
- ghostlab-0.3.0/examples/agent-lab/skills/release-notes/SKILL.md +7 -0
- ghostlab-0.3.0/examples/agent-lab/tiny-mcp.js +62 -0
- ghostlab-0.3.0/examples/agent.json +50 -0
- ghostlab-0.3.0/examples/demo-skill/SKILL.md +9 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/llms.txt +21 -10
- {ghostlab-0.2.1 → ghostlab-0.3.0}/mkdocs.yml +2 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/pyproject.toml +6 -3
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/__init__.py +1 -1
- ghostlab-0.3.0/rehearsal/agent_profile.py +290 -0
- ghostlab-0.3.0/rehearsal/agent_sandbox.py +324 -0
- ghostlab-0.3.0/rehearsal/agents.py +251 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/cli.py +1333 -141
- ghostlab-0.3.0/rehearsal/cli_ui.py +118 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/codex_backend.py +50 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/config.py +15 -2
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/dashboard.py +90 -26
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/dataset.py +5 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/evaluate.py +26 -7
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/generate.py +6 -4
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/__init__.py +24 -3
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/base.py +1 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/direct.py +17 -2
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/hosts/runner.py +39 -14
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/inspect.py +3 -2
- ghostlab-0.3.0/rehearsal/jobs.py +530 -0
- ghostlab-0.3.0/rehearsal/lab.py +296 -0
- ghostlab-0.3.0/rehearsal/llm_backend.py +90 -0
- ghostlab-0.3.0/rehearsal/opencode_backend.py +201 -0
- ghostlab-0.3.0/rehearsal/opencode_config.py +223 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/orchestrator.py +108 -8
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/personas.py +3 -3
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/plan.py +21 -13
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/plan_generate.py +24 -4
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/profile.py +12 -4
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/prompts.py +111 -3
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/report.py +7 -3
- ghostlab-0.3.0/rehearsal/resolved_config.py +131 -0
- ghostlab-0.3.0/rehearsal/rollout_report.py +327 -0
- ghostlab-0.3.0/rehearsal/runner_presets.py +246 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/runners.py +115 -0
- ghostlab-0.3.0/rehearsal/sandbox.py +527 -0
- ghostlab-0.3.0/rehearsal/skills.py +47 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/spec.py +136 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/testrun.py +66 -5
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/tool_capture.py +144 -1
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/ui/app.py +305 -59
- ghostlab-0.3.0/tests/test_agents.py +83 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_cli_spec_flow.py +159 -22
- ghostlab-0.3.0/tests/test_codex_backend_sandbox.py +47 -0
- ghostlab-0.3.0/tests/test_configured_agent.py +383 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_hosts_runner.py +2 -2
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_jobs.py +49 -0
- ghostlab-0.3.0/tests/test_opencode_backend.py +286 -0
- ghostlab-0.3.0/tests/test_prompts.py +32 -0
- ghostlab-0.3.0/tests/test_sandbox.py +132 -0
- ghostlab-0.3.0/tests/test_sandbox_stdio.py +213 -0
- ghostlab-0.3.0/tests/test_skills.py +39 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_testrun.py +36 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_tool_capture.py +9 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_widgets_and_dashboard.py +5 -0
- ghostlab-0.2.1/CONTRIBUTING.md +0 -56
- ghostlab-0.2.1/docs/concepts.md +0 -56
- ghostlab-0.2.1/docs/getting-started.md +0 -126
- ghostlab-0.2.1/docs/ghostlab-vision-gap-and-roadmap.md +0 -963
- ghostlab-0.2.1/docs/index.md +0 -26
- ghostlab-0.2.1/rehearsal/jobs.py +0 -245
- ghostlab-0.2.1/rehearsal/runner_presets.py +0 -113
- {ghostlab-0.2.1 → ghostlab-0.3.0}/.gitignore +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/LICENSE +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/mcp-config.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/scenario.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/examples/target.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/__init__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/__main__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/ghostlab/cli.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/__main__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/__init__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/assertions.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/executor.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/live.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/protocol.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/renderer.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/apps_host/report.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/compare.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/contract.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/critique.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/logging.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_apps.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_client.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_config.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/mcp_targets.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/readiness.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/review.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/sampling.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/scorecard.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/setup_runtime.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/__init__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/db.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/hashing.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/ids.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/migrations/0001_initial.sql +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/redact.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/storage/repository.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/termcolor.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/types.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/rehearsal/ui/__init__.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/claude-process.example.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-aut.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-local-aut.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-cortex-local-session.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-process.example.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/codex-user-emulator.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/mock-aut.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/runners/mock-user.json +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_apps_host.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_apps_live.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_compare.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_config.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_contract.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_critique.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_dataset.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_evaluate.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_generate.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_inspect_lint.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_apps.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_client.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_mcp_targets.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_orchestrator.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_personas.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_plan.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_plan_generate.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_profile.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_readiness.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_review.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_runner_presets.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_sampling.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_scorecard.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_session_runner.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_setup_runtime.py +0 -0
- {ghostlab-0.2.1 → ghostlab-0.3.0}/tests/test_spec.py +0 -0
- {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.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: ghostlab
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
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:
|
|
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
|
|
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)
|
|
52
54
|
[](llms.txt)
|
|
53
55
|
|
|
54
|
-
**Test
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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** —
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
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
|
|
154
|
-
-
|
|
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
|
-
-
|
|
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
|
|
206
|
-
Claude Code
|
|
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
|
|
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
|
|
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
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
-
|
|
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):
|