fluid-calendar
CLAUDE.md996 starsChanged 4 months agoMITView on GitHub
FluidCalendar is an open-source alternative to Motion: intelligent task scheduling plus calendar management. It ships in two flavors from one codebase - a free self-hosted open source build and a hosted SAAS build with premium features (billing, advanced AI scheduling). Next.js 15 (App Router) · React 19 · TypeScript · Prisma + PostgreSQL · NextAuth.js (v4) · Zustand · TanStack Query · FullCalendar · Tailwind + shadcn/ui (Radix) · Zod · BullMQ + Redis (jobs) · Stripe (SAAS billing). Local-first…
- Installs packages
We split this CLAUDE.md into the rules it gives an agent
13 rules. About 0 are common, 1 is distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 48
Background jobs: use BullMQ + Redis. All job code lives in src/saas/jobs/ (SAAS-only) and runs in a separate worker process (build:worker / …
- Very specific: line 56
All SAAS-only code goes in src/saas/.
- Very specific: line 61
Do not use .gitignore to hide SAAS files - exclusions belong in sync-repos.sh.
- Distinctive: line 62
When adding a feature, decide whether it's open-source, SAAS-only, or core-with-premium-enhancement.
- Very specific: line 66
Prisma client: import the singleton prisma from @/lib/prisma.
- Very specific: line 67
Dates: use helpers in @/lib/date-utils.ts for all date work, including new Date() - don't reach for date-fns/date-fns-tz directly.
- Very specific: line 69
Logging: use the logger from @/lib/logger, never console.log.
- Very specific: line 72
shadcn/ui: add components with npx shadcn@latest add.
- Very specific: line 74
Keep changes minimal and scoped.
- Very specific: line 75
Update CHANGELOG.md under [unreleased] as you make user-facing changes.
- Very specific: line 99
Use mulch prime --files src/foo.ts to load only records relevant to specific files.
- Very specific: line 109
Run mulch status to check domain health and entry counts.
- Very specific: line 110
Run mulch --help for full usage.
≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
FluidCalendar is an open-source alternative to Motion: intelligent task scheduling plus calendar management. It ships in two flavors from one codebase - a free self-hosted open source build and a hosted SAAS build with premium features (billing, advanced AI scheduling).
Commands
npm run dev # Dev server (Next.js + Turbopack) on :3000
npm run build # Production build (SAAS extensions if NEXT_PUBLIC_ENABLE_SAAS_FEATURES=true)
npm run build:os # Open-source build (forces SAAS features off)
npm run type-check # tsc --noEmit
npm run lint # next lint (CI requires --max-warnings=0; lint-staged enforces this)
npm run format # prettier --write
npm run test:unit # Jest unit tests (Node env, src/**/__tests__/**/*.test.ts)
npm run test:e2e # Playwright e2e (tests/, needs server on TEST_BASE_URL/localhost:3000)
npx jest path/to/file.test.ts # Run a single Jest test file
npx jest -t "test name substring" # Run tests matching a name
npm run prisma:generate # Regenerate Prisma client after schema changes
npm run prisma:studio # Browse the DB
npm run db:up # Start the Postgres container (docker compose)
npm run build:worker # Compile the BullMQ worker (tsconfig.worker.json -> dist/)
npm run start:worker # Run the compiled background job worker- Install with
npm install --legacy-peer-deps(React 19 peer-dep conflicts otherwise). - Node version is pinned in
.nvmrc(22.x). - Husky pre-commit runs
lint-staged: eslint (zero warnings) + prettier +type-checkon staged files.
Tech Stack
Next.js 15 (App Router) · React 19 · TypeScript · Prisma + PostgreSQL · NextAuth.js (v4) · Zustand · TanStack Query · FullCalendar · Tailwind + shadcn/ui (Radix) · Zod · BullMQ + Redis (jobs) · Stripe (SAAS billing).
Architecture
Local-first calendar sync. External calendars (Google / Outlook / CalDAV) are never read live in the UI. Each provider syncs into our own DB (CalendarFeed + CalendarEvent), and the app always operates on local data. OAuth token refresh is handled centrally so expired tokens are renewed transparently and syncing continues. Provider logic lives in src/lib/{google,outlook,caldav}-*.ts and src/lib/token-manager.ts.
Task scheduling engine (src/services/scheduling/): TaskSchedulingService orchestrates auto-scheduling; TimeSlotManager enumerates candidate slots from work hours / buffers; SlotScorer ranks them; CalendarServiceImpl checks calendar availability. Tasks marked isAutoScheduled get scheduledStart/End and a scheduleScore.
Task sync (src/lib/task-sync/): one-way sync from external task providers (Outlook, Google Tasks) into FluidCalendar using selective field sync - external-owned fields (title, status, due date, recurrence) are overwritten on each sync; local-owned fields (start date, duration, priority, energy level) are preserved. See src/lib/task-sync/README.md.
Background jobs use BullMQ + Redis. All job code lives in src/saas/jobs/ (SAAS-only) and runs in a separate worker process (build:worker / start:worker).
State: Zustand stores in src/store/ (small, focused, one concern each - calendar.ts, task.ts, settings.ts, etc.). Server state via TanStack Query. Command palette (cmdk) commands live in src/lib/commands/.
SAAS vs Open Source (critical)
The private SAAS repo is the superset; the public open-source repo is generated from it via scripts/sync-repos.sh. Get this wrong and SAAS code leaks into the public repo.
- All SAAS-only code goes in
src/saas/. - Route groups:
src/app/(saas)/,src/app/(open)/,src/app/(common)/. - File-extension convention:
*.saas.ts(x)compile only in the SAAS build,*.open.ts(x)only in open-source, plain files in both.next.config.jsderivespageExtensionsfromNEXT_PUBLIC_ENABLE_SAAS_FEATURES. Always give files in(saas)/(open)an explicit.saas/.openextension so the wrong build doesn't compile them. - For divergent shared components, create
Component.saas.tsxandComponent.open.tsxside-by-side and pick via dynamic import keyed on the env var (seesrc/app/(common)/settings/page.tsx). - Feature-gate with
isSaasEnabled/isFeatureEnabled()fromsrc/lib/config.ts. - Do not use
.gitignoreto hide SAAS files - exclusions belong insync-repos.sh. - When adding a feature, decide whether it's open-source, SAAS-only, or core-with-premium-enhancement. If unsure, ask.
Conventions
- Prisma client: import the singleton
prismafrom@/lib/prisma. Nevernew PrismaClient(). Import Prisma types from@prisma/client. - Dates: use helpers in
@/lib/date-utils.tsfor all date work, includingnew Date()- don't reach fordate-fns/date-fns-tzdirectly. - Calendar DB access: go through
@/lib/calendar-db.ts. - Logging: use the
loggerfrom@/lib/logger, neverconsole.log. Define aLOG_SOURCEstring per file and pass it as the last arg:logger.error("msg", { error }, LOG_SOURCE). - API route handlers (Next 15):
paramsis a Promise -async function GET(req, { params }: { params: Promise<{ id: string }> }) { const { id } = await params; }. - Admin-only: API routes use
requireAdminmiddleware from@/lib/auth/api-auth(do not callgetServerSessionand check role by hand); UI uses theuseAdminhook or<AdminOnly>wrapper with<AccessDeniedMessage>. - shadcn/ui: add components with
npx shadcn@latest add. Icons viareact-icons. - JSX text: escape quotes/apostrophes as
'/". - Keep changes minimal and scoped; don't refactor unrelated code. Don't remove
//todocomments; add them for deferred work. - Update
CHANGELOG.mdunder[unreleased]as you make user-facing changes.
Layout reference
src/services/scheduling/- task auto-scheduling enginesrc/lib/- providers, auth, date utils, config, commands, task-sync, db helperssrc/store/- Zustand storessrc/components/- feature-foldered UI (calendar, tasks, settings, auth, ...)src/app/api/- route handlersprisma/schema.prisma- Postgres schema (27 models; auth, calendar, tasks, settings, jobs, waitlist, subscriptions)src/saas/jobs/- BullMQ background jobs (SAAS, separate worker process)
<!-- mulch:start -->Project Expertise (Mulch)
<!-- mulch-onboard-v:1 -->This project uses Mulch for structured expertise management.
At the start of every session, run:
mulch primeThis injects project-specific conventions, patterns, decisions, and other learnings into your context.
Use mulch prime --files src/foo.ts to load only records relevant to specific files.
Before completing your task, review your work for insights worth preserving — conventions discovered, patterns applied, failures encountered, or decisions made — and record them:
mulch record <domain> --type <convention|pattern|failure|decision|reference|guide> --description "..."Link evidence when available: --evidence-commit <sha>, --evidence-bead <id>
Run mulch status to check domain health and entry counts.
Run mulch --help for full usage.
Mulch write commands use file locking and atomic writes — multiple agents can safely record to the same domain concurrently.
Before You Finish
- Discover what to record:
mulch learn - Store insights from this work session:
mulch record <domain> --type <convention|pattern|failure|decision|reference|guide> --description "..." - Validate and commit:
mulch sync
<!-- mulch:end -->In this repository12 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/main-rule.mdcCursor rule
- implement-github-issueSkill
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-exploreSkill
- openspec-proposeSkill
- review-merge-port-prSkill
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-exploreSkill
- openspec-proposeSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

