Instruction manual
calcom/cal.diy instruction manual
MIT-licensed, community-maintained self-hosted scheduling platform forked from Cal.com with commercial and enterprise code removed; it includes a Next.js web app, NestJS API v2, PostgreSQL/Prisma data layer, booking embeds, calendar and conferencing integrations, Docker deployment materials, and repository-local spec and engineering-rule documents intended to guide Claude during development, but no distributable Claude Code plugin, skill, hook, MCP server, or command is evidenced.
1. Purpose, scope, support level, and Claude Code classification
Cal.diy is the community-maintained, self-hosted scheduling application derived from Cal.com after the documented enterprise/commercial code was removed. The supplied README describes it as entirely MIT-licensed, requiring no Cal.com account or license for the main application, and having no managed Cal.diy service. Documented removed features include Teams, Organizations, Insights, Workflows, and SSO/SAML; use Cal.com rather than Cal.diy when commercial or enterprise-ready scheduling infrastructure is required.
Treat Cal.diy as personal, non-production software unless you independently establish that it meets your needs. Its own warning says operation requires advanced server administration, PostgreSQL management, secret handling, backups, upgrades, and security knowledge. The main stack is TypeScript with Next.js, React, tRPC, Tailwind CSS, Prisma, PostgreSQL, and Daily.co.
**Claude Code classification:** repository-local context injection, attached to a standalone application—not a native Claude Code plugin. Evidence supports this mechanism because feature folders contain `CLAUDE.md`, design and progress files that Claude is expected to read, while `agents/` supplies machine-readable engineering rules. No plugin manifest, hook, MCP server, skill installer, marketplace package, or minimum Claude Code version is documented. The product itself runs independently of Claude Code.
The public metadata identifies `calcom/cal.diy`, default branch `main`, with an MIT license. Some supplied files retain Cal.com-oriented material: notably, the API v2 development notes require a zero UUID license-key record even though the root README says no license is required. Follow that API-specific local-development procedure only when working on API v2; it does not establish an enterprise entitlement or a general deployment requirement.
2. Development installation and database initialization
Prerequisites are Node.js 18 or newer, PostgreSQL 13 or newer, and preferably Yarn. Clone and enter the repository, then install workspace packages:
git clone https://github.com/calcom/cal.diy.git
cd cal.diy
yarnOn Windows, the documented clone variant is `git clone -c core.symlinks=true https://github.com/calcom/cal.diy.git` in an administrator Git Bash. Duplicate `.env.example` as `.env`. Generate `NEXTAUTH_SECRET` with `openssl rand -base64 32` and `CALENDSO_ENCRYPTION_KEY` with `openssl rand -base64 24`, then place the results in `.env`. Windows users may replace Prisma’s environment symlink:
rm packages/prisma/.env && cp .env packages/prisma/.envSelect the repository’s Node version with `nvm use`; if absent, use `nvm install && nvm use`. The fastest development path requires Docker and Docker Compose:
yarn dxIt starts local PostgreSQL and seeds test users, including `free@example.com`/`free`, `pro@example.com`/`pro`, and `admin@example.com`/`ADMINadmin2022!`; use these only in local development. The app is at `http://localhost:3000`. Inspect all seeded records with `yarn db-studio` at `http://localhost:5555`.
For manual setup, put a PostgreSQL URL such as `postgresql://postgres:postgres@localhost:5432/Your-DB-Name` in `.env` and copy it to `.env.appStore`. Apply development migrations with:
yarn workspace @calcom/prisma db-migrate
yarn devProduction schema deployment uses `yarn workspace @calcom/prisma db-deploy`. To seed manually, run `cd packages/prisma` followed by `yarn db-seed`. Alternatively, create a user in Prisma Studio with `email`, `username`, a BCrypt-hashed `password`, and `metadata` set to `{}`; new users default to the `TRIAL` plan.
3. Runtime configuration, logging, email preview, and security controls
`DATABASE_URL` is required and may point to a connection pooler. `NEXT_PUBLIC_WEBAPP_URL` defaults to `http://localhost:3000`; `NEXTAUTH_URL` identifies the authentication endpoint and defaults conceptually to `{NEXT_PUBLIC_WEBAPP_URL}/api/auth`. `NEXTAUTH_SECRET` and the 32-byte AES256 `CALENDSO_ENCRYPTION_KEY` are required and must match their build-time values. Never retain the documented `secret` placeholder in a real deployment.
Control tRPC query and mutation logging with `NEXT_PUBLIC_LOGGER_LEVEL`: 0 silly, 1 trace, 2 debug, 3 info, 4 warn, 5 error, or 6 fatal. A selected level includes that level and all more severe levels. For info and above:
echo 'NEXT_PUBLIC_LOGGER_LEVEL=3' >> .envFor a memory-hungry development build, the README suggests setting `NODE_OPTIONS="--max-old-space-size=16384"`, adjusting the number to available RAM. Build-time `MAX_OLD_SPACE_SIZE` defaults to 4096. Set `CALCOM_TELEMETRY_DISABLED=1` to disable documented anonymous usage collection.
For development email capture when `E2E_TEST_MAILHOG_ENABLED` is `1`:
docker pull mailhog/mailhog
docker run -d -p 8025:8025 -p 1025:1025 mailhog/mailhogEmail templates live under `packages/emails`: `components` contains reusable pieces and `templates` contains message types. `renderEmail(templateName, props)` renders a named template from `templates/index.ts`; the supplied example passes translation, sender, recipient, team name, and join URL. Developers may preview HTML through `apps/web/pages/api/email.ts` after changing it to the template under development.
Enable the documented CSP mode with `CSP_POLICY="non-strict"`. It applies strict CSP except `unsafe-inline` in `style-src`; enforcement is currently limited to login, other SSR pages are report-only, and SSG is unsupported. `NODE_TLS_REJECT_UNAUTHORIZED=0` is documented only for trusted SSL-terminating load balancers; it disables TLS certificate rejection and should not be a general fix.
4. Docker operation, updating, source builds, and hosted deployment links
For Compose deployment, clone recursively, enter the project, copy the environment template, and replace required secrets:
git clone --recursive https://github.com/calcom/cal.diy.git
cd cal.diy
cp .env.example .env
docker compose pull
docker compose up -dThe full stack includes PostgreSQL, the web app, and Prisma Studio. With a configured remote `DATABASE_URL`, `docker compose up -d calcom studio` starts the app and Studio, while `docker compose up -d calcom` starts only the app. Remove `-d` for attached debugging. Visit `http://localhost:3000` or `NEXT_PUBLIC_WEBAPP_URL`; the first-run wizard creates the first user. The calendar step can be deferred by opening `<NEXT_PUBLIC_WEBAPP_URL>/event-types`, then adding calendars later under Settings > Integrations.
Generate push-notification credentials when VAPID keys are missing:
npx web-push generate-vapid-keysStore its public and private values as `NEXT_PUBLIC_VAPID_PUBLIC_KEY` and `VAPID_PRIVATE_KEY`; do not commit real keys. ARM image tags use the documented `{version}-arm` suffix.
To update an image-based installation:
docker compose down
docker compose pull
docker compose up -dFor a source image build, configure `.env` and an available database. A temporary local database can be started with `docker compose up -d database`, then build with:
DOCKER_BUILDKIT=0 docker compose build calcomThe documentation says disabling BuildKit is presently required for a build-time network bridge. Run the resulting services with the same Compose commands above.
First-party README links also expose Railway, Northflank, Vercel, Render, and Elestio deployment buttons. Vercel reportedly requires its Pro plan because of the number of serverless functions. Those services have separate operational and billing terms; the supplied files do not document their full procedures.
5. Calendar, conferencing, CRM, and rate-limit integrations
Integrations are optional and require provider credentials. For Google Calendar, enable Google Calendar API, configure an Internal or External OAuth consent screen, add `calendar.events` and `calendar.readonly`, and add test users. Create a Web Application OAuth client with both `<Cal.diy URL>/api/integrations/googlecalendar/callback` and `<Cal.diy URL>/api/auth/callback/google`. Put the downloaded JSON string in `GOOGLE_API_CREDENTIALS`. Repopulate the app store with:
cd packages/prisma
yarn seed-app-storePublishing the Google consent app is additionally documented for activation.
For Microsoft, create a multitenant Azure app registration with `<Cal.diy URL>/api/integrations/office365calendar/callback`; map its application ID and secret to `MS_GRAPH_CLIENT_ID` and `MS_GRAPH_CLIENT_SECRET`. For Zoom, create a non-marketplace, user-managed General App, set `<Cal.diy URL>/api/integrations/zoomvideo/callback` as redirect and allow-list URL, enable subdomain checking, and grant `meeting:write:meeting` plus `user:read:settings`; store `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET`.
Daily video requires `DAILY_API_KEY`; Daily Scale users may set `DAILY_SCALE_PLAN=true` for features such as recording. Basecamp 4 uses `<Cal.diy URL>/api/integrations/basecamp3/callback` and the `BASECAMP3_CLIENT_ID`/`BASECAMP3_CLIENT_SECRET` fields; the supplied text also says to format the secret environment variable as `{your_domain} ({support_email})`, an unusual instruction that should be verified against the provider before use.
HubSpot uses a public legacy app, `<Cal.diy URL>/api/integrations/hubspot/callback`, `HUBSPOT_CLIENT_ID`, `HUBSPOT_CLIENT_SECRET`, and read/write scopes for `crm.objects.contacts` and `crm.lists`; documented bookings become HubSpot meetings. Zoho CRM uses a server-based app, callback `/api/integrations/zohocrm/callback`, corresponding client variables, and optional Multi-DC. Separate package READMEs—not supplied here—are referenced for Webex, Zoho Calendar, Zoho Bigin, and Pipedrive, so no further steps are asserted. Optional Unkey rate limiting requires `UNKEY_ROOT_KEY` with `ratelimit.create_namespace` and `ratelimit.limit`; without it, rate limiting is disabled.
6. Embedding calendars and optimizing embedded booking flows
The embed system offers inline, modal, and floating-button presentation. `Cal.inline({ elementOrSelector, calLink })` places booking UI in the page; `Cal.modal({ calLink, config })` opens a dialog; `Cal.floatingButton({ calLink, buttonText, buttonPosition })` adds a button backed by modal behavior. Copy-paste forms documented by the repository include:
Cal.inline({
elementOrSelector: "#my-cal-inline",
calLink: "organization/event-type"
});Configuration can prefill `name`, `email`, and `notes`, and set `useSlotsViewOnSmallScreen: "true"`. To forward parent-page query parameters, place this immediately after the embed snippet:
Cal.config = Cal.config || {};
Cal.config.forwardQueryParams=trueEnable parent and iframe diagnostics by visiting the containing page with `?cal.embed.logging=1`. Internally, a global `Cal` entry point initializes `cal-modal-box`, `cal-floating-button`, and `cal-inline`; namespaced events isolate multiple embeds, and commands queue until the iframe is ready.
Preloading only warms static assets. Prerendering continues with a hidden iframe intended for later booking and currently supports modal use:
Cal("prerender", {
calLink,
type: "modal"
});For router-based flows, prerender only fields needed by routing rules, set an appropriate `pageType` such as `team.event.booking.slots`, and later open it with a `data-cal-link` button. Namespaced flows use `Cal.ns.myNamespace('prerender', ...)` plus `data-cal-namespace="myNamespace"`.
Reuse chooses among no action, reconnect without slot fetch, reconnect with slot fetch, and full reload. Path changes, failed state, or the force-reload age trigger a reload; configuration/query changes and slot staleness influence reconnect behavior. Skeletons support responsive/mobile and month views, dark/light themes, and slot pages; week, column, user-profile, and team-profile support is marked incomplete. Reusing the same modal iframe is documented as disabled because of stale UI.
7. API v2 and its local development conventions
`apps/api/v2` is a Nest.js project. Install dependencies, run Docker, and start MailHog from the email package:
yarn install
cd packages/emails && yarn dxCopy `apps/api/v2/.env.example` to `apps/api/v2/.env`. `NEXTAUTH_SECRET` must be identical there and in root `.env`. The API-specific notes require a `Deployment` database row with ID 1, null logo/theme, license key `00000000-0000-0000-0000-000000000000`, and the stated agreement timestamp, plus `CALCOM_LICENSE_KEY` set to that UUID. This is documented for local API v2 setup despite the root project’s no-license claim.
Optional Prisma preparation is:
cd packages/prisma
yarn prisma generate
yarn prisma migrate dev
yarn db-seedStart API v2 with `yarn dev`. If unrelated build changes cause restarts, build and run without watch mode using `cd apps/api/v2`, `yarn dev:build`, then `yarn start`. Because API v2 depends on platform libraries, constants, enums, utilities, and types, run `yarn run dev:build:watch` in another terminal to rebuild them. `yarn dev:no-docker` is the documented alternative when Docker is not wanted.
API v2 tests are `yarn run test`, `yarn run test:e2e`, `yarn run test:e2e some-file.e2e-spec.ts` for one watched E2E file, and `yarn run test:cov` for coverage.
Guard conventions are explicit: throw `ForbiddenException` with the guard name and error instead of returning false; never Redis-cache denied results, but successful access results may be cached. When `ApiAuthGuard` must accept only selected methods, add `@ApiAuthGuardOnlyAllow(["API_KEY"])` beneath `@UseGuards(ApiAuthGuard)`. Omitting the decorator, passing nothing, or passing an empty array allows all authentication methods.
8. Testing, diagnostics, upgrades, and release maintenance
Set local `NEXTAUTH_URL` to `http://localhost:3000` for browser E2E tests, then run:
yarn test-e2e
yarn playwright show-report test-results/reports/playwright-html-reportIf Playwright browsers are absent, the documented repair is `npx playwright install`. Web unit and integration tests require copying `.env.test.example` to `.env.test`. Run all Jest tests with `yarn test`, match a description with `yarn test -t getSchedule`, and add `--watchAll` to rerun on changes.
Checkly tests use `yarn checkly test`; `yarn checkly test --record` records a detailed Checkly UI view, `yarn checkly test {filePattern}` limits execution, and `yarn checkly deploy` deploys checks. These operations may interact with Checkly according to its configured environment.
For a non-Compose source upgrade:
git pull
yarn
yarn workspace @calcom/prisma db-migrate
yarn predev
yarn devUse `db-deploy` rather than `db-migrate` in production; development migration can sometimes clear the development database. `yarn predev` checks environment-variable changes. Production application startup is documented as `yarn build` followed by `yarn start`.
Troubleshooting: an empty Prisma user `metadata` may break creation in some versions; use `{}` and leave auto-incrementing `id` blank. A container `CLIENT_FETCH_ERROR` caused by host DNS may be corrected with `NEXTAUTH_URL=http://localhost:3000/api/auth`. On PowerShell, if Turbo fails to inject `DATABASE_DIRECT_URL`, the README supplies a direct Prisma-package workaround using explicit `DATABASE_URL` and `DATABASE_DIRECT_URL`, followed by `npx prisma db push`; substitute the real password before use.
Embed package releases use Changesets: `yarn changeset`, then `yarn changeset version`, review and merge the PR, then `yarn publish-embed`. The repository says the custom publisher is needed because ordinary Changesets publishing does not remove workspace prefixes.
9. Spec-first Claude workflow, engineering rules, and contribution boundaries
Start a feature specification by copying the template:
cp -r specs/_templates specs/{feature-name}Ask Claude to review the codebase and fill `specs/{feature}/design.md`. Each feature folder documents Claude-specific context in `CLAUDE.md`, the source-of-truth design in `design.md`, progress and blockers in `implementation.md`, architecture decisions in `decisions.md`, reusable requests in `prompts.md`, deferred work in `future-work.md`, and screenshot-backed internal documentation under `docs/`. A later session can be prompted with `Continue working on {feature}` so it reads the progress file.
The documented prompt `Generate docs with screenshots for {feature}` asks Claude to open the feature, capture key UI states, save them below `specs/{feature}/docs/screenshots/`, and update the feature docs README. `Promote {feature} docs to public` is documented to copy content into `docs/{feature}.mdx`, move images under `docs/images/{feature}/`, update `docs/mint.json`, and rewrite for customers. These are natural-language Claude workflows, not shell commands, and their effectiveness depends on the available Claude Code tools and permissions.
Keep each PR focused and reviewable in under ten minutes: the spec guide sets a target of 5–7 changed files excluding tests and at most 500 changed lines; split larger work. The `agents/` index organizes architecture, quality, data, API, performance, testing, CI/CD, patterns, culture, and reference rules. Rule files use YAML metadata for title, impact, optional impact description, and tags, followed by rationale, incorrect/correct TypeScript examples, and optional references. To add a rule, copy `_template.md`, choose the proper section prefix, complete metadata and explanation, add contrasting examples, and add a reference where applicable.
Contributions—including fixes, documentation, features, translations, and help-wanted issues—go to this community fork and do not flow into Cal.com production. Follow the linked `CONTRIBUTING.md` for standards and commit conventions; its contents were not supplied, so this manual does not infer additional commands.