Preset
AI Product
Streaming chat, typed output and tool calling, on auth, Postgres and billing.
What this preset installs
7
Agents
28
Skills
30
Rules
7
Hooks
75
Solution docs
5
MCP servers
Counted from the manifests for this exact selection. The repo wires hooks for Claude Code only. Codex and Cursor get the rules and the skills.
Why this one
Who it is for
For a product whose core loop is a model call. The Vercel AI SDK runs on Anthropic (or OpenAI). You get a streaming chat route and a chat page inside the signed-in app, plus Zod-checked structured output. A tool-calling scaffold ships with one read-only example tool.
Underneath is a working SaaS: sign-in with passwords, magic links and OAuth, a dashboard and settings, Polar billing with monthly, yearly and lifetime prices on a public /pricing page, and an admin panel with real users, bans, impersonation and an audit log. Better Auth, Drizzle on Neon Postgres, Resend, PostHog and Sentry.
Usage metering, background jobs, rate limits and tracing are left out on purpose. Solution docs cover when to add metering, jobs and tracing. Rules on src/lib/ai/** keep model calls on the server, streamed and schema-checked. /add-tool and /eval-prompt keep new work consistent.
The Compound Engineering plugin is enabled in .claude/settings.json and pinned to a release tag.
Highlights
- Vercel AI SDK on Anthropic: a streaming chat page in the signed-in app, and a Zod schema on every structured call
- Tool-calling scaffold with one read-only example tool and a tool registry
- Rules on
src/lib/ai/**: server-only model calls, streaming, no untrusted text in system prompts - Polar checkout for monthly, yearly and lifetime prices, from a public
/pricingpage - Better Auth sign-in, plus an admin panel with bans, impersonation and an audit log
- Solution docs on tool retries, streaming edge cases, metering, background jobs and tracing
The exact selection
- Stack
- Next.js on Vercel
- Package manager
- bun
- Design system
- Midnight
- Mode
- solo
- Agent targets
- claude
- Admin panel
- included
- AI bundle
- anthropic: streaming chat, structured output, tool calling
Batteries
9 batteries, each with its own rules
Path-scoped rules, at least one skill and at least five solution docs. That is the bar for getting into the registry at all.
ORM
Drizzle ORM
Typed SQL in TypeScript, no engine binary, and migrations you read as plain SQL.
Next.js with Drizzle ORM
Database
Neon
Serverless Postgres you can branch like git, with a driver built for cold starts.
Next.js with Neon
Auth
Better Auth
Own your users table. Passwords, magic links, Google, GitHub and Microsoft, all in your database.
Next.js with Better Auth
Payments
Polar
Merchant of record for developers. Polar sells to your customer, so tax is its job.
Next.js with Polar
Email
Resend
Transactional email with React Email templates you review in a pull request.
Next.js with Resend
Error tracking
Sentry
Stack traces with the release and route attached, scrubbed of user data first.
Next.js with Sentry
Analytics
PostHog
Product analytics, session replay, feature flags and experiments behind one key.
Next.js with PostHog
AI
AI bundle
Streaming chat, Zod-checked output and tool calling on the Vercel AI SDK.
Next.js with AI bundle
Admin panel
Admin panel
Users, bans, impersonation and an audit log. Your code, any auth provider.
Next.js with Admin panel
The output
Read every file before you download it
The real generated repo for AI Product: 560 files, content hash 36c2ae554827. The same selection always produces the same bytes.
.claude/74 files
agents/7 files
- db-inspector.md
- designer.md
- documentarian.md
- pr-reviewer.md
- product-analyst.md
- security-auditor.md
- system-manager.md
hooks/8 files
- README.md
- auto-lint.ts
- block-destructive.ts
- enforce-doc-meta.ts
- enforce-typecheck.ts
- env-leak-detector-write.ts
- env-leak-detector.ts
- guard-neon-sql.ts
rules/30 files
- admin-access.md
- admin-mutations.md
- ai-prompt-safety.md
- ai-server-boundary.md
- ai-structured-output.md
- ai-tools.md
- app-shell.md
- auth-server-boundary.md
- billing-core.md
- code-style.md
- deployment.md
- drizzle-migrations.md
- drizzle-schema.md
- email-sending-discipline.md
- event-naming.md
- git.md
- identify-timing.md
- landing-and-legal.md
- neon-connections.md
- neon-migrations.md
- polar-billing-adapter.md
- polar-webhook-integrity.md
- roles-are-server-side.md
- security.md
- sentry-capture.md
- sentry-no-pii.md
- server-truth-and-pii.md
- testing.md
- tokens-only.md
- ui-kit.md
skills/28 files
add-admin-action/1 file
- SKILL.md
add-admin-page/1 file
- SKILL.md
add-app-page/1 file
- SKILL.md
add-email-template/1 file
- SKILL.md
add-event/1 file
- SKILL.md
add-oauth-provider/1 file
- SKILL.md
add-product/1 file
- SKILL.md
add-table/1 file
- SKILL.md
add-tool/1 file
- SKILL.md
ask-product/1 file
- SKILL.md
db-branch/1 file
- SKILL.md
deploy-to-vercel/1 file
- SKILL.md
edit-pricing/1 file
- SKILL.md
eval-prompt/1 file
- SKILL.md
help/1 file
- SKILL.md
landing-copy/1 file
- SKILL.md
migrate/1 file
- SKILL.md
migrate-on-neon/1 file
- SKILL.md
new-component/1 file
- SKILL.md
preview-and-test-email/1 file
- SKILL.md
protect-route/1 file
- SKILL.md
qa-feature/1 file
- SKILL.md
scrub-pii/1 file
- SKILL.md
security-audit/1 file
- SKILL.md
test-webhook/1 file
- SKILL.md
triage-errors/1 file
- SKILL.md
verify/1 file
- SKILL.md
write-spec/1 file
- SKILL.md
- settings.json
.vscode/2 files
- extensions.json
- settings.json
docs/79 files
plans/2 files
- README.md
- TEMPLATE.md
solutions/76 files
admin-panel/8 files
- adding-an-audit-log.md
- bans-and-session-revocation.md
- empty-states-that-are-not-sad.md
- first-admin-without-a-backdoor.md
- impersonating-users-safely.md
- paginating-a-users-table.md
- role-checks-that-survive-a-refactor.md
- route-group-vs-path-segment.md
ai-bundle/6 files
- prompt-injection-through-user-content.md
- streaming-edge-cases.md
- tool-retries-and-partial-failures.md
- when-to-add-usage-metering.md
- when-to-move-ai-work-to-a-background-job.md
- when-tracing-pays-for-itself.md
better-auth/10 files
- account-linking-and-email-verification.md
- better-auth-on-the-edge.md
- csrf-and-cookie-flags.md
- guarding-the-auth-api-itself.md
- magic-link-tokens-and-scanners.md
- migrating-an-existing-user-table.md
- oauth-callback-url-mismatches.md
- password-reset-tokens.md
- role-modelling-for-the-admin-panel.md
- session-invalidation-and-logged-out-on-deploy.md
drizzle/5 files
- adding-a-column-with-a-backfill.md
- generate-vs-push.md
- relations-vs-joins.md
- transactions-in-serverless.md
- typing-partial-selects.md
midnight/4 files
- a-chart-palette-that-survives-dark-mode.md
- class-and-system-dark-mode-that-both-work.md
- pasting-shadcn-components-into-your-own-token-names.md
- tailwind-v4-dark-mode-does-nothing.md
neon/6 files
- branch-per-preview-deployment.md
- cold-start-latency.md
- connection-exhaustion-in-serverless.md
- local-postgres-without-a-neon-account.md
- migrations-on-vercel.md
- pooled-vs-unpooled-connections.md
nextjs-vercel/15 files
- auth-checks-in-an-app-shell.md
- compound-engineering-loop.md
- env-vars-on-vercel-without-leaking-them.md
- guard-hooks-and-how-to-extend-them.md
- llms-txt-for-a-saas-site.md
- one-time-purchases-vs-subscriptions.md
- pricing-page-without-a-database.md
- privacy-policy-that-lists-your-real-vendors.md
- rate-limiting-checkout-in-postgres.md
- refunds-disputes-and-entitlements.md
- regenerate-from-config-and-diff.md
- rules-skills-agents-when-to-use-each.md
- sample-testimonials-without-the-ftc-risk.md
- sidebar-state-without-a-flash.md
- writing-path-scoped-rules-agents-follow.md
polar/6 files
- merchant-of-record-vs-stripe.md
- migrate-a-stripe-catalogue-to-polar.md
- one-time-and-subscription-products-on-polar.md
- refunds-and-disputes-on-polar.md
- sandbox-to-production-checklist.md
- webhook-idempotency.md
posthog/5 files
- ad-blocker-reverse-proxy.md
- event-naming-that-survives.md
- feature-flags-without-flicker.md
- identify-race-conditions.md
- server-vs-client-events.md
resend/5 files
- batching-and-rate-limits.md
- bounces-complaints-and-webhooks.md
- domain-verification-spf-dkim-dmarc.md
- magic-link-deliverability.md
- previewing-templates-locally.md
sentry/5 files
- grouping-noisy-errors-with-fingerprints.md
- scrubbing-pii-before-it-leaves-the-process.md
- source-maps-on-vercel.md
- telling-a-real-incident-from-a-bot.md
- trace-sample-rates-that-do-not-bankrupt-you.md
- README.md
- onboard.md
scripts/17 files
admin/2 files
- grant.ts
- load-env.ts
auth/2 files
- make-admin.ts
- seed.ts
billing/4 files
- prune-events.ts
- reconcile.ts
- sync-plans.ts
- test-webhook.ts
email/2 files
- render-samples.ts
- send-test.ts
- ai-eval.ts
- ai-models.ts
- db-branch.ts
- neon-local-proxy.ts
- sentry-issues.ts
- verify-hooks.ts
- verify.ts
src/341 files
app/55 files
(admin)/13 files
admin/12 files
audit/2 files
- loading.tsx
- page.tsx
settings/2 files
- loading.tsx
- page.tsx
users/4 files
[id]/2 files
- loading.tsx
- page.tsx
- loading.tsx
- page.tsx
- error.tsx
- loading.tsx
- not-found.tsx
- page.tsx
- layout.tsx
(app)/15 files
billing/4 files
checkout/1 file
- route.ts
- error.tsx
- loading.tsx
- page.tsx
chat/1 file
- page.tsx
dashboard/1 file
- page.tsx
settings/5 files
profile/1 file
- page.tsx
security/1 file
- page.tsx
- layout.tsx
- loading.tsx
- page.tsx
- error.tsx
- layout.tsx
- loading.tsx
- not-found.tsx
(better-auth)/6 files
banned/1 file
- page.tsx
forgot-password/1 file
- page.tsx
reset-password/1 file
- page.tsx
sign-in/1 file
- page.tsx
sign-up/1 file
- page.tsx
- layout.tsx
(legal)/2 files
privacy/1 file
- page.tsx
terms/1 file
- page.tsx
api/6 files
agent/1 file
- route.ts
auth/1 file
[...all]/1 file
- route.ts
chat/1 file
- route.ts
health/1 file
- route.ts
webhooks/2 files
polar/1 file
- route.ts
resend/1 file
- route.ts
ingest/1 file
[...path]/1 file
- route.ts
llms.txt/1 file
- route.ts
pricing/1 file
- page.tsx
- error.tsx
- fonts.ts
- global-error.tsx
- globals.css
- layout.tsx
- loading.tsx
- not-found.tsx
- page.tsx
- robots.ts
- sitemap.ts
components/137 files
admin/25 files
- admin-header.tsx
- admin-shell.tsx
- admin-shortcut-card.tsx
- admin-sidebar.tsx
- audit-details.tsx
- audit-feed.tsx
- audit-filters.tsx
- audit-table.tsx
- ban-dialog.tsx
- billing-summary.tsx
- confirm-action-dialog.tsx
- grant-admin-form.tsx
- impersonation-banner.tsx
- revoke-session-button.tsx
- sessions-table.tsx
- stat-card.tsx
- stop-impersonating-button.tsx
- use-admin-action.ts
- use-provider-sign-out.ts
- user-actions.tsx
- user-badges.tsx
- user-identity.tsx
- users-filters.tsx
- users-pagination.tsx
- users-table.tsx
ai/1 file
- chat.tsx
app/10 files
- account-card.tsx
- app-header.tsx
- app-shell.tsx
- app-sidebar.tsx
- dashboard-card.tsx
- empty-state.tsx
- page-header.tsx
- settings-nav.tsx
- user-avatar.tsx
- user-menu.tsx
auth/22 files
settings/6 files
- connected-accounts-card.tsx
- email-card.tsx
- password-card.tsx
- profile-card.tsx
- reauthenticate-alert.tsx
- sessions-card.tsx
- account-settings.tsx
- auth-card.tsx
- auth-setup-notice.tsx
- check-inbox.tsx
- focus-first-error.ts
- forgot-password-form.tsx
- header-actions.tsx
- magic-link-form.tsx
- oauth-buttons.tsx
- password-input.tsx
- provider-icons.tsx
- reset-password-form.tsx
- session-provider.tsx
- sign-in-form.tsx
- sign-out-button.tsx
- sign-up-form.tsx
billing/12 files
- billing-notices.tsx
- checkout-pending.tsx
- current-plan-card.tsx
- plan-card.tsx
- plan-status.tsx
- plan-summary-card.tsx
- portal-button.tsx
- pricing-faq.tsx
- pricing-notice.tsx
- pricing-preview.tsx
- pricing-table.tsx
- purchase-history.tsx
dashboard/5 files
- card-action.tsx
- chart-area-interactive.tsx
- data-table.tsx
- data.json
- section-cards.tsx
marketing/17 files
- brand.tsx
- cta-band.tsx
- faq.tsx
- feature-grid.tsx
- hero.tsx
- json-ld.tsx
- legal-document.tsx
- logo-cloud.tsx
- product-preview.tsx
- sample-badge.tsx
- section-heading.tsx
- showcase-visuals.tsx
- showcase.tsx
- smart-link.tsx
- social-icons.tsx
- steps.tsx
- testimonials.tsx
observability/1 file
- sentry-identity.tsx
site/6 files
- auth-frame.tsx
- chrome.tsx
- footer.tsx
- header.tsx
- mobile-nav.tsx
- nav-link.tsx
theme/2 files
- theme-provider.tsx
- theme-toggle.tsx
ui/36 files
- accordion.tsx
- alert-dialog.tsx
- alert.tsx
- avatar.tsx
- badge.tsx
- breadcrumb.tsx
- button.tsx
- card.tsx
- chart.tsx
- checkbox.tsx
- collapsible.tsx
- dialog.tsx
- drawer.tsx
- dropdown-menu.tsx
- field.tsx
- input.tsx
- kbd.tsx
- label.tsx
- pagination.tsx
- popover.tsx
- progress.tsx
- radio-group.tsx
- select.tsx
- separator.tsx
- sheet.tsx
- sidebar.tsx
- skeleton.tsx
- spinner.tsx
- switch.tsx
- table.tsx
- tabs.tsx
- textarea.tsx
- toaster.tsx
- toggle-group.tsx
- toggle.tsx
- tooltip.tsx
db/17 files
- README.md
- audit.ts
- billing-schema.ts
- client.ts
- connection-url.ts
- direct-url.ts
- driver.ts
- drizzle.ts
- email-schema.ts
- health.ts
- index.ts
- load-env.ts
- migrate.ts
- neon-local.ts
- schema.ts
- tables.ts
- verify.ts
hooks/1 file
- use-mobile.ts
lib/128 files
admin/15 files
- actions.ts
- audit-store.ts
- audit.ts
- contract.ts
- cursor.ts
- format.test.ts
- format.ts
- policy.test.ts
- policy.ts
- provider.ts
- query.test.ts
- query.ts
- types.ts
- user-store.ts
- users.ts
ai/16 files
evals/2 files
- index.ts
- support-triage.ts
tools/2 files
- index.ts
- search-knowledge-base.ts
- access.ts
- agent.ts
- eval.ts
- http.ts
- knowledge-base.ts
- messages.ts
- models.ts
- prompt.ts
- provider.ts
- schemas.ts
- structured.ts
- untrusted.ts
analytics/5 files
- events.ts
- identify.ts
- posthog-client.ts
- posthog-server.ts
- provider.tsx
auth/23 files
- action-limit.test.ts
- action-limit.ts
- actions.ts
- adapter.ts
- auth.ts
- client.ts
- endpoint-guard.test.ts
- endpoint-guard.ts
- errors.ts
- guards.test.ts
- list-sessions.test.ts
- list-sessions.ts
- policy.ts
- providers.test.ts
- providers.ts
- roles.ts
- schema.ts
- schemas.ts
- secret.ts
- session.ts
- setup.ts
- user-agent.test.ts
- user-agent.ts
billing/33 files
- actions.ts
- catalog.test.ts
- catalog.ts
- checkout.ts
- entitlement.test.ts
- entitlement.ts
- entitlements.ts
- errors.ts
- format.ts
- index.ts
- origin.ts
- overview.ts
- polar-objects.test.ts
- polar-objects.ts
- polar-webhooks.test.ts
- polar-webhooks.ts
- polar.ts
- price-refs.ts
- provider.ts
- purchase-sql.ts
- rate-limit-rules.test.ts
- rate-limit-rules.ts
- rate-limit-sql.ts
- rate-limit.test.ts
- rate-limit.ts
- receipt.ts
- report.ts
- sign-up-url.ts
- store.ts
- types.ts
- user.ts
- webhook.test.ts
- webhook.ts
email/15 files
templates/6 files
- magic-link.tsx
- receipt.tsx
- reset-password.tsx
- theme.ts
- verify-email.tsx
- welcome.tsx
- address.ts
- index.ts
- observability.ts
- outbox.ts
- resend.ts
- retry.ts
- store.ts
- suppression.ts
- tags.ts
observability/2 files
- scrub.ts
- sentry.ts
- app-shell.test.ts
- app-shell.ts
- client-ip.test.ts
- client-ip.ts
- cn.test.ts
- cn.ts
- cx.ts
- design.ts
- env.ts
- llms.test.ts
- llms.ts
- nav.test.ts
- nav.ts
- pricing.ts
- routes.ts
- site.test.ts
- site.ts
- validate.ts
- verify.ts
- instrumentation-client.ts
- instrumentation.ts
- proxy.ts
tests/28 files
e2e/14 files
- admin.spec.ts
- app-shell.spec.ts
- auth.setup.ts
- auth.spec.ts
- auth.ts
- billing-webhook.spec.ts
- checkout.spec.ts
- fixtures.ts
- impersonation-lock.spec.ts
- landing.spec.ts
- legal.spec.ts
- outbox.ts
- pricing.spec.ts
- users.ts
unit/13 files
- ai-access.test.ts
- ai-chat-route.test.ts
- ai-eval.test.ts
- ai-messages.test.ts
- ai-mock-model.ts
- ai-models.test.ts
- ai-structured.test.ts
- ai-tools.test.ts
- ai-untrusted.test.ts
- email-outbox.test.ts
- email.test.ts
- env.test.ts
- scrub.test.ts
- smoke.spec.ts
- .env.example
- .gitignore
- .mcp.json
- CLAUDE.md
- DESIGN.md
- README.md
- agentic.config.json
- biome.jsonc
- components.json
- drizzle.config.ts
- next.config.ts
- package.json
- playwright.config.ts
- postcss.config.mjs
- sentry.edge.config.ts
- sentry.server.config.ts
- tsconfig.json
- vercel.json
- vitest.config.ts
The three files that do the work
# my-app
Generated by [Agentic Boilerplate](https://github.com/agentic-studio/agentic-boilerplate) from [Agentic Studio](https://theagentic.studio). Same `agentic.config.json`, same repo: regenerate and diff any time.
- **Stack:** Next.js on Vercel (`nextjs-vercel`)
- **Batteries:** Drizzle ORM (`drizzle`), Neon (`neon`), Better Auth (`better-auth`), Polar (`polar`), Resend (`resend`), Sentry (`sentry`), PostHog (`posthog`), AI bundle (`ai-bundle`), Admin panel (`admin-panel`)
- **Design:** Midnight (`midnight`). See [DESIGN.md](DESIGN.md).
- **Package manager:** bun
- **Mode:** solo
- **Agent targets:** claude
## Read this first
On a fresh clone, read [docs/onboard.md](docs/onboard.md) before running or
editing anything. It lists every environment variable, where to get it, and
the order to set the services up.
```sh
bun install
cp .env.example .env.local
bun run verify
bun run dev
```
## How this repo is set up for agents
- `.claude/rules/`: 30 rules. 4 load every session, 26 load when you read a file they cover.
- `.claude/agents/`: 7 subagents, listed below.
- `.claude/skills/`: 28 skills, listed below.
- `.claude/hooks/`: 7 guard hooks, wired in `.claude/settings.json` for Claude Code.
- `.mcp.json`: 5 MCP servers (`better-auth`, `neon`, `polar`, `posthog`, `sentry`). Setup is in [docs/onboard.md](docs/onboard.md).
- `docs/solutions/`: 75 solved problems. Read the relevant one before re-solving anything.
- `docs/plans/`: one plan per unit of work.
Run `bun run verify:hooks` to prove the guards still block what they claim to block.
Do not edit `.claude/settings.json` by hand: the `system-manager` agent owns it.
## Workflow
The Compound Engineering plugin adds the loop: `/ce-brainstorm`, `/ce-plan`, `/ce-work`, `/ce-code-review`, `/ce-compound`.
`.claude/settings.json` enables it once you trust this folder. If the commands are missing, run `/plugin install compound-engineering@compound-engineering-plugin`.
## Rules
Loaded every session:
- [Code style and file conventions](.claude/rules/code-style.md)
- [Git and change hygiene](.claude/rules/git.md)
- [Security rules](.claude/rules/security.md)
- [No personal data in breadcrumbs, tags or extra](.claude/rules/sentry-no-pii.md)
Loaded when you read a file they cover:
| Rule | Applies to |
|---|---|
| [Admin pages check the role themselves and read data on the server](.claude/rules/admin-access.md) | `src/app/(admin)/**`, `src/components/admin/**`, `src/lib/admin/actions.ts`, `src/app/api/admin/**` |
| [Admin writes go through the provider port, and every one is audited](.claude/rules/admin-mutations.md) | `src/lib/admin/**`, `src/components/admin/**`, `scripts/admin/**` |
| [Never interpolate untrusted text into a system prompt](.claude/rules/ai-prompt-safety.md) | `src/lib/ai/**`, `src/app/api/**` |
| [Model calls stay on the server, and they stream](.claude/rules/ai-server-boundary.md) | `src/lib/ai/**`, `src/app/api/chat/**`, `src/app/api/agent/**`, `src/components/ai/**`, `vercel.json` |
| [Every structured call carries a Zod schema](.claude/rules/ai-structured-output.md) | `src/lib/ai/**`, `src/app/api/**` |
| [Every tool validates its own input](.claude/rules/ai-tools.md) | `src/lib/ai/tools/**`, `src/lib/ai/agent.ts`, `src/app/api/agent/**` |
| [Pages in the signed-in app](.claude/rules/app-shell.md) | `src/app/(app)/**`, `src/components/app/**`, `src/components/ui/sidebar.tsx`, `src/lib/app-shell.ts`, `src/lib/nav.ts` |
| [The auth server boundary and sign-in methods](.claude/rules/auth-server-boundary.md) | `src/lib/auth/**`, `src/app/api/auth/**`, `src/app/(better-auth)/**`, `src/components/auth/**` |
| [Billing is one shared layer with one provider adapter](.claude/rules/billing-core.md) | `src/lib/pricing.ts`, `src/lib/billing/**`, `src/app/pricing/**`, `src/app/(app)/billing/**`, `src/components/billing/**` |
| [Deployment rules](.claude/rules/deployment.md) | `next.config.ts`, `vercel.json`, `package.json`, `src/proxy.ts`, `src/app/**/route.ts`, `.env.example` |
| [Every schema change ships with its generated migration](.claude/rules/drizzle-migrations.md) | `src/db/**`, `drizzle/**`, `drizzle.config.ts` |
| [Schema and query conventions for Drizzle](.claude/rules/drizzle-schema.md) | `src/db/**` |
| [Every email goes through sendEmail, from a verified domain, with a reply-to](.claude/rules/email-sending-discipline.md) | `src/lib/email/**`, `src/app/api/webhooks/resend/**`, `src/lib/auth/**`, `src/lib/billing/**` |
| [Events are declared in the catalogue, named object_verb, past tense](.claude/rules/event-naming.md) | `src/lib/analytics/**`, `src/app/**`, `src/components/**` |
| [Identify before the first event that matters, reset on sign-out](.claude/rules/identify-timing.md) | `src/lib/analytics/**`, `src/app/**`, `src/components/**` |
| [Landing page, legal pages and llms.txt](.claude/rules/landing-and-legal.md) | `src/lib/site.ts`, `src/lib/llms.ts`, `src/app/page.tsx`, `src/app/(legal)/**`, `src/app/llms.txt/**`, `src/components/marketing/**`, `src/components/site/**` |
| [One connection surface, and the right driver for the job](.claude/rules/neon-connections.md) | `src/db/**`, `src/app/api/**` |
| [Schema changes go through ORM migration files on the direct URL](.claude/rules/neon-migrations.md) | `src/db/**` |
| [Polar translates, the shared billing core writes the store](.claude/rules/polar-billing-adapter.md) | `src/lib/pricing.ts`, `src/lib/billing/**`, `scripts/billing/**` |
| [Verify every Polar webhook, keep every handler idempotent](.claude/rules/polar-webhook-integrity.md) | `src/app/api/webhooks/polar/**`, `src/lib/billing/provider.ts`, `src/lib/billing/polar-webhooks.ts`, `src/lib/billing/webhook.ts` |
| [Roles are decided on the server, every time](.claude/rules/roles-are-server-side.md) | `src/app/**`, `src/components/**`, `src/lib/auth/**` |
| [Every captured exception carries a stable fingerprint hint](.claude/rules/sentry-capture.md) | `src/**`, `sentry.server.config.ts`, `sentry.edge.config.ts` |
| [Server events for anything a client can lie about, and never PII in properties](.claude/rules/server-truth-and-pii.md) | `src/lib/analytics/**`, `src/app/**`, `src/components/**` |
| [Testing rules](.claude/rules/testing.md) | `tests/**`, `src/**/*.test.ts`, `src/**/*.test.tsx` |
| [Midnight: tokens only, and both modes every time](.claude/rules/tokens-only.md) | `src/components/**`, `src/app/**` |
| [Build UI from the component kit](.claude/rules/ui-kit.md) | `src/components/**`, `src/app/**` |
## Skills
| Skill | Use it for |
|---|---|
| `/add-admin-action` | Add an admin action (verify an email, reset a plan, delete an account) as a checked, validated, audited server action with a confirm dialog. |
| `/add-admin-page` | Add a page to /admin with the role check, a sidebar entry, loading and empty states, and data read through the admin ports. |
| `/add-app-page` | Add a page to the signed-in app (sidebar entry, session check, loading state), or a new tab under /settings. |
| `/add-email-template` | Add a React Email template, preview it, wire it into a send, and check it renders and lands in a real inbox. |
| `/add-event` | Add a product event end to end: catalogue entry, the question it answers, the capture call on the correct side of the network, and a check that it arrives. |
| `/add-oauth-provider` | Turn on Google, GitHub or Microsoft sign-in (env keys only), or add another OAuth provider to the list in src/lib/auth/providers.ts. |
| `/add-product` | Add or change a plan or price on Polar (monthly, yearly or one-time lifetime). Edit src/lib/pricing.ts, create the Polar product, wire its env var, and prove checkout and the webhook end to end. |
| `/add-table` | Add a table to the Drizzle schema, generate and apply its migration, and wire the typed queries for it. |
| `/add-tool` | Add a tool the model can call (schema, execute, registry entry, surface and a test) without widening what a stranger's sentence can reach. |
| `/ask-product` | Answer a question about user behaviour from this repo's event catalogue and the PostHog project, with the caveats that make the number usable. |
| `/db-branch` | Create, use, reset and delete Neon database branches, for a feature branch, a preview deploy, a migration rehearsal or a point-in-time investigation. |
| `/deploy-to-vercel` | Ship my-app to Vercel: local gates, environment variables per scope, preview verification, promotion and rollback. |
| `/edit-pricing` | Add, change or remove a plan or a price (monthly, yearly or one-time lifetime) and wire it to the payment provider. |
| `/eval-prompt` | Change a prompt, a model or a schema safely. Build the eval suite first, measure the baseline, change one thing, and compare pass rates. |
| `/help` | Explain the agentic system in this repo (rules, skills, agents, hooks, solution docs and the CE loop) and where to go for help beyond it. |
| `/landing-copy` | Rewrite the landing page, the metadata and the legal details for the real product from a short brief, by editing src/lib/site.ts only. |
| `/migrate` | Generate, review and apply Drizzle migrations safely, including backfills, destructive changes and the deploy step. |
| `/migrate-on-neon` | Run a schema migration against Neon safely, on the direct URL, rehearsed on a branch first, with a recovery path when it fails halfway. |
| `/new-component` | Add a component to the Midnight kit. Prefer pasting from shadcn/ui, fix the two bridge classes, keep it token-only and verify it in both light and dark. |
| `/preview-and-test-email` | Diagnose an email problem (not sending, landing in spam, rendering wrong) in the order that finds the cause fastest. |
| `/protect-route` | Put an authentication or role check on a page, a route handler, a server action or a whole route group, at the right layer, without a redirect loop. |
| `/qa-feature` | Exercise a feature end to end (happy path, unhappy paths, auth boundaries, refresh and mobile) before anyone calls it done. |
| `/scrub-pii` | Audit what this app actually sends to Sentry, extend the scrubbing layer for a new field or shape, and respond when something sensitive has already been sent. |
| `/security-audit` | Run the standing security pass through the security-auditor agent (secrets, auth boundaries, injection, dependencies and deploy config) and turn findings into fixes. |
| `/test-webhook` | Exercise the Polar webhook endpoint locally. Forward real sandbox events with the Polar CLI, or sign a one-time order yourself; buy both kinds of price, refund one, prove replays are no-ops, and debug signature failures. |
| `/triage-errors` | Work the Sentry issue list: rank by users affected, separate regressions from background noise, find the deploy that caused it, and fix or suppress with a reason. |
| `/verify` | Prove the repo is actually configured: every required env var present, every configured service reachable, and the guard hooks still blocking what they claim to block. |
| `/write-spec` | Turn a loose request into a written spec (problem, scope, behaviour, acceptance criteria) that /ce-plan can consume without guessing. |
## Subagents
| Agent | Use it for |
|---|---|
| `db-inspector` | Read-only Neon Postgres inspector. Explains schema, data shape and query plans. Runs SELECT and EXPLAIN only, and refuses every statement that writes or changes schema. |
| `designer` | Owns the Midnight design system and its shadcn bridge. The only agent allowed to introduce a new visual pattern or a new token. Refuses to ship a raw colour or a single-mode change. |
| `documentarian` | Keeps README, CLAUDE.md, DESIGN.md, docs/onboard.md and docs/solutions/ true to the code. Writes solution docs from work that just landed. |
| `pr-reviewer` | Reviews a diff against this repo's rules before it becomes a PR. Convention-aware, blocking on correctness and security, advisory on taste. |
| `product-analyst` | Read-only product analyst. Answers questions about user behaviour from the event catalogue and the PostHog project, and says plainly when the instrumentation cannot answer them. |
| `security-auditor` | Audits the repo or a diff for leaked secrets, broken auth boundaries, injection, unsafe dependencies and unsafe deploy configuration. |
| `system-manager` | Maintains the .claude agentic layer itself: rules, skills, agents, hooks, settings. Adds a rule when a correction repeats. |
## Credit
Generated by [Agentic Boilerplate](https://github.com/agentic-studio/agentic-boilerplate) from [Agentic Studio](https://theagentic.studio).
- [AI Mechanic](https://theagentic.studio/ai-mechanic): Fix a vibe-coded repo, then install this system into it.
- [Claude Engineering System](https://theagentic.studio/claude-engineering-system): The same agentic layer, installed into your existing codebase.
- [AI Product Sprint](https://theagentic.studio/ai-product-sprint): We build the MVP on top of a repo like this one.
---
paths:
- src/app/(admin)/**
- src/components/admin/**
- src/lib/admin/actions.ts
- src/app/api/admin/**
---
# Admin pages check the role themselves and read data on the server
## Three checks, each for a different question
| Where | Call | What it stops |
|---|---|---|
| `src/app/(admin)/layout.tsx` | `requireRole("admin", returnTo)` | A non-admin ever seeing the shell |
| Every `page.tsx` | `requireRole("admin", "/admin/<path>")` | A stale layout: layouts do not re-render on client navigation |
| Every server action | `authorise()` in `src/lib/admin/actions.ts` | Anyone with curl: an action is a public POST endpoint |
```tsx
export default async function AdminReportsPage() {
await requireRole("admin", "/admin/reports");
// load data, render
}
```
The page's call is free: each auth battery wraps its session read in React
`cache`. Pass the page's own path so sign-in brings the admin back to it.
Every export of `src/lib/admin/actions.ts` starts with `authorise()`, before it
reads a form field. It runs `requireRole("admin")`, then re-reads the admin
from the provider, because a role removed a minute ago can still sit in a
cached cookie (Better Auth, 5 minutes) or an unexpired token (Clerk, Supabase).
The one exception is `stopImpersonationAction`: the impersonated session is not
an admin session, so it checks `adminProvider.getImpersonation()` instead.
A route handler under `src/app/api/admin/**` uses `requireApiRole("admin")`
(401 or 403, never a redirect) and catches with `authErrorResponse`.
Never:
- rely on the proxy: `/admin/:path*` is in its matcher so signed-out visitors
bounce early, but it has no role check worth trusting;
- compare strings (`user.role === "admin"` misses Clerk's `owner`): use
`requireRole`, or `navItemsFor` for what the UI shows;
- move a page out of `src/app/(admin)/admin/`: it loses the shell and the
layout's check, and nothing warns you;
- render the shell for a refused user: `requireRole` answers with a 404 or the
auth battery's no-access page, and the chrome would tell an outsider the
page exists.
## Pages load, components render
A page is a Server Component. It calls the read helpers (`listUsers`,
`getUser`, `getUserStats` from `@/lib/admin/users`, `listAuditEntries` from
`@/lib/admin/audit`) and passes results down. Load independent data with
`Promise.all`. A slow section goes in its own async component inside
`<Suspense>` with a skeleton, as `/admin` does for its counts.
Components under `src/components/admin/**` take props. Two kinds load their
own data because a slot cannot pass them any: `ImpersonationBanner` (the
`app-banner` fill) and the billing summary (`AdminBillingStats`,
`AdminBillingCard`). Do not add a third without the same reason.
## Keep data on the server
- Modules in `src/lib/admin/` that reach a provider open with
`import "server-only"`: `users.ts`, `audit.ts`, `user-store.ts`,
`provider.ts`, `audit-store.ts`. Client components import only the pure
ones (`types.ts`, `policy.ts`, `format.ts`, `query.ts`, `cursor.ts`) and the
`"use server"` actions.
- Pick fields for client components: `UserActions` gets
`{ id, name, email, role, banned }`, never a database row.
- Never send a session token to the browser. The page sends a session id;
`findSessionToken` turns it into a token on the server.
- Filters and cursors live in the URL, parsed by `parseUserQuery` and
`parseAuditQuery`. A value that does not parse means "no filter", never an
error page.
## Look like the rest of the app
Use the kit (`@/components/ui/*`), `PageHeader` and `EmptyState` from
`@/components/app/*`, and token classes (`bg-surface-card`, `text-muted`,
`border-hairline`). No palette classes, no hex, no `dark:` for colour: the
panel must read well in every design, light and dark.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/auto-lint.ts"
},
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/enforce-doc-meta.ts"
}
]
},
{
"matcher": "Edit|Write|MultiEdit|Bash|Read|Grep",
"hooks": [
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/env-leak-detector-write.ts"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-destructive.ts"
},
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/enforce-typecheck.ts"
},
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-neon-sql.ts"
}
]
},
{
"matcher": "Bash|Read|Grep",
"hooks": [
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/env-leak-detector.ts"
}
]
}
]
},
"extraKnownMarketplaces": {
"compound-engineering-plugin": {
"source": {
"source": "github",
"repo": "EveryInc/compound-engineering-plugin",
"ref": "compound-engineering-v3.28.2"
}
}
},
"enabledPlugins": {
"compound-engineering@compound-engineering-plugin": true
}
}
After you unzip
cd my-app
bun install
# then follow docs/onboard.md for env vars
bun run verifyThe agentic layer
Everything an agent reads on its first run
Compiled from neutral definitions into Claude Code’s format, plus Codex and Cursor when you pick those targets. Each entry names where it came from: a battery, the design or the base stack.
Agents (7)
Subagents in .claude/agents/. Each carries its own system prompt and, where it matters, a tool allowlist.
- Neon
db-inspector
Read-only Neon Postgres inspector. Explains schema, data shape and query plans. Runs SELECT and EXPLAIN only, and refuses every statement that writes or changes schema.
tools: Read, Grep, Glob, Bash, mcp__neon
- Midnight
designer
Owns the Midnight design system and its shadcn bridge. The only agent allowed to introduce a new visual pattern or a new token. Refuses to ship a raw colour or a single-mode change.
tools: Read, Grep, Glob, Edit, Write
- Next.js on Vercel
documentarian
Keeps README, CLAUDE.md, DESIGN.md, docs/onboard.md and docs/solutions/ true to the code. Writes solution docs from work that just landed.
tools: Read, Grep, Glob, Edit, Write, Bash
- Next.js on Vercel
pr-reviewer
Reviews a diff against this repo's rules before it becomes a PR. Convention-aware, blocking on correctness and security, advisory on taste.
tools: Read, Grep, Glob, Bash
- PostHog
product-analyst
Read-only product analyst. Answers questions about user behaviour from the event catalogue and the PostHog project, and says plainly when the instrumentation cannot answer them.
tools: Read, Grep, Glob, mcp__posthog
Show all 7Show fewer
- Next.js on Vercel
security-auditor
Audits the repo or a diff for leaked secrets, broken auth boundaries, injection, unsafe dependencies and unsafe deploy configuration.
tools: Read, Grep, Glob, Bash
- Next.js on Vercel
system-manager
Maintains the .claude agentic layer itself: rules, skills, agents, hooks, settings. Adds a rule when a correction repeats.
tools: Read, Grep, Glob, Edit, Write, Bash
Skills (28)
Slash commands in .claude/skills/, encoding the repeatable jobs for this selection.
- Admin panel
/add-admin-action
Add an admin action (verify an email, reset a plan, delete an account) as a checked, validated, audited server action with a confirm dialog.
.claude/skills/add-admin-action/SKILL.md
- Admin panel
/add-admin-page
Add a page to /admin with the role check, a sidebar entry, loading and empty states, and data read through the admin ports.
.claude/skills/add-admin-page/SKILL.md
- Next.js on Vercel
/add-app-page
Add a page to the signed-in app (sidebar entry, session check, loading state), or a new tab under /settings.
.claude/skills/add-app-page/SKILL.md
- Resend
/add-email-template
Add a React Email template, preview it, wire it into a send, and check it renders and lands in a real inbox.
.claude/skills/add-email-template/SKILL.md
- PostHog
/add-event
Add a product event end to end: catalogue entry, the question it answers, the capture call on the correct side of the network, and a check that it arrives.
.claude/skills/add-event/SKILL.md
Show all 28Show fewer
- Better Auth
/add-oauth-provider
Turn on Google, GitHub or Microsoft sign-in (env keys only), or add another OAuth provider to the list in src/lib/auth/providers.ts.
.claude/skills/add-oauth-provider/SKILL.md
- Polar
/add-product
Add or change a plan or price on Polar (monthly, yearly or one-time lifetime). Edit src/lib/pricing.ts, create the Polar product, wire its env var, and prove checkout and the webhook end to end.
.claude/skills/add-product/SKILL.md
- Drizzle ORM
/add-table
Add a table to the Drizzle schema, generate and apply its migration, and wire the typed queries for it.
.claude/skills/add-table/SKILL.md
- AI bundle
/add-tool
Add a tool the model can call (schema, execute, registry entry, surface and a test) without widening what a stranger's sentence can reach.
.claude/skills/add-tool/SKILL.md
- PostHog
/ask-product
Answer a question about user behaviour from this repo's event catalogue and the PostHog project, with the caveats that make the number usable.
.claude/skills/ask-product/SKILL.md
- Neon
/db-branch
Create, use, reset and delete Neon database branches, for a feature branch, a preview deploy, a migration rehearsal or a point-in-time investigation.
.claude/skills/db-branch/SKILL.md
- Next.js on Vercel
/deploy-to-vercel
Ship my-app to Vercel: local gates, environment variables per scope, preview verification, promotion and rollback.
.claude/skills/deploy-to-vercel/SKILL.md
- Next.js on Vercel
/edit-pricing
Add, change or remove a plan or a price (monthly, yearly or one-time lifetime) and wire it to the payment provider.
.claude/skills/edit-pricing/SKILL.md
- AI bundle
/eval-prompt
Change a prompt, a model or a schema safely. Build the eval suite first, measure the baseline, change one thing, and compare pass rates.
.claude/skills/eval-prompt/SKILL.md
- Next.js on Vercel
/help
Explain the agentic system in this repo (rules, skills, agents, hooks, solution docs and the CE loop) and where to go for help beyond it.
.claude/skills/help/SKILL.md
- Next.js on Vercel
/landing-copy
Rewrite the landing page, the metadata and the legal details for the real product from a short brief, by editing src/lib/site.ts only.
.claude/skills/landing-copy/SKILL.md
- Drizzle ORM
/migrate
Generate, review and apply Drizzle migrations safely, including backfills, destructive changes and the deploy step.
.claude/skills/migrate/SKILL.md
- Neon
/migrate-on-neon
Run a schema migration against Neon safely, on the direct URL, rehearsed on a branch first, with a recovery path when it fails halfway.
.claude/skills/migrate-on-neon/SKILL.md
- Midnight
/new-component
Add a component to the Midnight kit. Prefer pasting from shadcn/ui, fix the two bridge classes, keep it token-only and verify it in both light and dark.
.claude/skills/new-component/SKILL.md
- Resend
/preview-and-test-email
Diagnose an email problem (not sending, landing in spam, rendering wrong) in the order that finds the cause fastest.
.claude/skills/preview-and-test-email/SKILL.md
- Better Auth
/protect-route
Put an authentication or role check on a page, a route handler, a server action or a whole route group, at the right layer, without a redirect loop.
.claude/skills/protect-route/SKILL.md
- Next.js on Vercel
/qa-feature
Exercise a feature end to end (happy path, unhappy paths, auth boundaries, refresh and mobile) before anyone calls it done.
.claude/skills/qa-feature/SKILL.md
- Sentry
/scrub-pii
Audit what this app actually sends to Sentry, extend the scrubbing layer for a new field or shape, and respond when something sensitive has already been sent.
.claude/skills/scrub-pii/SKILL.md
- Next.js on Vercel
/security-audit
Run the standing security pass through the security-auditor agent (secrets, auth boundaries, injection, dependencies and deploy config) and turn findings into fixes.
.claude/skills/security-audit/SKILL.md
- Polar
/test-webhook
Exercise the Polar webhook endpoint locally. Forward real sandbox events with the Polar CLI, or sign a one-time order yourself; buy both kinds of price, refund one, prove replays are no-ops, and debug signature failures.
.claude/skills/test-webhook/SKILL.md
- Sentry
/triage-errors
Work the Sentry issue list: rank by users affected, separate regressions from background noise, find the deploy that caused it, and fix or suppress with a reason.
.claude/skills/triage-errors/SKILL.md
- Next.js on Vercel
/verify
Prove the repo is actually configured: every required env var present, every configured service reachable, and the guard hooks still blocking what they claim to block.
.claude/skills/verify/SKILL.md
- Next.js on Vercel
/write-spec
Turn a loose request into a written spec (problem, scope, behaviour, acceptance criteria) that /ce-plan can consume without guessing.
.claude/skills/write-spec/SKILL.md
Rules (30)
Rules in .claude/rules/. The glob is what loads them only where they apply, instead of one CLAUDE.md an agent skims.
- Admin panel
admin-access
Admin pages check the role themselves and read data on the server
src/app/(admin)/** · src/components/admin/** · src/lib/admin/actions.ts · src/app/api/admin/**
- Admin panel
admin-mutations
Admin writes go through the provider port, and every one is audited
src/lib/admin/** · src/components/admin/** · scripts/admin/**
- AI bundle
ai-prompt-safety
Never interpolate untrusted text into a system prompt
src/lib/ai/** · src/app/api/**
- AI bundle
ai-server-boundary
Model calls stay on the server, and they stream
src/lib/ai/** · src/app/api/chat/** · src/app/api/agent/** · src/components/ai/** · vercel.json
- AI bundle
ai-structured-output
Every structured call carries a Zod schema
src/lib/ai/** · src/app/api/**
Show all 30Show fewer
- AI bundle
ai-tools
Every tool validates its own input
src/lib/ai/tools/** · src/lib/ai/agent.ts · src/app/api/agent/**
- Next.js on Vercel
app-shell
Pages in the signed-in app
src/app/(app)/** · src/components/app/** · src/components/ui/sidebar.tsx · src/lib/app-shell.ts · src/lib/nav.ts
- Better Auth
auth-server-boundary
The auth server boundary and sign-in methods
src/lib/auth/** · src/app/api/auth/** · src/app/(better-auth)/** · src/components/auth/**
- Next.js on Vercel
billing-core
Billing is one shared layer with one provider adapter
src/lib/pricing.ts · src/lib/billing/** · src/app/pricing/** · src/app/(app)/billing/** · src/components/billing/**
- Next.js on Vercel
code-style
Code style and file conventions
repo-wide
- Next.js on Vercel
deployment
Deployment rules
next.config.ts · vercel.json · package.json · src/proxy.ts · src/app/**/route.ts · .env.example
- Drizzle ORM
drizzle-migrations
Every schema change ships with its generated migration
src/db/** · drizzle/** · drizzle.config.ts
- Drizzle ORM
drizzle-schema
Schema and query conventions for Drizzle
src/db/**
- Resend
email-sending-discipline
Every email goes through sendEmail, from a verified domain, with a reply-to
src/lib/email/** · src/app/api/webhooks/resend/** · src/lib/auth/** · src/lib/billing/**
- PostHog
event-naming
Events are declared in the catalogue, named object_verb, past tense
src/lib/analytics/** · src/app/** · src/components/**
- Next.js on Vercel
git
Git and change hygiene
repo-wide
- PostHog
identify-timing
Identify before the first event that matters, reset on sign-out
src/lib/analytics/** · src/app/** · src/components/**
- Next.js on Vercel
landing-and-legal
Landing page, legal pages and llms.txt
src/lib/site.ts · src/lib/llms.ts · src/app/page.tsx · src/app/(legal)/** · src/app/llms.txt/** · src/components/marketing/** · src/components/site/**
- Neon
neon-connections
One connection surface, and the right driver for the job
src/db/** · src/app/api/**
- Neon
neon-migrations
Schema changes go through ORM migration files on the direct URL
src/db/**
- Polar
polar-billing-adapter
Polar translates, the shared billing core writes the store
src/lib/pricing.ts · src/lib/billing/** · scripts/billing/**
- Polar
polar-webhook-integrity
Verify every Polar webhook, keep every handler idempotent
src/app/api/webhooks/polar/** · src/lib/billing/provider.ts · src/lib/billing/polar-webhooks.ts · src/lib/billing/webhook.ts
- Better Auth
roles-are-server-side
Roles are decided on the server, every time
src/app/** · src/components/** · src/lib/auth/**
- Next.js on Vercel
security
Security rules
repo-wide
- Sentry
sentry-capture
Every captured exception carries a stable fingerprint hint
src/** · sentry.server.config.ts · sentry.edge.config.ts
- Sentry
sentry-no-pii
No personal data in breadcrumbs, tags or extra
repo-wide
- PostHog
server-truth-and-pii
Server events for anything a client can lie about, and never PII in properties
src/lib/analytics/** · src/app/** · src/components/**
- Next.js on Vercel
testing
Testing rules
tests/** · src/**/*.test.ts · src/**/*.test.tsx
- Midnight
tokens-only
Midnight: tokens only, and both modes every time
src/components/** · src/app/**
- Next.js on Vercel
ui-kit
Build UI from the component kit
src/components/** · src/app/**
Hooks (7)
Guard hooks wired into .claude/settings.json. The repo wires hooks for Claude Code only. Run verify:hooks to prove each one still blocks what it claims to.
- Next.js on Vercel
auto-lint
Runs Biome on the file that was just edited, applies safe fixes, and reports anything it could not fix.
PostToolUse · Edit|Write|MultiEdit
- Next.js on Vercel
block-destructive
Blocks irreversible shell commands: recursive force deletes, DROP and TRUNCATE sent to a database, force pushes, git reset --hard, git clean, dd, and truncating redirects onto tracked files.
PreToolUse · Bash
- Next.js on Vercel
enforce-doc-meta
Checks that files written under docs/solutions/ and docs/plans/ carry the frontmatter those directories depend on, and reports exactly what is missing.
PostToolUse · Edit|Write|MultiEdit
- Next.js on Vercel
enforce-typecheck
Rewrites a bare tsc, however it is launched, into the project's typecheck script before it runs.
PreToolUse · Bash
- Next.js on Vercel
env-leak-detector
Blocks tool calls that would print, transmit or commit a secret: literal credential shapes, reads of local .env files by any command or by the Read and Grep tools, echo of secret variables, environment dumps, and live values from your .env files.
PreToolUse · Bash|Read|Grep
Show all 7Show fewer
- Next.js on Vercel
env-leak-detector-write
The second half of env-leak-detector: redacts live secret values from command, read and search output before the agent sees them, and flags secrets written into files, private env vars read in client components, and secrets passed to log calls.
PostToolUse · Edit|Write|MultiEdit|Bash|Read|Grep
- Neon
guard-neon-sql
Blocks raw DDL through psql, migrations that would really run through the Neon pooler, and schema pushes that skip migration files. The repo's own db:migrate scripts pass.
PreToolUse · Bash
Institutional memory
75 solution docs, seeded on day one
They ship inside the repo under docs/solutions/. They are published here too, so you can read them first.
Admin panel (8)
- Designing an audit log for an admin panelOne append-only table, namespaced past-tense actions, emails copied in, and a clear rule for when the audit row can share a transaction with the change and when it cannot.docs/solutions/admin-panel/adding-an-audit-log.md
- Bans that actually sign people outSetting banned = true stops the next sign-in, not the session already open. What Better Auth, Clerk and Supabase do on a ban, where caches and tokens let a banned user linger, and how to say so.docs/solutions/admin-panel/bans-and-session-revocation.md
- Empty states that are not sadAn empty state that only says "No data available" is a dead end. It should say what belongs here, why it is missing, and what to do next.docs/solutions/admin-panel/empty-states-that-are-not-sad.md
- Making the first admin without a back doorA fresh deploy has no admin, and the admin page needs one to add one. Use a terminal script with database or API credentials, never an env list of emails or a first-user-wins rule.docs/solutions/admin-panel/first-admin-without-a-backdoor.md
- impersonating-users-safelydocs/solutions/admin-panel/impersonating-users-safely.md
- Paginating admin tables without a client libraryOffset pages with a total for the users table, keyset cursors for the audit log, both in the URL and rendered on the server. When to use which, and the details that make each correct.docs/solutions/admin-panel/paginating-a-users-table.md
- Role checks that survive a layout refactorA check that lives only in a layout disappears the day someone moves the page. Put the boundary where the route is, and check again where the work happens.docs/solutions/admin-panel/role-checks-that-survive-a-refactor.md
- Route group or path segment: how to lay out an admin sectionA route group shares a layout without touching the URL; a path segment is the URL. Admin panels need both, and confusing them produces public pages and 404s.docs/solutions/admin-panel/route-group-vs-path-segment.md
Show all 75Show fewer
AI bundle (6)
- Prompt injection through user content: why delimiters are not the fixAny text a user can influence can carry instructions. Wrapping helps a little; least-privilege tools, human confirmation and never trusting output as authorisation are what actually hold.docs/solutions/ai-bundle/prompt-injection-through-user-content.md
- Streaming edge cases: aborts, disconnects, backpressure and errors after the first tokenA streamed response that fails halfway does not reject anything, and a user who closes the tab keeps billing you. The four cases every streaming route has to handle.docs/solutions/ai-bundle/streaming-edge-cases.md
- Tool retries and partial failures: what the AI SDK retries and what it does notThe SDK retries the request to the model, never your tool's side effects. A tool that half-succeeded and then got called again is where duplicate charges come from.docs/solutions/ai-bundle/tool-retries-and-partial-failures.md
- When to add usage metering to an AI feature, and how to do it in an afternoonA public AI route is a public spend endpoint. The three signals that say you need metering now, and the smallest implementation that actually protects you.docs/solutions/ai-bundle/when-to-add-usage-metering.md
- When AI work has to move to a background job, and what breaks if you waitServerless functions have a hard timeout that no amount of streaming avoids. The four signals that mean the work no longer belongs in the request, and the smallest queue that fixes it.docs/solutions/ai-bundle/when-to-move-ai-work-to-a-background-job.md
- When LLM tracing pays for itself, and the free version to build firstA user reports an answer you cannot reproduce. Without the exact prompt, the tool steps and the model version, you are guessing. But a paid tracing tool is not the first thing to reach for.docs/solutions/ai-bundle/when-tracing-pays-for-itself.md
Better Auth (10)
- Account linking and email verification without account takeoversWhen "Continue with Google" joins an existing password account, when it refuses, and why an unverified email address or a trusted provider list can hand one person's account to another.docs/solutions/better-auth/account-linking-and-email-verification.md
- Better Auth on the edge: why your session check fails in middlewareEdge runtimes have no TCP sockets and no Node crypto, so a session lookup that works in a page throws in the proxy. Read the cookie there and verify in the render.docs/solutions/better-auth/better-auth-on-the-edge.md
- CSRF, SameSite and the cookie flags that make a session safeWhat each session cookie flag actually defends against, why trustedOrigins is your CSRF check, and the three configuration changes that quietly disable both.docs/solutions/better-auth/csrf-and-cookie-flags.md
- Guard Better Auth's endpoints, not just your settings formsEvery /api/auth endpoint is a public URL. One hook refuses account changes from an impersonation session and asks for a recent sign-in before a password or provider is added.docs/solutions/better-auth/guarding-the-auth-api-itself.md
- The magic-link token: single use, ten minutes, and the scanner that clicks it firstHow long the credential lives, why a corporate mail scanner burns it before the human arrives, and why the rate limiter has to be backed by your database rather than by process memory.docs/solutions/better-auth/magic-link-tokens-and-scanners.md
- Moving an existing user table onto Better Auth without logging everyone outMap your columns to the four required tables, backfill ids and accounts, and let people migrate themselves on next sign-in instead of forcing a password reset.docs/solutions/better-auth/migrating-an-existing-user-table.md
- oauth-callback-url-mismatchesdocs/solutions/better-auth/oauth-callback-url-mismatches.md
- Password reset tokens that cannot be replayed, guessed or leakedOne hour, single use, answered the same way for every address, and kept out of logs, Referer headers and search results. What Better Auth does for you and the four things it cannot.docs/solutions/better-auth/password-reset-tokens.md
- Modelling roles you will not regret when the admin panel growsA role column, a ranked vocabulary in one file, and permission checks that name the action, not a boolean isAdmin scattered across forty components.docs/solutions/better-auth/role-modelling-for-the-admin-panel.md
- Session invalidation, or why everyone got logged out on deployA rotated secret, a changed cookie name or a wiped database invalidates every session at once. Here is what invalidates what, and how to revoke one user on purpose.docs/solutions/better-auth/session-invalidation-and-logged-out-on-deploy.md
Drizzle ORM (5)
- Adding a NOT NULL column to a table that already has rowsThe one-line migration fails on any populated database. Split it into add-nullable, backfill in batches, and enforce: three migrations across two deploys.docs/solutions/drizzle/adding-a-column-with-a-backfill.md
- drizzle-kit generate or drizzle-kit push, and when each is safepush diffs your schema straight onto the database with no file to review; generate writes SQL you commit. Use push only on a database you can throw away.docs/solutions/drizzle/generate-vs-push.md
- db.query relations or an explicit join: choosing in Drizzle without an N+1The relational API returns nested objects and one round trip; the core builder returns flat rows and total control. Which to reach for, and the loop that quietly becomes N+1.docs/solutions/drizzle/relations-vs-joins.md
- Transactions in Drizzle on serverless: what works over HTTP and what needs a socketAn interactive db.transaction() needs a real connection held open. On an HTTP driver it silently is not one. Here is what each driver supports and how to write atomic writes without holding a connection.docs/solutions/drizzle/transactions-in-serverless.md
- Typing partial selects and joins in Drizzle without writing the types by hand$inferSelect describes the whole row, not the three columns you selected. Use the query builder's inferred types, Awaited<ReturnType<...>>, and helper types instead of hand-maintained interfaces.docs/solutions/drizzle/typing-partial-selects.md
Midnight (4)
- A chart palette that survives dark modeSix brand colours picked on white turn muddy or fluorescent on near-black. Define the series palette as tokens with two values each, assign them in order, and never let colour be the only encoding.docs/solutions/midnight/a-chart-palette-that-survives-dark-mode.md
- A dark mode toggle that works on a machine already set to darkprefers-color-scheme and a .dark class fight over specificity and order. One extra :not() makes an explicit choice win in both directions, and one inline script kills the flash.docs/solutions/midnight/class-and-system-dark-mode-that-both-work.md
- Pasting a shadcn component into a repo that renamed the tokensshadcn components are written against variable names, not values. Publish those names alongside your own and a paste works unmodified: except for the ones you already claimed.docs/solutions/midnight/pasting-shadcn-components-into-your-own-token-names.md
- Tailwind v4: your dark mode does nothingAdding a .dark block that overrides your colour variables changes nothing if the utilities were generated with @theme instead of @theme inline. Here is the difference and the fix.docs/solutions/midnight/tailwind-v4-dark-mode-does-nothing.md
Neon (6)
- A Neon branch per preview deploymentPreview deploys that share the production database corrupt it or lie to you. Give every preview its own copy-on-write Neon branch, wired to the deployment's environment variables.docs/solutions/neon/branch-per-preview-deployment.md
- Neon cold starts, where the half second goes and what to do about itScale-to-zero means an idle branch takes roughly 500 ms to wake, and a serverless function adds its own cold start on top. How to measure the parts and fix the ones that matter.docs/solutions/neon/cold-start-latency.md
- Connection exhaustion on serverless Postgres, and how to actually fix itServerless does not queue requests on a pool, it creates pools. Here is the arithmetic, the four real causes, and the fix for each.docs/solutions/neon/connection-exhaustion-in-serverless.md
- Local Postgres with the Neon serverless driver, no Neon accountThe Neon driver speaks HTTPS and WebSocket, not the Postgres wire protocol. A small local proxy plus two neonConfig settings let it run against a Postgres on your laptop, with no code fork.docs/solutions/neon/local-postgres-without-a-neon-account.md
- Running migrations on Vercel without a half-applied schemaVercel has no migration step, so people add one in the wrong place. Where migrations belong in the build, why the direct URL is mandatory, and how to deploy a breaking change in two safe halves.docs/solutions/neon/migrations-on-vercel.md
- Neon's pooled and unpooled connection strings, and which one to use whereThe -pooler host and the direct host are not interchangeable. Runtime queries need the pooler; migrations, advisory locks and session state need the direct endpoint.docs/solutions/neon/pooled-vs-unpooled-connections.md
Next.js on Vercel (15)
- Protecting a signed-in app in the App Router, in three layersA layout that checks the session is not enough, because layouts do not re-render on client navigation. Where the proxy, the layout and the page each check, and why.docs/solutions/nextjs-vercel/auth-checks-in-an-app-shell.md
- The Compound Engineering loop, and where /ce-plan and /ce-work actually fitAgents that start typing immediately produce work nobody can review. Plan in a file, execute against it, then write down what you learned so the next pass is shorter.docs/solutions/nextjs-vercel/compound-engineering-loop.md
- Environment variables on Vercel, without leaking them into the browserNext.js inlines env reads at build time, so one import can ship a server key to every visitor. Here is the boundary that prevents it and the checks that prove it held.docs/solutions/nextjs-vercel/env-vars-on-vercel-without-leaking-them.md
- What each guard hook blocks, and how to extend one without breaking your sessionClaude Code hooks stop the mistakes that cost the most. Here is what each one refuses, how the exit codes work, and the safe way to add a rule of your own.docs/solutions/nextjs-vercel/guard-hooks-and-how-to-extend-them.md
- llms.txt for a SaaS site, generated from the same copy as the pageAn llms.txt file tells AI agents what your product is and where the important pages are. Build it from the landing page's data so it never goes stale, and serve it as a static file.docs/solutions/nextjs-vercel/llms-txt-for-a-saas-site.md
- Selling one-time purchases next to subscriptions without two billing systemsModel a lifetime deal as a one-time price that grants a plan, record it in a purchases table with a monotonic status, and resolve access from subscriptions and purchases in one rule.docs/solutions/nextjs-vercel/one-time-purchases-vs-subscriptions.md
- A pricing page that renders with no database and no payment keysKeep the plan catalogue in code, map provider price ids through env vars, and make /pricing a static page whose buttons are plain links to a checkout route.docs/solutions/nextjs-vercel/pricing-page-without-a-database.md
- A privacy policy that lists the vendors you actually useGDPR and the US state privacy laws expect you to say who processes personal data for you. Let each integration add itself to the list, so the policy changes when the code does.docs/solutions/nextjs-vercel/privacy-policy-that-lists-your-real-vendors.md
- Rate limit checkout in Postgres, before the provider sees itOne small table and one atomic upsert keep a looping user from spending your payment provider's API limit, across every serverless instance, with no Redis.docs/solutions/nextjs-vercel/rate-limiting-checkout-in-postgres.md
- Refunds and disputes should take access away, exactly onceWhich webhook carries a refund or a dispute on each payment provider, how to find the purchase it belongs to, and how to revoke access without a late event giving it back.docs/solutions/nextjs-vercel/refunds-disputes-and-entitlements.md
- Regenerating from agentic.config.json to see what upstream changedThere is no sync service and no template remote. Regenerate a clean copy from your recorded selection, diff it against your repo, and take only the agent layer.docs/solutions/nextjs-vercel/regenerate-from-config-and-diff.md
- Rules, skills and agents, which one you actually needThe same instruction behaves completely differently depending on where you put it. Rules are ambient constraints, skills are invoked procedures, agents are delegated scopes.docs/solutions/nextjs-vercel/rules-skills-agents-when-to-use-each.md
- Sample testimonials that never reach productionA landing page template needs quotes, logos and numbers to look finished, and publishing invented ones is illegal. Mark them as samples, show them in development, and drop them from the production build.docs/solutions/nextjs-vercel/sample-testimonials-without-the-ftc-risk.md
- A collapsible sidebar that remembers its state without a flashSaving the sidebar's open or collapsed state in localStorage makes every page load jump. A cookie the server reads renders the right width in the first HTML.docs/solutions/nextjs-vercel/sidebar-state-without-a-flash.md
- Writing a path-scoped rule that agents actually followRules fail for two reasons: they load when nobody needs them, or they are unfalsifiable. Scope by path, write checkable statements, and give every rule an escape hatch.docs/solutions/nextjs-vercel/writing-path-scoped-rules-agents-follow.md
Polar (6)
- Merchant of record explained, what Polar takes on that Stripe leaves with youWith Stripe you are the seller and you owe VAT, GST and US sales tax yourself. Polar sells on your behalf and carries that liability. What actually changes, what it costs, and how little of it reaches your code.docs/solutions/polar/merchant-of-record-vs-stripe.md
- Moving from Stripe to Polar without breaking existing customersYou cannot transfer live Stripe subscriptions to Polar. Sell new customers on Polar, keep Stripe's webhook alive for the ones you have, move them at renewal, and let the provider-neutral billing rows carry access through the whole overlap.docs/solutions/polar/migrate-a-stripe-catalogue-to-polar.md
- One-time and subscription products on Polar, from lifetime deal to renewalPolar sells one price per product, so a plan sold monthly, yearly and for life is three products. How each kind checks out, which webhook proves it was paid, where it is stored, and how access resolves when a customer holds both.docs/solutions/polar/one-time-and-subscription-products-on-polar.md
- Refunds and disputes on Polar, and taking access back exactly onceA refund arrives as order.refunded with the whole order. A dispute arrives as nothing at all. How this repo revokes a lifetime deal in both cases, why partial refunds keep access, and why a late paid delivery cannot give it back.docs/solutions/polar/refunds-and-disputes-on-polar.md
- Polar sandbox to production, the checklist that stops launch-day silenceSandbox and production are separate Polar deployments with separate tokens, product ids and webhook secrets. Nothing carries over. Everything that has to be recreated, in order, and how to prove it worked.docs/solutions/polar/sandbox-to-production-checklist.md
- Polar webhooks arrive twice and sign two ways, make the handler survive bothAt-least-once delivery means duplicates and out-of-order events are normal traffic, and Polar changed its signing key format in September 2026. Verify with both keys, claim the webhook-id before any write, re-read subscriptions and let orders only move forward.docs/solutions/polar/webhook-idempotency.md
PostHog (5)
- Ad blockers eat a third of your analytics: proxy ingestion through your own domainBlockers match on hostnames, not behaviour. A first-party /ingest route handler forwards events to PostHog server-side and recovers most of the missing traffic.docs/solutions/posthog/ad-blocker-reverse-proxy.md
- Event names that still make sense in twelve monthsWhy analytics projects rot into five spellings of "signup", and the object_verb convention plus a typed catalogue that stops it.docs/solutions/posthog/event-naming-that-survives.md
- Feature flags without the flickerClient-side flags render the control experience first and swap it a beat later. Evaluate on the server, pass the decision down, and keep a bootstrap for the client hooks.docs/solutions/posthog/feature-flags-without-flicker.md
- The identify race that empties your signup funnelEvents fired before identify() stay on the anonymous profile forever. Here is why the merge is not retroactive, and the ordering that fixes it.docs/solutions/posthog/identify-race-conditions.md
- Server events versus client events, and when each one liesA browser event is a claim, a server event is a record. Which side to fire from, why serverless drops events without after(), and how to keep the two from double-counting.docs/solutions/posthog/server-vs-client-events.md
Resend (5)
- Sending a lot of email without hitting the rate limit or the spam folderResend allows a couple of requests a second by default. Use the batch endpoint, add backoff for 429s, keep one idempotency key per recipient, and never batch a magic link.docs/solutions/resend/batching-and-rate-limits.md
- Bounces and spam complaints: listen, or lose the inbox for everyoneA hard bounce means the mailbox is gone. Keep sending and mailbox providers downgrade every message from your domain. Wire the webhook, suppress permanently, and never suppress on a soft bounce.docs/solutions/resend/bounces-complaints-and-webhooks.md
- SPF, DKIM and DMARC: what each record does and why your mail needs all threeThree DNS records decide whether a mailbox provider treats your email as authentic. Here is what each one proves, how to set them up on a subdomain, and how to read a failure.docs/solutions/resend/domain-verification-spf-dkim-dmarc.md
- Magic links that actually arrive, and survive the scanner that clicks them firstA sign-in link is the highest-stakes email you send. It has to land in seconds, work once, and survive corporate mail scanners that follow every URL before the human does.docs/solutions/resend/magic-link-deliverability.md
- Previewing React Email templates locally, and what the preview cannot tell youReact Email's preview server renders your templates with realistic props and hot reload. Here is how to set it up, what to check, and the four failure modes only a real client will show you.docs/solutions/resend/previewing-templates-locally.md
Sentry (5)
- One issue with 40,000 events: grouping, fingerprints and the helper that ruined themSentry groups by stack trace, so a shared fetch wrapper merges every unrelated failure into one useless issue. Fingerprints put the grouping back where the cause is.docs/solutions/sentry/grouping-noisy-errors-with-fingerprints.md
- Scrubbing PII before it leaves your process, not after it reaches SentryServer-side scrubbing runs after the data has crossed the network. beforeSend runs in your process, and it is the only layer you fully control.docs/solutions/sentry/scrubbing-pii-before-it-leaves-the-process.md
- Source maps on Vercel: why your production stack traces are unreadableA minified trace means the build never uploaded source maps. The auth token, the release name and the preview environment are the three things that are usually wrong.docs/solutions/sentry/source-maps-on-vercel.md
- Telling a real incident from a bot, a browser extension or a stale tabMost of a new project's error feed is not your bug. The four signatures of noise, how to filter each one at the right layer, and the three signals that mean it is real.docs/solutions/sentry/telling-a-real-incident-from-a-bot.md
- Trace sample rates that do not bankrupt youErrors are cheap and spans are not. How to pick tracesSampleRate, why the edge runtime needs a lower one, and how to keep the traces you actually need while dropping 95% of the rest.docs/solutions/sentry/trace-sample-rates-that-do-not-bankrupt-you.md
Use AI Product
The builder opens with these 9 batteries picked. Change anything, then download the zip.