Dev Environment Lifecycle (IaC)
Declarative dev environment management that ensures apps are always running, seeded, and testable β both on-demand and during warp-drive autonomous coding.
Overview
Every project declares its dev environment in dev.json at the project root. The dev-up command reads this manifest and orchestrates the full lifecycle: server management, migrations, seed data, and test user provisioning. Itβs idempotent, composable, and integrates directly into warp-drive.
Quick Start
# 1. Copy the template to your project
cp ~/.claude/templates/dev.json ./dev.json
# 2. Customize for your project (edit server command, port, auth adapter, etc.)
vi dev.json
# 3. Set up seed data
mkdir -p seed/
cp ~/.claude/templates/seed/users.json ./seed/
cp ~/.claude/templates/seed/001-base-data.sql ./seed/
cp ~/.claude/templates/seed/002-sample-entities.sql ./seed/
# Customize the SQL for your schema
# 4. Run it
~/.claude/scripts/dev-lifecycle/dev-up.sh . --verbosedev.json Manifest
{
"server": {
"command": "npm run dev", // Command to start the dev server
"port": 5173, // Port the server listens on
"health": "/api/health", // Health check endpoint path
"restart": "on-failure", // Restart strategy: "on-failure" | "always" | "never"
"env": {} // Additional environment variables
},
"migrations": {
"command": "npm run migrate:dev", // Migration command (null to skip)
"auto_run": true // Run migrations automatically
},
"seed": {
"directory": "seed/", // Path to seed scripts
"runner": "node", // Script runner: "node" | "npx tsx" | custom
"order": "alphabetical", // Execution order
"d1_database": "db" // D1 database name for SQL seeds (if applicable)
},
"auth": {
"adapter": "d1", // Auth adapter: "d1" | "sqlite" | "supabase" | "script" | "custom"
"users_file": "seed/users.json", // Path to test user definitions
"table": "users", // Database table name for users
"provision_command": null // Custom provisioning command (for "custom" adapter)
},
"access": {
"localhost": "http://localhost:5173", // Local access URL
"farm_01": null // Remote dev server URL (if accessible)
}
}Scripts
All scripts live in ~/.claude/scripts/dev-lifecycle/ and follow the IaC prime directive: standalone, idempotent, parameterized, with --help.
| Script | Purpose | Usage |
|---|---|---|
dev-up.sh | Full lifecycle orchestrator | dev-up.sh [DIR] [--check|--verbose|--skip-*] |
health-check.sh | Lightweight health probe | health-check.sh [DIR] [--port N --path /path] |
provision-users.sh | Test user provisioning | provision-users.sh [DIR] [--adapter TYPE] |
check-seed-coverage.sh | Seed data coverage check | check-seed-coverage.sh [DIR] |
dev-up.sh
The main orchestrator. Runs the full lifecycle:
- Server: Check health β start if not running β kill & restart if unhealthy
- Migrations: Run migration command if configured and
auto_runis true - Seed data: Execute all scripts in
seed/directory alphabetically - Test users: Provision users via the configured auth adapter
- Report: Output JSON status and access URL
Flags:
--checkβ Health check only (no start/seed/users). Fast gate for warp-drive.--skip-seedβ Skip seed data scripts--skip-usersβ Skip user provisioning--skip-serverβ Skip server management (run seed/users only)--verboseβ Show detailed step-by-step output
health-check.sh
Lightweight standalone health probe. Returns JSON:
{"status": "healthy", "port": 5173, "url": "http://localhost:5173"}provision-users.sh
Reads seed/users.json and provisions users via pluggable adapters:
| Adapter | How it works |
|---|---|
d1 | Generates SQL, executes via wrangler d1 execute --local |
sqlite | Direct sqlite3 INSERT OR REPLACE |
supabase | Delegates to supabase db reset --local |
script | Runs project-local seed/provision-users.sh |
custom | Runs auth.provision_command from dev.json |
check-seed-coverage.sh
Advisory check: warns if migration/schema files changed but no seed files were modified. Used by warp-drive during the coding phase to remind about additive seed data.
Seed Data Convention
See ~/.claude/templates/seed/README.md for full details.
Key rules:
- Files run in alphabetical order. Use numeric prefixes:
001-base.sql,002-entities.sql - Every script MUST be idempotent (INSERT OR REPLACE, UPSERT, etc.)
- Seed entities in ALL lifecycle states your domain defines β not just fresh/active records
- New features add their own seed file in the same commit (e.g.,
010-feature-invoicing.sql)
Standardized Test Users
Defined in seed/users.json. The superuser credentials are consistent across all projects:
| Role | Password | Purpose | |
|---|---|---|---|
| superuser | admin@test.local | admin123 | Full access, consistent across projects |
| editor | editor@test.local | editor123 | Read/write/publish access |
| viewer | viewer@test.local | viewer123 | Read-only access |
| guest | guest@test.local | guest123 | Minimal/no access |
Projects should customize the role-specific users to match their permission model while keeping the superuser unchanged.
Warp-Drive Integration
When a project has dev.json, warp-drive automatically manages the dev environment:
| Phase | Action |
|---|---|
| prerequisites | Full dev-up --verbose β start everything before coding begins |
| coding | check-seed-coverage β advisory reminder if schema changes lack seed data |
| chunk_complete | dev-up --check β fast health gate before next chunk |
| chunk_complete (recovery) | Full dev-up --verbose if health check fails |
Dev health failure is treated as a blockable event. If recovery fails after 2 attempts, warp-drive escalates per its error protocol.
Projects without dev.json skip all dev lifecycle steps β the integration is opt-in.
Adopting in a Project
- Copy
~/.claude/templates/dev.jsonto your project root - Customize the server command, port, and health endpoint
- Create
seed/directory with your initial seed scripts - Copy
~/.claude/templates/seed/users.jsonand customize roles - Set the auth adapter in dev.json to match your stack
- Run
dev-up . --verboseto verify
The template at ~/.claude/templates/dev.json has sensible defaults for SvelteKit + Cloudflare Workers projects.
Docs Site Lifecycle (#153)
Every BoB-provisioned project can host a Quartz 4 docs site that reads its own docs/, README.md, and CLAUDE.md. The lifecycle is orthogonal to the dev environment lifecycle but follows the same declarative pattern.
| Sub-command | Script | Purpose |
|---|---|---|
/docs-site init | ~/.claude/scripts/docs-site/init.sh | Scaffold .docs-site/ (Quartz 4 install, default quartz.config.ts, docs-site.json if missing). Idempotent on re-run. |
/docs-site build | ~/.claude/scripts/docs-site/build.sh | Sync content + run Quartz build. Output at .docs-site/public/. |
/docs-site dev | ~/.claude/scripts/docs-site/dev.sh | Sync content + Quartz dev server with hot reload (default port 8080). |
/docs-site deploy | ~/.claude/scripts/docs-site/deploy.sh | Build, then publish to the configured target (cloudflare-pages, static, custom). |
/docs-site clean | ~/.claude/scripts/docs-site/clean.sh | Drop build artifacts (preserves config + Quartz install). --hard also drops the Quartz install. |
Per-project config (docs-site.json at project root):
{
"title": "Bodmail Docs",
"description": "Documentation for the Bodmail email platform",
"base_url": "https://docs.bodmail.app",
"sources": ["docs/", "README.md", "CLAUDE.md"],
"exclude": ["docs/archive/**", "docs/audits/**"],
"deploy": { "target": "cloudflare-pages", "project": "bodmail-docs" }
}Adopting in a project:
cd /path/to/project && /docs-site initβ scaffolds.docs-site/and a defaultdocs-site.json.- Edit
docs-site.jsonβ set the title, base URL, and deploy target. /docs-site devβ preview at http://localhost:8080./docs-site deploywhen ready.
Wikilinks: Quartzβs Obsidian-flavored markdown plugin handles [[page]] links, including across the unified content tree (everything under .docs-site/content/ is one namespace, regardless of which source it came from).
Universal portability: the scripts read --root, $PROJECT_ROOT, or cwd. Smoke-tested in /tmp/docs-site-test (a non-BoB tree) β init.sh --no-clone scaffolds docs-site.json + quartz.config.ts + .gitignore additions correctly.
Auto-deploy on doc changes (#155). A GitHub Actions workflow at .github/workflows/docs-deploy.yml rebuilds and publishes the site whenever a published doc source changes (docs/**, README.md, CLAUDE.md, bob-identity.md, docs-site.json, the docs-site scripts, or the Quartz config). On master push it deploys to production; on PRs it deploys a preview and posts the URL back as a sticky comment.
The pipeline is:
checkout β cache .docs-site/.quartz/node_modules
β docs-site init (idempotent)
β make docs-check (high-severity drift fails the build, blocks deploy)
β docs-site build
β wrangler pages deploy β bigbrain-docs (production OR pr-NN preview)
β comment preview URL on the PR
Required repo configuration:
- Secret
CLOUDFLARE_API_TOKENβ Cloudflare API token withPages:Editscope. - Secret
CLOUDFLARE_ACCOUNT_IDβ the Cloudflare account UUID. - Variable
DOCS_SITE_DEPLOY_ENABLED=trueβ feature flag that gates the wrangler steps. Until itβs set, the workflow still builds and runs the drift gate (catching breakage), but skips the actual deploy. See #187 for the one-time Cloudflare Pages connection step.
NPM script aliases live in the root package.json so users can run npm run docs:build / docs:dev / docs:deploy from anywhere in the repo.
Drift report on the site (#156)
Every /doc-audit run writes two artifacts to docs/audits/:
doc-audit-YYYY-MM-DD.{md,json}β date-stamped historical recordlatest.{md,json}β canonical aliases the docs site reads
The site (when built via /docs-site build) consumes docs/audits/latest.md for a βDocs last verifiedβ badge on the landing page and an βAuditsβ entry in the nav. latest.json is exposed as a downstream API endpoint at /audits/latest.json. See README.md for the canonical-path contract and history convention.
The Quartz nav + landing-badge component wiring lands as a follow-up to this issue β the data plumbing (latest aliases + history) is in place.