Architecture¶
RoboCI is organized around a simple local-first contract:
- Commands create evaluation runs.
- Runs write structured artifacts under
runs/<run_id>/. - Reports, regression checks, the FastAPI backend, and the dashboard read those artifacts.
The MVP uses file-based storage. This keeps CI usage simple and makes every run inspectable with ordinary tools.
System Diagram¶
Major Components¶
CLI¶
The CLI lives in roboci/cli/.
main.pydefines the Typer command surface.commands.pyadapts command-line inputs into core Python calls.
The CLI is intentionally thin. It should parse arguments, call domain logic, print concise status, and set exit codes.
Closed-loop Runner¶
The closed-loop runner lives in roboci/core/runner.py.
It does this for each scenario:
- Load and validate the scenario.
- Create a simulator.
- Reset simulator state.
- Ask the agent for an action.
- Step the simulator.
- Append a frame to episode JSONL.
- Stop on success, failure, or timeout.
- Compute metrics.
- Export replay artifacts.
- Detect failures.
- Collect run provenance.
- Write summary, provenance, and report artifacts.
Open-loop Runner¶
The open-loop runner lives in roboci/openloop/runner.py.
It does this for each sample:
- Load dataset metadata and samples.
- Attach ground-truth annotations.
- Call model prediction.
- Measure prediction latency.
- Compute per-sample metrics.
- Aggregate metrics.
- Evaluate open-loop gates.
- Collect model and dataset provenance.
- Write open-loop artifacts.
Storage¶
The storage layer lives in roboci/storage/.
artifacts.pycontains JSON and JSONL helpers.paths.pyresolves workspace-relative paths.run_store.pycreates and lists run directories. Run detail reads fullsummary.provenance, while run lists expose a compactprovenance_summaryto avoid shipping every source-file hash.
The most important design choice is that RunStore("runs") resolves runs/ from the current working directory or a parent workspace. This prevents the API from returning no runs when launched from frontend/.
ROBOCI_RUNS_DIR can point at a local path or mounted network share. roboci storage sync copies run artifacts to local/network paths, S3 via aws s3 sync, or GCS via gsutil -m rsync -r; the core API still reads a filesystem path so runs remain inspectable with ordinary tools.
API¶
The API lives in roboci/api/.
It is a read/write façade over local artifacts:
- Reads summaries, provenance, metrics, regression files, replays, scenarios, and failures.
- Updates failure tags, notes, lifecycle status, owner, fixed-in run, and regressed-in run fields.
- Appends status history in
failures.jsonwhen a failure moves through the debugging workflow. - Does not own core evaluation logic.
Frontend¶
The dashboard lives in frontend/.
It fetches from the FastAPI backend through frontend/lib/api.ts, then renders:
- Dashboard KPIs.
- Run lists and details.
- Replay and trajectory views.
- Regression Explorer, compare workbench, and run-level regression diffs.
- Failure triage surfaces.
Run Artifact Flow¶
Closed-loop run:
The dashboard run detail page also requests GET /runs/{run_id}/artifacts to build a local artifact tree. The API returns an index of known run files, but text preview is intentionally narrower: GET /runs/{run_id}/artifacts/read?path=... only reads allowlisted root artifacts (summary.json, metrics.json, regression.json, failures.json, config.yaml, and provenance.json). Other indexed files remain local-only for preview; POST /runs/{run_id}/artifacts/open?path=... can ask the local API process to launch only indexed artifacts with the host default app, so the dashboard does not become arbitrary filesystem access.
Open-loop run:
Design Principles¶
- Local-first: Runs are ordinary files, not remote records.
- Adapter-based: Simulators and agents are replaceable.
- Small interfaces:
SimulatorAdapter,Agent, andOpenLoopModelare intentionally minimal. - Artifact-driven UI: The dashboard reads the same files the CLI writes.
- CI-friendly: Commands use exit codes and write HTML plus PR-friendly markdown reports.