Open-source B2B CRM: leads, deals, pipelines, forecasting and outreach.
An open alternative to Salesforce Sales Cloud and HubSpot Sales Hub.
Features · Install · How it works · Development · Design · Build brief
A complete B2B CRM for a sales team of 5 to 100.
This is a Zite solution, meaning a workspace you install into your own Zite account and then edit. Zite provides the Postgres database, the endpoint runtime, auth and hosting. Everything above that is the ~64,000 lines of TypeScript in this repository.
Two apps share one database:
| App | Directory | Who it's for | Access |
|---|---|---|---|
| CRM | apps/crm |
The sales team: admins, managers, reps and read-only viewers | Internal (organization members) |
| CRM Pages | apps/crm-pages |
Prospects and customers: web forms, meeting booking, quotes, unsubscribe | External (public) |
A fresh install opens empty, with a starter pipeline and pick lists ready for your own records. To see it with work in it first, an admin can load a sample organization from the bottom of Settings → General: Ashgrove Software, with 36 companies, about 60 contacts, about 70 deals across two pipelines and six months of activity. Settings → Sample data removes it again.
-
Leads. an inbox of inbound and prospected people, scored and routed to a rep, worked through a one-at-a-time review deck, and converted into a company, a contact and a deal in one step.
-
Deals. pipelines with stages you configure, a board you drag deals across, a sortable ledger, weighted forecasting, stalled-deal warnings, and a next step on every open deal.
-
Companies and contacts. the records everything hangs off, with a timeline of every call, email, meeting and note, duplicate detection and merge, and custom fields per object.
-
Activities and tasks. log a call in two keystrokes; a task queue that opens on what's due today; a meeting agenda; an activity log for the team.
-
Quotes and products. a price book, line items that set a deal's amount, a quote builder, a PDF, and a public link the buyer accepts or declines.
-
Outreach. email templates with merge fields, multi-step sequences that send and create tasks on a schedule, web forms that create leads, and public meeting links that book straight into the CRM.
-
Reports. pipeline, forecast against quota, activity, lead conversion and team attainment, all computed in SQL.
-
Automations. "when this happens, do that" rules over deals, leads, forms, meetings and quotes, with a run log.
-
Admin. teammates and roles, teams, pipelines and stages, custom fields, pick lists and tags, lead routing, CSV import with undo, export, and sample data you can load into an empty workspace and remove again.
-
AI assists (optional). A written brief on where a deal stands, email drafts, and follow-up tasks pulled out of meeting notes. Every one of them falls back to a non-AI version when no Anthropic connection is attached.
Nothing is loaded automatically. The first person to open a fresh install becomes its Admin and lands in an empty CRM with a starter "Sales" pipeline and the standard lost, disqualify and lead-source lists, so the first deal can be created straight away.
While the workspace has no companies, contacts, deals or leads of its own, the bottom of Settings → General offers to load Ashgrove Software, a B2B software seller in Portland: 36 companies, about 60 contacts, about 70 deals across two pipelines, six months of activity, tasks, leads, quotes, sequences, meeting links and reports. Everything is generated from a fixed seed and dated relative to today, and the admin who loads it is given a real slice of the work. It never overwrites an organization name, address or footer you have already set.
Settings → Sample data → Remove sample data (in the nav only while the sample is loaded) deletes all of it when a real team is ready to start. It keeps everything that was there before the sample was loaded and anything added since, and once the workspace is empty again the sample can be loaded again.
Zite apps are built by pointing a coding agent at the platform over MCP, and installing one works the same way.
1. Connect the Zite MCP server to your agent.
claude mcp add --transport http zite https://mcp.zite.com/mcp(Cursor, VS Code and any other MCP client work the same way. See the Zite quickstart.)
2. Give it this prompt.
Install https://github.com/zite/crm into a new Zite workspace.
create_workspacenamed "CRM", thencreate_sandboxon it.- In the sandbox, add this repo as a git remote and check its files out over
/workspace, keeping the sandbox's ownzite.config.json.- Read
zite.schema.jsonand create all 33 tables withcreate_table, passing each field'sdefinition(name,type,template) straight through. Do this beforecreate_app, becausecreate_appandcheck_apprefreshzite.schema.jsonfrom the live database, and would otherwise blank it.create_app"CRM" (internal) and "CRM Pages" (external). Use those names exactly: the directory is derived from the name, and these two produceapps/crmandapps/crm-pages, which is what this repo already uses.- Run
yarn install, so the workspace packages are linked and@project/sharedresolves.check_appboth apps,commit, thenpublish_appboth.
3. Open the CRM. It opens empty, and you are its Admin. To look around with records in it first, load the sample organization from the bottom of Settings → General; when you are ready for real data, remove it from Settings → Sample data, which deletes everything the sample created and keeps anything you have added.
A Zite workspace is one database with one or more apps on top of it. The split that matters:
| Part | Where it runs |
|---|---|
apps/*/src/ minus api/ |
The browser. A normal Vite + React SPA. |
apps/*/src/api/*.ts |
Zite's endpoint runtime, server-side. One file = one endpoint. |
packages/* |
Imported by both. No build step; consumed as TypeScript source. |
.zite/ |
Generated clients: typed DB access and a typed caller. Never edited by hand. |
The frontend never touches the database. It calls endpoints through a generated
typed client (import { listDeals } from 'zitejs/api'), and endpoints reach the
database through another (import { zite } from 'zitejs/db'). 128 endpoints: 117
in the CRM and 11 serving the public pages.
Where to look:
- DESIGN.md is the design language: density, tokens, vocabulary, patterns. Read it before touching the UI.
- BRIEF.md is how the code is organised, the platform's runtime rules (SQL identifiers, unset text, rate limits) and the server engine.
packages/sharedholds the rules used by both apps and every endpoint: money, dates, roles, merge fields, deal and quote arithmetic, and the server engine (server/deals.ts,activities.ts,tasks.ts,events.ts,notify.ts,email.ts,automations.ts,sequences.ts).apps/crm/src/ui,glyphs,pickers,records,timelineare the kit every screen is built from.scripts/check-contrast.mjsmeasures every colour pair in both themes. Run it after any palette change.
yarn install
cp .env.example .env.local # then put your own workspace id in it
yarn dev # the CRM on :8080
yarn dev:crm-pages # public pages on :8081What works offline: the whole frontend, tsc, and vite build. Editing a
component hot-reloads.
What does not: the endpoints in src/api/ execute on Zite's runtime against
your workspace database, not on your machine. yarn dev serves the UI, but every
endpoint call goes out to the workspace named in .env.local and needs a session
for that organization. There is no local database mode yet.
Run yarn generate after adding, renaming or deleting an endpoint.
yarn run check # tsc + endpoint bundling + vite build, both appsNote. On an app this size
zitejs checkprintsbundle endpoints ✗with no error and exits non-zero. That is a 1 MB stdout buffer in the checker, not a real failure. To see genuine endpoint errors, bundle to a file instead:npx zitejs bundle --app crm > /tmp/b.jsonand readendpointErrors.
React 18 · TypeScript · Vite · Tailwind CSS 3 · shadcn/ui · Radix · TanStack Query & Table · Recharts · dnd-kit · date-fns · zod · zitejs (database, endpoints, auth, email, PDF, uploads, schedules) · Claude for the optional AI assists.
Issues and pull requests are welcome. See CONTRIBUTING.md, and read DESIGN.md before changing UI. Anything security-related goes to SECURITY.md instead of a public issue.

