CLAUDE.md and GEMINI.md
This file provides guidance to Claude Code (claude.ai/code) and also Gemini CLI (https://github.com/google-gemini/gemini-cli) when working with code in this repository.
CoCalc Source Repository
This is the source code of CoCalc in a Git repository
It is a complex JavaScript/TypeScript SaaS application
CoCalc is organized as a monorepository (multi-packages) in the subdirectory "./packages"
The packages are managed as a pnpm workspace in "./packages/pnpm-workspace.yaml"
Code Style
Everything is written in TypeScript code
Indentation: 2-spaces
Run
pretter -w [filename]
after modifying a file (ts, tsx, md, json, ...) to format it correctly.All .js and .ts files are formatted by the tool prettier
Add suitable types when you write code
Follow DRY principles!
Variable name styles are
camelCase
for local andFOO_BAR
for global variables. React Components and Classes areFooBar
. If you edit older code not following these guidlines, adjust this rule to fit the files style.Some older code is JavaScript or CoffeeScript, which will be translated to TypeScript
Use ES modules (import/export) syntax, not CommonJS (require)
Organize the list of imports in such a way: installed npm packages are on top, newline, then are imports from @cocalc's code base. Sorted alphabetically.
Colors: Always use the
COLORS
dictionary from@cocalc/util/theme
for all color values. Never hardcode colors like#f0f0f0
orrgb(...)
. Import withimport { COLORS } from "@cocalc/util/theme";
and use predefined constants likeCOLORS.GRAY_M
,COLORS.GRAY_L
,COLORS.GRAY_LL
, etc.Backend Logging: Use
getLogger
from@cocalc/project/logger
for logging in backend code. Do NOT useconsole.log
. Example:const L = getLogger("module:name").debug;
Development Commands
Essential Commands
pnpm build-dev
- Build all packages for developmentpnpm clean
- Clean allnode_modules
anddist
directoriespnpm test
- Run full test suitepnpm depcheck
- Check for dependency issuespython3 ./scripts/check_npm_packages.py
- Check npm package consistency across packagesprettier -w [filename]
to format the style of a file after editing itafter creating a file, run
git add [filename]
to start tracking it
Package-Specific Commands
cd packages/[package] && pnpm build
- Build and compile a specific packagefor packages/next and packages/static, run
cd packages/[package] && pnpm build-dev
cd packages/[package] && pnpm test
- Run tests for a specific packagecd packages/[package] && pnpm build
- Build a specific packageTo typecheck the frontend, it is best to run
cd packages/static && pnpm build
- this implicitly compiles the frontend and reports typescript errorsIMPORTANT: When modifying packages like
util
that other packages depend on, you must runpnpm build
in the modified package before typechecking dependent packages
Development
IMPORTANT: Always run
prettier -w [filename]
immediately after editing any .ts, .tsx, .md, or .json file to ensure consistent stylingAfter TypeScript or
*.tsx
changes, runpnpm build
in the relevant package directoryWhen editing the frontend, run
pnpm build-dev
inpackages/static
. This implicitly builds the frontend!
Architecture Overview
Package Structure
CoCalc is organized as a monorepo with key packages:
frontend - React/TypeScript frontend application using Redux-style stores and actions
backend - Node.js backend services and utilities
hub - Main server orchestrating the entire system
database - PostgreSQL database layer with queries and schema
util - Shared utilities and types used across packages
comm - Communication layer including WebSocket types
conat - CoCalc's container/compute orchestration system
sync - Real-time synchronization system for collaborative editing
project - Project-level services and management
static - Static assets and build configuration
next - Next.js server components
Key Architectural Patterns
Frontend Architecture
Redux-style State Management: Uses custom stores and actions pattern (see
packages/frontend/app-framework/actions-and-stores.ts
)TypeScript React Components: All frontend code is TypeScript with proper typing
Modular Store System: Each feature has its own store/actions (AccountStore, BillingStore, etc.)
WebSocket Communication: Real-time communication with backend via WebSocket messages
Authentication Waiting: When frontend code needs to wait for user authentication, use
redux.getStore("account").async_wait({ until: () => store.get_account_id() != null, timeout: 0 })
to wait indefinitely until authentication completesConat DKV Usage: For key-value storage with real-time sync, use
webapp_client.conat_client.dkv({ account_id, name: "store-name" })
to get a distributed key-value store that syncs across sessions
Backend Architecture
PostgreSQL Database: Primary data store with sophisticated querying system
WebSocket Messaging: Real-time communication between frontend and backend
Conat System: Container orchestration for compute servers
Event-Driven Architecture: Extensive use of EventEmitter patterns
Microservice-like Packages: Each package handles specific functionality
Database Access: Use
getPool()
from@cocalc/database/pool
for direct database queries in hub/backend code. Example:const pool = getPool(); const { rows } = await pool.query('SELECT * FROM table WHERE id = $1', [id]);
Hub Migration Functions: Migration functions in hub should be designed to run once at startup, use batch processing with delays between batches to avoid database saturation
Communication Patterns
WebSocket Messages: Primary communication method (see
packages/comm/websocket/types.ts
)Database Queries: Structured query system with typed interfaces
Event Emitters: Inter-service communication within backend
REST-like APIs: Some HTTP endpoints for specific operations
API Schema: API endpoints in
packages/next/pages/api/v2/
use Zod schemas inpackages/next/lib/api/schema/
for validation. These schemas must be kept in harmony with the TypeScript types sent from frontend applications usingapiPost
(inpackages/next/lib/api/post.ts
) orapi
(inpackages/frontend/client/api.ts
). When adding new fields to API requests, both the frontend types and the API schema validation must be updated.Conat Frontend → Hub Communication: CoCalc uses a custom distributed messaging system called "Conat" for frontend-to-hub communication:
Frontend ConatClient (
packages/frontend/conat/client.ts
): Manages WebSocket connection to hub, handles authentication, reconnection, and provides API interfacesCore Protocol (
packages/conat/core/client.ts
): NATS-like pub/sub/request/response messaging with automatic chunking, multiple encoding formats (MsgPack, JSON), and delivery confirmationHub API Structure (
packages/conat/hub/api/
): Typed interfaces for different services (system, projects, db, purchases, jupyter) that map function calls to conat subjectsMessage Flow: Frontend calls like
hub.projects.setQuotas()
→ ConatClient.callHub() → conat request to subjecthub.account.{account_id}.api
→ Hub API dispatcher → actual service implementationAuthentication: Each conat request includes account_id and is subject to permission checks at the hub level
Subjects: Messages are routed using hierarchical subjects like
hub.account.{uuid}.{service}
orproject.{uuid}.{compute_server_id}.{service}
Key Technologies
TypeScript: Primary language for all new code
React: Frontend framework
PostgreSQL: Database
Node.js: Backend runtime
WebSockets: Real-time communication
pnpm: Package manager and workspace management
Jest: Testing framework
SASS: CSS preprocessing
Database Schema
Comprehensive schema in
packages/util/db-schema
Query abstractions in
packages/database/postgres/
Type-safe database operations with TypeScript interfaces
Testing
Jest: Primary testing framework
ts-jest: TypeScript support for Jest
jsdom: Browser environment simulation for frontend tests
Test files use
.test.ts
or.spec.ts
extensionsEach package has its own jest.config.js
Import Patterns
Use absolute imports with
@cocalc/
prefix for cross-package importsExample:
import { cmp } from "@cocalc/util/misc"
Type imports:
import type { Foo } from "./bar"
Destructure imports when possible
Development Workflow
Changes to TypeScript require compilation (
pnpm build
in relevant package)Database must be running before starting hub
Hub coordinates all services and should be restarted after changes
Use
pnpm clean && pnpm build-dev
when switching branches or after major changes
Workflow
Be sure to build when you're done making a series of code changes
Prefer running single tests, and not the whole test suite, for performance
Git Workflow
Never modify a file when in the
master
ormain
branchAll changes happen through feature branches, which are pushed as pull requests to GitHub
When creating a new file, run
git add [filename]
to track the file.Prefix git commits with the package and general area. e.g. 'frontend/latex: ...' if it concerns latex editor changes in the packages/frontend/... code.
When pushing a new branch to Github, track it upstream. e.g.
git push --set-upstream origin feature-foo
for branch "feature-foo".
Important Instruction Reminders
Do what has been asked; nothing more, nothing less.
NEVER create files unless they're absolutely necessary for achieving your goal.
ALWAYS prefer editing an existing file to creating a new one.
REFUSE to modify files when the git repository is on the
master
ormain
branch.NEVER proactively create documentation files (
*.md
) or README files. Only create documentation files if explicitly requested by the User.
React-intl / Internationalization (i18n)
CoCalc uses react-intl for internationalization with SimpleLocalize as the translation platform.
Architecture Overview
Library: Uses
react-intl
library withdefineMessages()
anddefineMessage()
Default Language: English uses
defaultMessage
directly - no separate English translation filesSupported Languages: 19+ languages including German, Chinese, Spanish, French, Italian, Dutch, Russian, Japanese, Portuguese, Korean, Polish, Turkish, Hebrew, Hindi, Hungarian, Arabic, and Basque
Translation Platform: SimpleLocalize with OpenAI GPT-4o for automatic translations
Translation ID Naming Convention
Translation IDs follow a hierarchical pattern: [directory].[subdir].[filename].[aspect].[label|title|tooltip|...]
Examples:
labels.masked_files
- for common UI labelsaccount.sign-out.button.title
- for account sign-out dialogcommand.generic.force_build.label
- for command labels
Usage Patterns
TSX Components:
<FormattedMessage id="..." defaultMessage="..." />
Data Structures:
defineMessage({id: "...", defaultMessage: "..."})
Programmatic Use:
useIntl()
hook +intl.formatMessage()
Non-React Contexts:
getIntl()
function
Translation Workflow
For new translation keys:
Add the translation to source code (e.g.,
packages/frontend/i18n/common.ts
)Run
pnpm i18n:extract
- updatesextracted.json
from source codeRun
pnpm i18n:upload
- sends new strings to SimpleLocalizeNew keys are automatically translated to all languages
Run
pnpm i18n:download
- fetches translationsRun
pnpm i18n:compile
- compiles translation files
For editing existing translation keys: Same flow as above, but before 3. i18n:upload, delete the key. Only new keys are auto-translated. pnpm i18n:delete [id]
.
Translation File Structure
packages/frontend/i18n/README.md
- detailed documentationpackages/frontend/i18n/common.ts
- shared translation definitions (labels, menus, editor, jupyter, etc.)packages/frontend/i18n/extracted.json
- auto-extracted messages from source codepackages/frontend/i18n/trans/[locale].json
- downloaded translations from SimpleLocalizepackages/frontend/i18n/trans/[locale].compiled.json
- compiled translation files for runtimepackages/frontend/i18n/index.ts
- exports and locale loading logic
Ignore
Ignore files covered by
.gitignore
Ignore everything in
node_modules
ordist
directoriesIgnore all files not tracked by Git, unless they are newly created files
important-instruction-reminders
Do what has been asked; nothing more, nothing less. NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.