Skip to content
File

Blob: AGENTS.md

Markdown99 lines

AGENTS.md

Operating Rules

  • Product name: tessera, lowercase in code, comments, docs, and user-facing copy unless grammar requires otherwise.
  • Ask first: "Can we do more with less code?" Prefer the smallest correct change that preserves clarity, performance, and security.
  • If a local fix creates known fragility or a security-sensitive dead end, pay the structural cost now. Optional refactors should be proposed, not made by default.
  • Read before editing. For non-local changes, inspect the target file plus a caller, consumer, sibling module, or focused test.
  • Work from the live source tree. Docs and prior context are secondary when they drift.
  • Keep edits scoped. Multiple agents may be working in parallel, so never overwrite or revert unrelated changes.
  • Assume the dev server may already be running. Do not start npm run dev unless asked, clearly needed, or no relevant server is running.
  • Prefer explicit code over clever code. Reuse existing helpers, route patterns, schemas, UI primitives, and auth utilities before adding new ones.
  • Preserve the src/client/, src/worker/, generated-code, and migration boundaries.
  • Prefer the @/ alias for imports from src.
  • For current Cloudflare behavior, prefer official Cloudflare docs via cloudflare-docs MCP when available. For package signatures, read local .d.ts files first.

Source Of Truth

  • README.md: architecture and local quickstart.
  • OPERATOR.md: deployment, secrets, and production operation.
  • The live source tree is authoritative when docs drift.
  • docs/phase-1-design.md and docs/tessera-phase-1-design.md: historical security-sensitive design context for issuer, callbacks, cookies, signing keys, invites, and sub claims. Confirm endpoint paths, env vars, schema details, and generated output against current source before treating them as current.
  • src/worker/db/schema/: D1 schema source. drizzle/d1/ is generated by npm run db:generate.
  • src/worker/auth/cli-config.ts: Better Auth CLI source. src/worker/db/schema/auth.ts is generated by npm run auth:generate.
  • worker-configuration.d.ts, dist/, and .wrangler/ are generated outputs. Regenerate them; do not hand-edit them.

Project Map

tessera is a Cloudflare Workers OIDC provider with a React frontend.

  • Worker: src/worker/index.ts mounts Hono; auth/ configures Better Auth; api/ owns tessera routes; db/ owns Drizzle; middleware/ owns auth gates, origin checks, security headers, admin allowlisting, and rate limiting; services/ owns crypto, Turnstile, and URL helpers.
  • Client: src/client/app.tsx and main.tsx boot the React app; pages live in pages/, UI in components/, admin-specific components in components/admin/, hooks in hooks/, HTTP/auth/navigation helpers in lib/, and styles in styles/app.css.
  • Tests: worker and client Vitest specs in tests/worker/ and tests/client/, Playwright in tests/e2e/, local OIDC simulators in scripts/test-client/ and scripts/test-consent/.
  • Runtime config and generated output: wrangler.jsonc, drizzle/d1/, worker-configuration.d.ts, dist/, and .wrangler/.

Security And Runtime Invariants

  • tessera is invite-only. Do not introduce open signup.
  • Stable opaque sub claims are core product behavior. Account linking, issuer URLs, callback paths, cookie behavior, signing keys, token claims, and token lifetimes are security-sensitive.
  • D1 is authoritative for users, accounts, sessions, OAuth clients, signing keys, invites, roles, and bans. Better Auth state stays in D1.
  • /api/*, /.well-known/*, and /healthz must run through the Worker before static asset handling. OAuth endpoints live under /api/auth/oauth2/*; JWKS is /api/auth/jwks.
  • OIDC discovery must advertise endpoints and JWKS paths that the Worker actually serves.
  • Turnstile-gated flows fail closed on missing config, missing tokens, and failed verification.
  • Sign-in, social sign-in, invite acceptance, and /api/auth/* remain rate-limited through RL_AUTH / RL_API; public JWKS and auth utility endpoints stay explicitly exempt.
  • Admin routes use requireAdmin; protected user routes use requireUser.
  • Keep OAuth client secret creation, rotation, and revocation fail-closed.
  • Do not log secrets, bearer tokens, OAuth client secrets, session cookies, password material, invite tokens, signing keys, or raw Turnstile responses.

Change Guidance

  • Worker routes belong in src/worker/api/ and are mounted from src/worker/index.ts.
  • Keep reusable worker logic in helpers or middleware rather than route handlers.
  • Reuse src/worker/http.ts for HTTP errors/responses, src/worker/config.ts for base URL and issuer logic, src/worker/services/turnstile.ts for Turnstile, and src/worker/middleware/rate-limit.ts for rate limiting.
  • If request or response shapes change, update the worker route, matching client helper in src/client/lib/, and affected tests together.
  • Frontend changes should reuse src/client/components/ui/ and preserve accessible semantics, keyboard behavior, focus states, labels, and contrast.
  • Treat TurnstileWidget and /api/config as the authoritative client Turnstile path.
  • Update src/worker/db/schema/ before generating D1 migrations. Do not hand-edit drizzle/d1/ unless explicitly asked.
  • Cross-check README.md, OPERATOR.md, current source, and focused tests before shipping security-sensitive auth or OIDC changes. Treat phase design docs as context, not current implementation authority.

Commands

  • npm run dev: start Vite + Cloudflare Worker dev.
  • npm run build: production bundle in dist/.
  • npm run typecheck: generate Worker types and run TypeScript checks.
  • npm test: run Vitest with the Cloudflare worker pool.
  • npm run test:e2e: run Playwright e2e coverage.
  • npm run test:client: run the local OIDC RP simulator.
  • npm run test:consent: run the local consent-flow simulator.
  • npm run db:generate: generate D1 migrations.
  • npm run db:migrate: apply remote D1 migrations.
  • npm run db:migrate:local: apply local D1 migrations.
  • npm run db:seed-initial-user / npm run db:seed-initial-user:local: seed the bootstrap invite.
  • npm run auth:generate: regenerate Better Auth schema.
  • npm run format:check / npm run format: check or apply Prettier formatting.

Validation

  • Run npm run typecheck for most code changes.
  • Prefer focused tests/worker/*.test.ts for worker, auth, invite, OIDC, Turnstile, rate-limit, and service behavior changes.
  • Do not run the full npm test suite by default. It includes Argon2id coverage and is intentionally slow; run it only when broad cross-file worker regression coverage is clearly needed or explicitly requested.
  • Run npm run build when changing route wiring, bundling, static assets, wrangler.jsonc, or runtime registration.
  • Run npm run test:e2e or a focused Playwright spec for browser-visible auth, invite, account, admin, or consent flows.
  • Run npm run test:client after OIDC discovery, authorize/token, PKCE, client registration, or claim-shape changes.
  • Run npm run test:consent after consent-page or consent-route changes.
  • If an appropriate check cannot be run, state why.

Primary References

  • Worker entry: src/worker/index.ts
  • Auth setup: src/worker/auth/index.ts, src/worker/auth/cli-config.ts
  • API handlers: src/worker/api/
  • Auth middleware: src/worker/middleware/auth.ts
  • D1 schema: src/worker/db/schema/
  • Issuer/base URL: src/worker/config.ts
  • Turnstile/rate limits: src/worker/services/turnstile.ts, src/worker/middleware/rate-limit.ts
  • Client app: src/client/app.tsx, src/client/main.tsx
  • Client helpers and UI: src/client/lib/, src/client/components/ui/
  • Tests: tests/worker/, tests/client/, tests/e2e/, scripts/test-client/, scripts/test-consent/