Tight dev loop¶
One-command full-stack dev with backend hot-reload + frontend HMR.
Brings up: compose stores + migrations (viastart-compose.sh) → demo seed → gateway with
uvicorn --reload (backend code hot-reloads) → frontend vite (HMR) pointed at the gateway →
tails both logs. Ctrl-C stops the gateway + frontend (the compose stores keep running).
- URLs: gateway
http://localhost:8088(:8000is taken by another local app), frontendhttp://localhost:5174. - Options:
--fe-mocks(run the SPA on MSW mocks instead of live),--no-fe,--no-seed,--gateway-port N. The frontend's gateway base comes fromweb/brain-builder/.env.development.local(whichdev.shwrites) + inline env — note Vite ranks.env.developmentabove.env.local, so the.localfor the current mode (.env.development.local) is what reliably overrides it. ./scripts/dev-down.shstops the app processes;--storesalso tears down compose.
What auto-runs / how to iterate¶
- Backend code change → the gateway hot-reloads (no restart). (Once Phase 6 adds app
Dockerfiles,
dev.shwould build/restart that container instead.) - Frontend change → vite HMR reflects it immediately.
- Schema change (models/migrations) → run
alembic upgrade head(or./scripts/start-compose.shre-runs it), or wipe + reseed:./scripts/reset-db.sh # alembic downgrade base -> upgrade head -> bb seed-demo ./scripts/reset-db.sh --purge # also clears data/git + data/lightrag (corpus + file lens)reset-db.shis local-guarded (refuses unless DATABASE_URL is localhost;--forceto override) and prompts unless-y.
Seeding¶
bb seed-demo (idempotent) provisions the demo: the four accounts (see docs/api/gateway.md) + the
Meridian tenant end-to-end (brain → approved corpus → certified/published version → one pending
change set). Safe to re-run; each step skips if already present.
Fast checks¶
./scripts/check.sh # ruff + mypy + unit pytest + contract-check
./scripts/check.sh --all # + frontend typecheck/lint + alembic migration-drift check (needs local stack)
./scripts/contract-check.sh # FE↔gateway drift only: every SPA /v1 path must have a gateway route
contract-check parses every /v1/... path the SPA references and asserts the gateway exposes a
matching route (catches the missing/renamed-endpoint drift, e.g. the /coverage gap found during
the joint integration). Allowlist intentional exceptions in scripts/_contract_check.py.
Migrations: change a model → migrate¶
Default workflow: whenever an ORM model changes, create + apply the Alembic migration as part
of that change (never leave the schema un-migrated). Migrations are Postgres-targeted (some use
::json default casts) — they don't run on SQLite; unit tests use Base.metadata.create_all, so a
migration round-trip is validated on Postgres (or via reset-db / a scratch DB), not the unit suite.
./scripts/check.sh --all runs alembic check against the local DB to flag a model that drifted
from its migrations.