Phase 0, task 0.9c — the CLI, third piece of the vertical slice (after 0.9a provenance #80, 0.9b persistence #83).
Scripted ensembles must not require the browser (ADR-002). The existing workflow is entirely scripted and has to stay viable, so the CLI is not a convenience wrapper over the API — it is a first-class path to the same code.
Scope
plume-studio run <config.yaml> [--out DIR] — resolve, persist, submit, wait, record artefacts and summary, print the run's identity.
plume-studio sweep <sweep.yaml> [--plan] — expand axes into runs. --plan prints N and submits nothing, mirroring the existing runners' plan verb (run_ensemble.py:174).
plume-studio status <run-id> — read persisted job state. Worth having precisely because it proves the state outlives the process that submitted it (ADR-007).
python -m studio.cli.run <input.json> <outdir> already exists from 0.6 as the subprocess entry point and stays as-is.
Constraints
- Verbs stay recognisable to anyone who has used
run_ensemble.py (plan | one | run).
- The database is migrated on startup, idempotently — a fresh clone must not need a manual
alembic upgrade.
- A stale config is refused before anything is written.
- No test hooks: if the CLI needs a seam for testing, it must be a parameter that a real deployment would also use.
Base branch: studio/dev.
Phase 0, task 0.9c — the CLI, third piece of the vertical slice (after 0.9a provenance #80, 0.9b persistence #83).
Scripted ensembles must not require the browser (ADR-002). The existing workflow is entirely scripted and has to stay viable, so the CLI is not a convenience wrapper over the API — it is a first-class path to the same code.
Scope
plume-studio run <config.yaml> [--out DIR]— resolve, persist, submit, wait, record artefacts and summary, print the run's identity.plume-studio sweep <sweep.yaml> [--plan]— expand axes into runs.--planprints N and submits nothing, mirroring the existing runners'planverb (run_ensemble.py:174).plume-studio status <run-id>— read persisted job state. Worth having precisely because it proves the state outlives the process that submitted it (ADR-007).python -m studio.cli.run <input.json> <outdir>already exists from 0.6 as the subprocess entry point and stays as-is.Constraints
run_ensemble.py(plan | one | run).alembic upgrade.Base branch:
studio/dev.