A rules-driven character + crew manager for Forged in the Dark (FitD) tabletop RPGs. It works two ways: as your character sheet anywhere (build a rules-valid scoundrel and crew — every action the app offers is legal for your ruleset — and bring it to any table), and as the live mechanical layer for async, play-by-post games on Discord (rolls, clocks, stress, per-score gear, crew/faction state, and a score-grouped campaign log the table builds as the story posts over days). The narrative stays in Discord prose; the mechanics live here — think "Avrae for Forged in the Dark." Play can happen in person, on Discord, or in-app — take what you want and leave the rest.
# Install dependencies
pnpm install
# Start development servers
pnpm dev
# Build all packages
pnpm build
# Build specific package
pnpm build:ui
pnpm build:webheist-mind/
├── apps/
│ ├── web/ # Next.js web application
│ └── discord-bot/ # Discord bot (future)
├── packages/
│ ├── database/ # Supabase client and types
│ ├── shared/ # Shared utilities and types
│ └── ui/ # Component library
├── supabase/ # Database schema and migrations
└── .claude/skills/cx-map/ # Living product docs (status, CX map, findings)
- Frontend: Next.js 15, React 19, TypeScript 5
- Styling: Tailwind CSS 4
- State Management: Zustand with domain separation
- Database: Supabase with PostgreSQL
- Monorepo: pnpm workspaces + Turborepo
- Deployment: Vercel
HeistMind follows a Domain-Driven Design approach with:
- Multi-tenant database with Row Level Security
- Domain-separated frontend (auth, games, characters)
- Enterprise-grade state management with Zustand
- Type-safe API integration throughout the stack
pnpm dev # Start all development servers
pnpm build # Build all packages
pnpm lint # Lint all packages
pnpm type-check # Type check all packages
pnpm clean # Clean all build outputspnpm build:ui # Build UI package only
pnpm build:web # Build web app only
pnpm dev:ui # Start UI package in watch mode
pnpm dev:web # Start web app onlypnpm db:push # Push schema changes to Supabase
pnpm db:types # Generate TypeScript types from schema- Smart Caching: Only rebuilds changed packages
- Dependency-Aware: Builds packages in correct order
- Parallel Execution: Faster builds and development
- Selective Builds: Build only what you need
Two ways to use HeistMind — a rules-valid character sheet you bring anywhere, and the shared mechanical layer for async play-by-post on Discord. Campaign state is DB-backed and loaded on view (no realtime required); the narrative lives in your Discord channels, the mechanics live here.
- Upload and manage custom FitD rulesets (JSON), or load the bundled Brackwater starter
- Run campaigns with a crew sheet, progress clocks, factions, a roster (player→character, status, retire), and a score-grouped campaign log
- Start/end a score, make fortune/GM rolls, and advance clocks as it unfolds
- Build rule-driven characters with a guided wizard (playbook, action ratings, abilities, identity); level up from the same editor
- Work from a live character sheet: stress, harm, XP tracks, per-score loadout, and action/resistance rolls — every option the app offers is legal for the ruleset
- Log results from wherever you play (in-app, or recording what happened at the table / on Discord); it all lands in one shared, score-grouped campaign log
-
Clone the repository
git clone https://github.com/your-org/heist-mind.git cd heist-mind -
Install dependencies
pnpm install
-
Set up environment variables
cp .env.example .env.local # Edit .env.local with your Supabase credentials. # SUPABASE_PROJECT_ID is needed for `pnpm db:types` (remote type regen).
-
Boot the database and apply migrations
supabase start # local Postgres + Auth (Docker); configured by supabase/config.toml pnpm db:push # apply supabase/migrations/*
-
Start development
pnpm dev
Domain types are generated from the live schema into packages/database/src/supabase-types.ts.
After a migration adds/changes a column or table, regenerate types or the repository adapter (and
CI type-check) will fail — the new column doesn't exist on the generated types until you regen:
pnpm db:types # remote schema — needs SUPABASE_PROJECT_ID
pnpm --filter database db:types-local # …or a running local stackCharacter mechanics ride a JSONB column, so most character-shape changes need no migration at all.
Living product docs are maintained in the cx-map skill (.claude/skills/cx-map/):
STATUS.md— what HeistMind is, what's built, architecture/constraints, and current plansBRD.md— the scope-of-record: product requirements, core-value / à-la-carte principles, phased planCX-MAP.md— every page and user flow (routes, character wizard, campaign panels, roles)COMPETITIVE.md— value prop + competitive frame (vs D&D Beyond and Avrae) + ranked P0 gapsFINDINGS.md— known CX flaws + FitD-rule gaps (the backlog)
Repo conventions, commands, and the deploy loop live in CLAUDE.md.
- Row Level Security: Multi-tenant data isolation
- Type Safety: End-to-end TypeScript coverage
- Authentication: Discord OAuth via Supabase Auth
- Environment Separation: Schema-based dev/prod isolation
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and type checking
- Submit a pull request
The code is licensed under the MIT License — see LICENSE. Built-in game content (the catalog rulesets) carries its own per-ruleset licenses (CC BY 3.0 / CC0 / CC BY 4.0) — see NOTICE.md for the full breakdown, attributions, and the not-affiliated disclaimer.