PayKit is a TypeScript-first payments orchestration framework for modern SaaS. It sits between your app and payment providers (Stripe, PayPal, regional PSPs), providing a unified API without vendor lock-in. PayKit does not process payments — it orchestrates them.
Read ob/spec.md before making architectural decisions.
pnpm install # Install dependencies
pnpm build # Build all packages (Turbo)
pnpm dev # Dev mode (Turbo, persistent)
pnpm lint # Lint with oxlint (--deny-warnings)
pnpm lint:fix # Auto-fix lint issues
pnpm format # Format with oxfmt
pnpm format:check # Check formatting
pnpm typecheck # Type check (tsc --build)Run specific tests with vitest /path/to/<test-file> -t <pattern>, not pnpm test.
- Runtime: Node.js >= 22 | Package manager: pnpm 10.4.1 (workspaces)
- Build: Turbo 2.8.10 | Language: TypeScript 5.9.2 (strict, composite)
- Linter: oxlint 1.51 | Formatter: oxfmt 0.36 | Validation: Zod 4
- Git hooks: simple-git-hooks + lint-staged (runs
oxlint --fix+oxfmt --writeon commit)
- Framework: Next.js (App Router) | Styling: Tailwind CSS v4
- Animations: Framer Motion | Components: shadcn/ui + fumadocs-ui
- Code highlighting: Shiki with custom Vercel Dark theme (
landing/src/lib/shiki-vercel-theme.ts), applied as default inDynamicCodeBlock
Enforced by oxlint, oxfmt, and TypeScript config. Follow strictly.
- Strict mode with
noUncheckedIndexedAccess,useConstenforced import typewith separated style; Node.js protocol (node:fs,node:path)import * as z from "zod", neverimport { z } from "zod"- No
@ts-ignore(use@ts-expect-errorwith explanation), noany(useunknown), nodelete, no implicitanyonlet - All promises must be awaited or explicitly voided
- Avoid classes (use functions/objects) and enums (use
as constor unions) - No
Bufferin library code — useUint8Array.Bufferallowed in tests - 2-space indent, oxfmt handles formatting — do not add Prettier or Biome
- while using tailwing, prefer sizes in tw units like
-5rather than in pixels via-[20px] - prefer to co-locate component Props with a function, rather than separating them into an interface
- while using Zod, prefer not duplicate types, just infer them from schemas
- Use CSS variables for theme colors (
bg-background,bg-card) — never hardcode hex in components - Use standard Tailwind sizes (
text-xs,text-sm,text-base) — avoid arbitrary pixel values - Dark theme uses oklch color space with neutral grays (no chroma)
- PRs target
main. Conventional Commits:feat(scope):,fix(scope):,docs:,chore: - Scope = package name:
feat(stripe): add webhook handler - Vitest for tests. Add
@seeJSDoc with issue URL for regression tests
- When asked opinion questions ("Maybe do this?", "what do you think?", "should we do X?"), only answer — don't make code changes unless explicitly asked!!
- Never
git commit,git push, or run database migrations without explicit approval or being asked - while generating a db migration, always provide --name. like pnpm db:generate --name add_product_table
- never edit past migrations, only way is generating new one
Use /browse from gstack for all web browsing. Never use mcpclaude-in-chrome* tools. Available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /review, /ship, /browse, /qa, /qa-only, /design-review, /setup-browser-cookies, /retro, /investigate, /document-release, /codex, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade.