feat(studio): web UI for raptor under packages/studio/ - #215
Conversation
A FastAPI + Jinja2 web UI that reads and writes raptor's project data,
triggers all pure-Python and Claude-backed command kinds via a SQLite
job queue with live SSE log streaming, and renders raptor's full
finding schema — final_status, verdict × impact, Stage E feasibility,
chain_breaks, exploitation_paths, CodeQL dataflow SVGs inline, OSS
forensics walkthrough.
Launch from the raptor repo root:
pip install -r requirements.txt
python3 raptor_studio.py # → http://127.0.0.1:8765
## Feature surface
Browsing
- Dashboard with cross-project KPIs (or welcome state when empty)
- Findings with raptor's full schema (final_status / verdict × impact
/ Stage E feasibility / chain_breaks / exploitation_paths / PoC)
- Per-run detail: kind-aware artifact summary, scan metrics, fuzzing
report, validation bundle counts, inline CodeQL dataflow SVGs,
OSS forensics walkthrough (evidence, hypothesis timeline, final
report — all markdown-rendered)
- Diff two runs by (file, line, normalized_vuln_type) identity
- Exploits / Patches / Reports / Activity browsers
- /personas global browser + /glossary with grouped concept cards
- Three-lane IA (source / binary / forensics) with type-adaptive
sidebar — irrelevant lanes collapse under "Other capabilities"
Triggering
- Create project (3 types, typed form with progressive disclosure)
- SQLite-backed job queue + subprocess worker
- Pure-Python kinds (scan, agentic, codeql, fuzz) → raptor_*.py
- Claude-backed kinds (understand, validate, oss-forensics,
crash-analysis) → bash -c "raptor project use <n> && claude -p '/…'"
- Live log streaming via SSE; cancel via SIGTERM to process group
- Every trigger form shows the Equivalent CLI for reproducibility
Configuration
- /settings edits ~/.config/raptor/models.json (4 role cards:
analysis / code / consensus / fallback)
- Env-var fallback status, RAPTOR_MAX_COST display
## Schema & round-trip
Projects created via the UI write raptor's exact 7-field schema
(version, name, target, output_dir, created, description, notes) at
~/.raptor/projects/<name>.json — indistinguishable from
`raptor project create`. Studio-only metadata (project type, optional
binary / corpus / focus / language / vendor_report_url) lives in a
sidecar at $STUDIO_DATA_DIR/project-extras/ so raptor's CLI ignores it.
Finding schema rendered verbatim from raptor's own output — no
reinterpretation. SARIF 2.1.0 fallback when no findings.json exists.
## Testing
python -m pytest packages/studio/tests/
# 161 passed, 1 skipped
17 test modules including test_worker_integration which actually
spawns subprocesses to exercise the queue + cancel paths.
## Architecture
packages/studio/
├── app.py # FastAPI, ~20 routes
├── config.py # env-driven paths
├── services/ # 14 read/write/classify modules
├── templates/ # 23 Jinja2 templates
├── static/ # pixel-art velociraptor avatar
├── tests/ # 17 modules (incl. live subprocess)
├── scripts/ # seed_demo.py, process_avatar.py
├── docs/
│ ├── PRD.md # product scope + invariants
│ ├── CHANGELOG.md # commit-by-commit narrative
│ └── UX_RECONCILIATION.md
└── fixtures/
Services layer is pure-Python, provider-agnostic, does not import
raptor's Python runtime except raptor_version.py which reads
RaptorConfig.VERSION directly.
## Non-goals (deliberate)
- Auth / multi-user — raptor is single-user by design
- Replacing the CLI — every UI action surfaces its Equivalent CLI so
power users can reproduce outside the browser
## Provenance
Developed in the open at https://github.com/yesnet0/raptor-studio over
27 commits. This PR squashes that history for reviewability; the
companion repo retains the full timeline and the test run that
generated the dashboard screenshots.
## Dependencies added to requirements.txt
fastapi>=0.110.0
uvicorn[standard]>=0.27.0
jinja2>=3.1.0
python-multipart>=0.0.9
markdown>=3.5
All pure-Python (uvicorn's C extensions are optional via httptools).
Changes to adapt content written for the companion repo to the in-tree context, and to pre-answer likely review questions. New: - packages/studio/docs/FAQ.md — pre-answers scope / architecture / security / integration / ops / future questions, with explicit mentions of why-not alternatives (Flask, Django, SPA, etc). - packages/studio/docs/ARCHITECTURE.md — one-page call-flow plus request lifecycles for create-project, browse-findings, trigger-run (pure-Python + Claude-backed), and state-location table. Rewritten: - packages/studio/docs/PRD.md — dropped "v0.0.1 pre-absorption" framing; now describes the in-tree context with the right relationships to raptor (packages/studio/, core.config.RaptorConfig.VERSION, etc.). Test count corrected to 160. - packages/studio/README.md — links to FAQ + ARCHITECTURE docs; test count to 160. - packages/studio/docs/UX_RECONCILIATION.md — preamble clarifying the doc dates from the companion-repo era and how to read it in-tree. - packages/studio/docs/CHANGELOG.md — added an entry describing the in-tree migration squashed in this PR. Code cleanup (drive-by): - Dropped the legacy `binary=` kwarg alias on create_project() and the ProjectExtras.binary property. No existing users to maintain on a fresh merge; cleaner diff for reviewers. - Removed the matching back-compat test (test_backcompat_reads_old_ binary_field). Tests: still 160 passing, 1 skipped.
The upstream absorption PR (gadievron/raptor#215) introduced two new documents (FAQ.md, ARCHITECTURE.md) written to pre-answer maintainer review questions and diagram the request lifecycles. Mirror both into the companion repo so anyone who lands here from the PR sees the same docs. - docs/FAQ.md — added with a top-banner noting it was originally written for the in-tree context; companion-repo equivalents noted where they differ (e.g. raptor_version.py regex-scrape vs direct import). - docs/ARCHITECTURE.md — added verbatim. - docs/PRD.md — top-banner linking to the open upstream PR; clarifies that the companion repo remains the standalone home regardless of the PR outcome. - README.md — upstream-PR banner at top; trimmed outdated test/ commit counts.
Both `core.project.project.PROJECTS_DIR` and `core.startup.PROJECTS_DIR` now fall back to `$RAPTOR_PROJECTS_DIR` before the default `~/.raptor/projects`. Defaults unchanged. Why: companion tooling (raptor-studio) and test harnesses need to point raptor at an alternate registry without monkey-patching module constants. Without this, studio's UI could display projects from an alternate `RAPTOR_PROJECTS_DIR`, but the subprocess-driven `raptor project use` would read from the hardcoded default and report "Project not found" — silent, confusing divergence between UI state and CLI state. Tests: new `test_env_projects_dir.py` covers both modules; existing 137 project tests + 12 startup tests still pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New server-side picker (GET /api/fs/list) + reusable `_fs_picker.html`
partial rendering a modal with breadcrumb navigation, shortcut pills
(Home / Projects / Downloads / Desktop / /tmp), and directory/file
selection. Any input tagged `data-fs-picker="dirs"` (or `"files"`)
automatically gets a 📂 Browse button injected beside it.
Wired into:
- /projects/new target input — mode switches source→dirs, binary→files,
button hidden for forensics (target is a URL)
- /projects/new corpus_dir / source_repo / output_dir — dirs
- /projects/{name}/{kind}/new target — dirs or files depending on
spec.target_arg
- trigger-form render_field macro — path-ish field names (corpus,
output_dir, binary, input_file, reproducer, map) get auto-picker
Why: typing an absolute path from memory is a consistent newcomer
friction point; the picker reveals the filesystem inline and fills the
field. Preserves the existing smart-name autofill: commit fires an
`input` event, which the existing listener picks up to set the name
from the chosen basename.
Single-user localhost assumption (documented in the endpoint comment
and raptor-studio's PRD) means no path-traversal restriction — just
normalization via Path.resolve().
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Same pass as raptor-studio main; see that repo's companion commit for the rationale. - Drop "on the roadmap" copy from stage page + project settings page - Project settings page now has an edit form for description/notes, writes back via new update_project_metadata() round-tripping the raptor project.json schema - next_action() takes project_kind — binary projects now suggest Fuzz, forensics suggest OSS forensics - "Validation bundle" card hidden on non-validate runs (checklist alone no longer qualifies — understand writes one too) - Pure-Python triggers now wrap argv with `raptor project use <project> && python3 ...` so artifacts land in the right output_dir regardless of the previous active project - Exploits / Patches / Reports / run-detail Report files / SARIF files link to the file-serve route; suffix whitelist expanded to cover exploit/patch source (.py/.c/.sh/.patch/.diff/…) - Activity page: run names link to run detail Tests: 160 passed, 1 skipped — no regressions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
I have tested this PR locally against the current repo state. The Studio work looks useful and the tests pass cleanly against the PR's declared base branch, but there are a few security issues I think we should fix before merging. Validation performed:
Security risks to resolve:
In short: functionally this is in good shape against |
|
Hey gents, checking in on this - Can I help with anything? |
|
Picking up on what @danielcuthbert said... want to tag-team the security fixes? |
Summary
A FastAPI + Jinja2 web UI that reads and writes raptor's project data, triggers all pure-Python and Claude-backed command kinds via a SQLite job queue with live SSE log streaming, and renders raptor's full finding schema inline.
Launch from the repo root:
Developed in the open at https://github.com/yesnet0/raptor-studio over 27 commits with screenshots, tests, and a full PRD / changelog. This PR squashes that history for reviewability; the companion repo keeps the full timeline.
Feature surface
Browsing
final_status/ verdict × impact / Stage E feasibility (protections,exploitation_paths,chain_breakstagged[source]/[binary],what_would_help) / PoC / Source-Sink-Flow proofdataflow_*.svgdiagrams, OSS-forensics walkthrough (evidence-source count, hypothesis timeline with confirmed/rejected badges, final forensic report — all rendered from markdown)/personasglobal browser (10 expert briefs fromtiers/personas/) +/glossaryexplaining schema termsTriggering
$STUDIO_DATA_DIR/jobs.db+ daemon-thread workerscan,agentic,codeql,fuzz→ spawnpython3 raptor_*.pyunderstand,validate,oss-forensics,crash-analysis→ wrap asbash -c "raptor project use <name> && claude -p '<slash-cmd>'"/api/jobs/{id}/stream)Configuration
/settingsedits~/.config/raptor/models.jsonin raptor's exact 4-role schemaANTHROPIC_API_KEY, etc.)RAPTOR_MAX_COSTdisplaySchema preservation
Projects created via the UI write raptor's 7-field
project.jsonschema exactly — indistinguishable fromraptor project create. Studio-only metadata (type,source_repo,focus,vendor_report_url,language,corpus_dir) lives in$STUDIO_DATA_DIR/project-extras/<name>.json. Raptor's CLI ignores the sidecar. A round-trip test importscore/project/schema.py::validate_projectand runs it against studio output.Finding schema rendered verbatim from raptor's output — no reinterpretation. SARIF 2.1.0 fallback when no
findings.jsonexists.Tests
17 test modules including
test_worker_integrationwhich actually spawns subprocesses to cover completed / failed / cancelled / missing-executable paths end-to-end (~8.5s total).Architecture
Services are provider-agnostic and do not import raptor's runtime except
services/raptor_version.pywhich importsRaptorConfig.VERSIONdirectly. Root launcherraptor_studio.pymirrors theraptor_agentic.py/raptor_codeql.py/raptor_fuzzing.pypattern —sys.pathbootstrap + argparse +uvicorn.run.Non-goals (deliberate)
New dependencies (requirements.txt)
All pure-Python (uvicorn's C extensions are optional via httptools).
Test plan
validate_project/,/personas,/glossary,/api/healthall 200