File
Blob: AGENTS.md
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 devunless 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 fromsrc. - For current Cloudflare behavior, prefer official Cloudflare docs via
cloudflare-docsMCP when available. For package signatures, read local.d.tsfiles 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.mdanddocs/tessera-phase-1-design.md: historical security-sensitive design context for issuer, callbacks, cookies, signing keys, invites, andsubclaims. 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 bynpm run db:generate.src/worker/auth/cli-config.ts: Better Auth CLI source.src/worker/db/schema/auth.tsis generated bynpm 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.tsmounts 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.tsxandmain.tsxboot the React app; pages live inpages/, UI incomponents/, admin-specific components incomponents/admin/, hooks inhooks/, HTTP/auth/navigation helpers inlib/, and styles instyles/app.css. - Tests: worker and client Vitest specs in
tests/worker/andtests/client/, Playwright intests/e2e/, local OIDC simulators inscripts/test-client/andscripts/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
subclaims 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/healthzmust 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 throughRL_AUTH/RL_API; public JWKS and auth utility endpoints stay explicitly exempt. - Admin routes use
requireAdmin; protected user routes userequireUser. - 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 fromsrc/worker/index.ts. - Keep reusable worker logic in helpers or middleware rather than route handlers.
- Reuse
src/worker/http.tsfor HTTP errors/responses,src/worker/config.tsfor base URL and issuer logic,src/worker/services/turnstile.tsfor Turnstile, andsrc/worker/middleware/rate-limit.tsfor 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
TurnstileWidgetand/api/configas the authoritative client Turnstile path. - Update
src/worker/db/schema/before generating D1 migrations. Do not hand-editdrizzle/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 indist/.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 typecheckfor most code changes. - Prefer focused
tests/worker/*.test.tsfor worker, auth, invite, OIDC, Turnstile, rate-limit, and service behavior changes. - Do not run the full
npm testsuite 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 buildwhen changing route wiring, bundling, static assets,wrangler.jsonc, or runtime registration. - Run
npm run test:e2eor a focused Playwright spec for browser-visible auth, invite, account, admin, or consent flows. - Run
npm run test:clientafter OIDC discovery, authorize/token, PKCE, client registration, or claim-shape changes. - Run
npm run test:consentafter 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/