You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Proposed shape: bun create next-app → ./dashboard at monorepo root — a live job monitor, "like inspect view but fuzzing-shaped" (CPU/mem, exec/s, coverage & crash curves). Captuing the design discussion here.
TL;DR — this is a data problem wearing a UI costume
The stack choice is fine; the blocker is that we don't emit the live, fuzzing-shaped telemetry a hot-reload view needs. Fix the data feed first, the frontend is then a thin reader.
What's missing on the Python side
No live/incremental stream.save_manifest only fires at run-level transitions (mark_run_started/completed/failed), so polling the manifest gives "12 of 36 grid cells done," not the in-progress curves that are the point of this issue. Mid-run FuzzingState lives in Inspect's TaskState.store and never hits disk.
No CPU/mem data at all. Today FuzzingStats captures execs_per_sec, total_execs, corpus_size, crashes_found, plus the oom_killed/timed_out flags — and they're point-in-time per cycle, not a time-series. The "CPU stats" ambition isn't backed by collected data; it needs docker stats sampling on the sandbox container inside the campaign loop.
Define a JSON/JSONL "dashboard feed" contract that Python writes and TS reads, decoupled from both Inspect and logfire. The runner + campaign loop append one event per cycle; the dashboard is a thin reader (Next route handler tails the file server-side, pushes via SSE — or dumb 1s polling, since presentation is explicitly out of scope). This survives #138.
{ "run_id", "ts", "cycle",
"execs_per_sec", "total_execs", "corpus_size", "unique_crashes",
"line_coverage_pct", "branch_coverage_pct",
"cpu_pct", "rss_bytes", "oom_killed", "timed_out",
"tokens", "fuzz_seconds" } // last two feed the #135 efficiency metrics
The real fork (decide before scaffolding): vs. Logfire
#138 adopts Logfire, which is itself a live job monitor (timeline, token usage, span drill-down). So:
Logfire-native — push fuzzing metrics as span attributes, build Logfire dashboards. Near-zero infra, but hosted/external and awkward for fuzzing-domain views (coverage-over-time, CASR crash clusters, swarm marginal-crash curve).
Bespoke ./dashboard — full control of fuzzing-shaped views, runs locally/offline against the results dir, but we build/maintain it.
Recommendation: both, split by job. Logfire owns agent-trace + token drill-down (link out, don't reimplement). ./dashboard owns what Logfire can't show well: exec/s & coverage curves, crash dedup / CASR clusters, the #135 efficiency metrics (vulns_per_fuzz_hour, vulns_per_mtok_equiv), CPU/mem, and SwarmResult.marginal_crash_curve.
Fit & footguns
./dashboard parallels scaffold/ and comms/ cleanly. It subsumes the Streamlit viz/ (slated for overhaul) and stays distinct from comms/site — which is exactly the "build-up-front website" this issue says not to do. Clean split: dashboard = live research, comms/site = presentation.
Polyglot monorepo: the existing .github/workflows/ci.yml is scaffold-scoped (ruff/ty/pytest) and won't touch the TS app — add a separate dashboard job for lint/build.
Thinnest de-risking slice
Emit events.jsonl from the runner per cycle.
Next route handler tails it + SSE.
One page: run grid + per-run exec/s & crashes sparkline.
CPU/mem is a fast-follow once docker stats sampling lands. This sequence proves the live-data pipe before any UI investment.
Open decisions
Logfire-native vs bespoke vs both (recommend both, split by job)
Lock the events.jsonl schema + the runner/campaign emission points
Revised recommendation: Logfire is the primary research dashboard. Build bespoke UI only for the residue Logfire genuinely can't express, and keep that residue as small as possible:
Likely-still-bespoke: crash dedup / CASR cluster views, SwarmResult.marginal_crash_curve (a derived shape, not a raw time series).
This also collapses the live-data plumbing: no events.jsonl + SSE tail to build/maintain for anything Logfire already ingests. We get hot-reload-ish live views for free from Logfire's live tail.
On viz/
Maintainer says they don't care about viz/. So drop the "overhaul Streamlit viz" framing entirely — Logfire replaces viz/, it doesn't get rebuilt. comms/site stays as the separate presentation layer (the "build-up-front website" this issue says not to do for research).
Updated open decisions
Logfire-native vs bespoke vs both → Logfire-native primary, bespoke only for CASR-cluster / marginal-crash views
Activity
quinn-dougherty commentedon Jun 11, 2026
Design notes: a hot-reload research dashboard
Proposed shape:
bun create next-app→./dashboardat monorepo root — a live job monitor, "likeinspect viewbut fuzzing-shaped" (CPU/mem, exec/s, coverage & crash curves). Captuing the design discussion here.TL;DR — this is a data problem wearing a UI costume
The stack choice is fine; the blocker is that we don't emit the live, fuzzing-shaped telemetry a hot-reload view needs. Fix the data feed first, the frontend is then a thin reader.
What's missing on the Python side
save_manifestonly fires at run-level transitions (mark_run_started/completed/failed), so polling the manifest gives "12 of 36 grid cells done," not the in-progress curves that are the point of this issue. Mid-runFuzzingStatelives in Inspect'sTaskState.storeand never hits disk.FuzzingStatscapturesexecs_per_sec,total_execs,corpus_size,crashes_found, plus theoom_killed/timed_outflags — and they're point-in-time per cycle, not a time-series. The "CPU stats" ambition isn't backed by collected data; it needsdocker statssampling on the sandbox container inside the campaign loop..eval. The Inspect ZIP log format is internal, and the pydantic-ai/logfire migration (Instrument Logfire on top of Inspect-AI (observability) #138) may delete it. A dashboard that parses.evalbreaks on that migration.The load-bearing decision: a project-owned feed
Define a JSON/JSONL "dashboard feed" contract that Python writes and TS reads, decoupled from both Inspect and logfire. The runner + campaign loop append one event per cycle; the dashboard is a thin reader (Next route handler tails the file server-side, pushes via SSE — or dumb 1s polling, since presentation is explicitly out of scope). This survives #138.
Strawman event (per cycle, append-only
results/<exp>/events.jsonl):The real fork (decide before scaffolding): vs. Logfire
#138 adopts Logfire, which is itself a live job monitor (timeline, token usage, span drill-down). So:
./dashboard— full control of fuzzing-shaped views, runs locally/offline against the results dir, but we build/maintain it.Recommendation: both, split by job. Logfire owns agent-trace + token drill-down (link out, don't reimplement).
./dashboardowns what Logfire can't show well: exec/s & coverage curves, crash dedup / CASR clusters, the #135 efficiency metrics (vulns_per_fuzz_hour,vulns_per_mtok_equiv), CPU/mem, andSwarmResult.marginal_crash_curve.Fit & footguns
./dashboardparallelsscaffold/andcomms/cleanly. It subsumes the Streamlitviz/(slated for overhaul) and stays distinct fromcomms/site— which is exactly the "build-up-front website" this issue says not to do. Clean split:dashboard= live research,comms/site= presentation..github/workflows/ci.ymlis scaffold-scoped (ruff/ty/pytest) and won't touch the TS app — add a separatedashboardjob for lint/build.Thinnest de-risking slice
events.jsonlfrom the runner per cycle.CPU/mem is a fast-follow once
docker statssampling lands. This sequence proves the live-data pipe before any UI investment.Open decisions
events.jsonlschema + the runner/campaign emission points./dashboardreplacesviz/Bridge Inspect sample lifecycle into Logfire spans (#138, route 2)
quinn-dougherty commentedon Jun 16, 2026
Updated stance: lean on Logfire heavily; shrink the bespoke surface
Since the "both, split by job" comment above, the ground has shifted in Logfire's favor:
eval samplespan)../dashboardwas being proposed to own.Revised recommendation: Logfire is the primary research dashboard. Build bespoke UI only for the residue Logfire genuinely can't express, and keep that residue as small as possible:
SwarmResult.marginal_crash_curve(a derived shape, not a raw time series).vulns_per_fuzz_hour/vulns_per_mtok_equiv(develop metric for vulns per mtok and/or vulns per CPU-time (or vulns per some combination of mtok and time) #135), error rates — all become Logfire queries/charts off structured attributes + the sample-span attributes from Instrument Logfire on top of Inspect-AI (observability) #138.This also collapses the live-data plumbing: no
events.jsonl+ SSE tail to build/maintain for anything Logfire already ingests. We get hot-reload-ish live views for free from Logfire's live tail.On
viz/Maintainer says they don't care about
viz/. So drop the "overhaul Streamlit viz" framing entirely — Logfire replacesviz/, it doesn't get rebuilt.comms/sitestays as the separate presentation layer (the "build-up-front website" this issue says not to do for research).Updated open decisions
Logfire-native vs bespoke vs both→ Logfire-native primary, bespoke only for CASR-cluster / marginal-crash viewsviz/→ deprecate/remove rather than overhaulHarden logging facade for structured kwargs + structure fuzzing hot p…
Emit per-cycle fuzzing metrics to Logfire (#147)
Emit `model`/run identity so Logfire owns the research curves (#114)
Add importable Logfire dashboard JSON for the #114 research views