Loopworks is an agentic software factory portal for planning, executing, validating, and improving software delivery loops. GitHub Issues are the source of truth for roadmap, planning, milestones, decisions, and execution state. Vercel is the application visibility surface for previews, deployments, and build status.
- Next.js App Router, TypeScript, Bun
- ShadCN/UI and Tailwind CSS
- Auth.js GitHub SSO
- Postgres and Drizzle
- Biome, Vitest, Playwright, Storybook
- Markdownlint for Markdown documentation
- Pino structured logging
- Eve, Vercel Workflows, Vercel Sandbox, Vercel AI Gateway integration points
bun install
bun run devFor local UI work without GitHub OAuth credentials:
bun run dev:fixtureTo inspect a signed GitHub issue webhook fixture without sending it:
bun run github:webhook-fixture -- --kind agent-ready
bun run github:webhook-fixture -- --kind spike-agent-readyThe fixture defaults to http://127.0.0.1:3000/api/github/webhooks, uses
GITHUB_WEBHOOK_SECRET, and only posts to the local webhook route when
--send is provided. Sending is restricted to loopback URLs.
Copy .env.example to .env.local for local development. The fixture server only needs the defaults from .env.example; real GitHub SSO, webhooks, database persistence, and Vercel deployment visibility use these variables:
AUTH_SECRETAUTH_GITHUB_IDAUTH_GITHUB_SECRETLOOPWORKS_AUTH_BYPASSLOOPWORKS_ALLOWED_GITHUB_USERSLOOPWORKS_ALLOWED_GITHUB_ORGSLOOPWORKS_AGENT_READY_LOOP_ENABLEDLOOPWORKS_DEVELOPMENT_LOOP_ENABLEDLOOPWORKS_RESEARCH_LOOP_ENABLEDLOOPWORKS_PORTAL_DATA_MODELOOPWORKS_EVE_TEST_RECEIPT_SECRETLOOPWORKS_EVE_TEST_WRITER_FIXTURE_MODELOG_LEVELDATABASE_URLOTEL_EXPORTER_OTLP_PROTOCOLOTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_TRACES_HEADERSOTEL_EXPORTER_OTLP_METRICS_HEADERSOTEL_SERVICE_NAMEOTEL_RESOURCE_ATTRIBUTESGITHUB_APP_IDGITHUB_APP_PRIVATE_KEYGITHUB_WEBHOOK_SECRETVERCEL_ACCESS_TOKENVERCEL_TEAM_IDVERCEL_TEAM_SLUG
OpenTelemetry is registered through @vercel/otel. Local development is safe
by default: leave the OTLP exporter variables blank unless you intentionally want
to ship telemetry. For the ADR 0012 Axiom preview proof, use OTLP/HTTP protobuf,
send traces to an Axiom Events dataset with
OTEL_EXPORTER_OTLP_TRACES_HEADERS, and send metrics to a dedicated Axiom
Metrics dataset with OTEL_EXPORTER_OTLP_METRICS_HEADERS. Pino stdout logs stay
attached to Vercel runtime logs with the active traceId; direct Pino-to-Axiom
log shipping is tracked separately by issue #65.
bun run format:check
bun run lint
bun run agent-docs:check
bun run markdownlint
bun run typecheck
bun run test
bun run storybook:build
bun run test:e2ebun run test:e2e owns a fresh development server with explicit non-production
fixture mode. It deterministically verifies the Fixture fallback path and
does not attach to an existing server. LOOPWORKS_PORTAL_DATA_MODE=fixtures
is ignored in production, where database failures continue to fail closed.
The seeded Postgres browser lane is separate. It requires a local
loopworks_e2e database owned by the loopworks role:
createdb --host 127.0.0.1 --username loopworks loopworks_e2e
DATABASE_URL="postgres://loopworks:loopworks@127.0.0.1:5432/loopworks_e2e" \
bun run test:e2e:seededThe seeded command refuses production runtimes, non-Postgres URLs,
non-loopback hosts, and database names other than loopworks_e2e before it
runs migrations. It then runs migrations, resets only the fixed-id demo rows,
and requires Live database browser evidence. Migration or seed failures name
the failed stage; confirm Postgres is running and that the local role and
database exist.
The aggregate command is:
bun run validateLoopworks uses pre-k through uvx prek.
bun run precommit:install
bun run precommit:runThe pre-commit hook runs bun run precommit, which mirrors CI validation: Biome format check, Biome lint, agent docs sync, Markdownlint, TypeScript, Vitest, Storybook build, and Playwright.
- Agent workflow:
AGENTS.md - Claude Code shim:
CLAUDE.mdimportsAGENTS.md; runbun run agent-docs:syncafter changing agent guides - Contributing guide:
CONTRIBUTING.MD - Product requirements:
docs/prd.md - Architecture:
docs/architecture.md - ADR index:
docs/adr/README.md - Loop manifest:
docs/loop-manifest.md - Design-system planning:
docs/design-system-planning.md - Observability:
docs/observability.md - Personas and test scenarios:
docs/personas-and-test-scenarios.md - MVP security review:
docs/security-review.md
After the database bootstrap (bun run db:migrate), seed a demo dataset
covering repos, loops, runs, run steps, artifacts, approvals, and Vercel
deployment states in every status. DATABASE_URL must explicitly identify a
local Postgres database:
bun run db:seedSeeding is idempotent (upsert by fixed id), so running it again does not duplicate rows. To clear the fixed-id demo rows and reseed from scratch:
bun run db:seed:resetReset only deletes the exact rows this script owns, not the whole table, so any other data in those tables is left untouched.
Add -- --dry-run to either command to print the planned row counts without
writing. Per
ADR 0007, both
commands refuse to run when DATABASE_URL is missing or malformed, when
NODE_ENV or VERCEL_ENV is production, or when the URL is not Postgres on
a loopback host (localhost/127.0.0.1/::1) — Loopworks demo data must never
write into a database that isn't explicitly and obviously local.