For Developers

How to clone, run, and extend HotCRM — for engineers building customisations.

For Developers

This page is for engineers. End users and admins can skip it.

Prerequisites

  • Node.js 20+
  • pnpm 9+ (workspace package manager)
  • A clone of the objectstack-ai/hotcrm repository

Setting up locally

git clone https://github.com/objectstack-ai/hotcrm.git
cd hotcrm
pnpm install
pnpm dev

Open http://localhost:3000 — the app boots with seed data the first time you sign up.

What's in the repo

hotcrm/
├── packages/             # Business capability packages
│   ├── crm/              # Sales objects, flows, sharing, approvals
│   ├── finance/          # Contracts, revenue
│   ├── products/         # Product catalog
│   ├── service/          # Cases, knowledge base
│   ├── marketing/        # Campaigns
│   └── ai/               # Copilot agents, skills, knowledge bases
└── apps/
    ├── crm/              # The CRM application
    └── docs/             # This documentation site

Each package follows the file suffix protocol:

SuffixDefines
*.object.tsData model
*.hook.tsServer-side lifecycle logic
*.action.tsAPI endpoints / AI-callable tools
*.flow.tsMulti-step automation
*.skill.tsAI skill
*.agent.tsComposite AI agent
*.page.tsUI page layout
*.view.tsList view
*.dashboard.tsDashboard
*.sharing.tsSharing rule
*.approval.tsApproval process
*.statemachine.tsState transitions

Core platform: ObjectStack

HotCRM runs on @objectstack/runtime — a metadata-first runtime that handles persistence, sharing, validation, automation, and AI. We don't modify the runtime; we define metadata that the runtime executes.

Key concepts:

  • Objects are TypeScript files (no YAML, no JSON, no UI clicking).
  • ObjectQL is the data-access API — broker.find('crm_opportunity', {...}) instead of SQL.
  • Hooks fire on lifecycle events (before_create, after_update, etc.).
  • Flows orchestrate multi-step business logic visually defined in TS.
  • Every metadata file is validated at compile time against @objectstack/spec schemas.

Common tasks

Add a field to an existing object

// packages/your-extension/src/opportunity.object.ts
import { defineObject, Field, ObjectSchema } from '@objectstack/spec/data';

export default ObjectSchema.parse(defineObject({
  name: 'crm_opportunity',
  extends: 'crm.opportunity',
  fields: {
    custom_priority: Field.select({
      options: [
        { value: 'a', label: 'A' },
        { value: 'b', label: 'B' },
      ],
    }),
  },
}));

➜ Full guide: Extending Objects

Add an AI skill

// packages/your-extension/src/your_skill.skill.ts
import { defineSkill } from '@objectstack/spec/ai';

export default defineSkill({
  name: 'your_skill',
  // ...
});

➜ Full guide: Building AI Skills

Customise a page

// packages/your-extension/src/opportunity.page.ts
import { definePage, PageSchema } from '@objectstack/spec/ui';

export default PageSchema.parse(definePage({
  object: 'crm_opportunity',
  // ...
}));

➜ Full guide: UI Extensions

Validating your changes

pnpm typecheck       # validates all metadata against @objectstack/spec
pnpm test            # unit tests
pnpm lint            # code style
pnpm build           # full build

CI runs the same checks on every PR.

Where to keep customisations

Add a new package under packages/ rather than editing core packages. This keeps you upgradable when HotCRM ships updates.

packages/
  acme-crm-extension/    # your customisations

Your package can extends: any core object, register new skills against the existing Copilot, and add pages/views/dashboards alongside the built-in ones.

Where to go next

On this page