Everything Product 5 does today.
162 capabilities have shipped, and 31 have not.
Everyone you sell to and every business they belong to, deduplicated and linked.
- Contacts15
- Companies11
- Tags3
Contacts
15Everyone you sell to — searchable, owned, and never duplicated.
- Change hundreds of contacts at once
- Contact detail
- Contact list
- Contact owner
- Contact search
- Create contact
- Custom fields on a contact
- Delete contact
- Duplicate contact detection
- Edit contact
- Filter and sort by your own fields
- Merge two contacts
- Restore a deleted contact
- See where a contact came from
- Undo a contact merge
Companies
11The businesses behind your contacts, with their deals rolled up.
- Change hundreds of companies at once
- Company detail
- Company list
- Create company
- Delete company
- Duplicate company detection
- Edit company
- Link a contact to a company
- Merge two companies
- Restore a deleted company
- Undo a company merge
Tags
3Your own labels, on anything, with counts you can see.
- Manage tags
- Merge tags
- Tag a record
A board shaped to the way you sell, with the totals kept up to date for you.
- Deals14
- Pipelines and stages8
- Dashboard7
Deals
14Every opportunity on a board you can drag.
- Change hundreds of deals at once
- Close or reopen a deal
- Create deal
- Custom fields on a deal
- Deal detail
- Deal owner
- Deals kanban board
- Delete deal
- Edit deal
- Jump straight into a new deal
- Link a deal to a contact
- Move a deal between stages
- Restore a deleted deal
- Switch the board to a sortable table
Pipelines and stages
8Stages named the way your team actually sells.
- A starter pipeline on day one
- Add a stage
- Delete a stage
- Live totals on every stage
- Manage stages
- Rename or recolour a stage
- Reorder stages
- Run more than one pipeline
Dashboard
7What deserves attention today, the moment you sign in.
- Dashboard narrative
- Empty-workspace prompt
- Headline metrics
- Open tasks
- Pipeline by stage
- Recent activity feed
- Top open deals
What you owe people, what was said, and one keystroke to find any of it.
- Tasks8
- Notes and timeline4
- Notifications3
- Search3
Tasks
8What you owe people, and when you owe it.
- Assign a task
- Change hundreds of tasks at once
- Complete a task
- Create a task
- Delete a task
- Edit a task
- Keep a task that belongs to nobody
- Tasks hub
Notes and timeline
4Notes and calls, kept on the record they belong to.
- Activity panel in the deal sheet
- Activity timeline
- Add a note
- Remove a note
Notifications
3A nudge when something needs you, and silence when it does not.
- In-app notifications
- Notification preferences
- One daily email instead of many
Search
3Find any record in one keystroke.
- Command palette
- Global search
- Search with AI
Shape the CRM around your business without waiting on a release.
- Custom fields7
- Saved views and filters4
- Forms6
- Import and export3
Custom fields
7The fields your business runs on, added in a minute.
- Define a custom field
- Delete a custom field
- Edit a custom field
- Make a field compulsory
- Reorder custom fields
- Separate fields for contacts and deals
- Text, number, date, dropdown or checkbox
Saved views and filters
4Save a filter once and reuse it forever.
- Filter any list by any field
- Natural-language filter
- Save a filter and sort as a view
- Share a view with the workspace
Forms
6Collect leads from your own site, straight into the CRM.
- A ready-made page to share
- Form builder
- Send new leads to the right person
- Share or embed a form
- Spam held back for review
- Turn a submission into a contact automatically
Import and export
3Bring your data in, and take it out whenever you like.
- Export a filtered list to CSV
- Import contacts or companies from a CSV
- Preview an import before it writes anything
Build a workflow on a canvas, or just ask for what you want in plain English.
- Automations7
- Assistant16
Automations
7The follow-ups that happen whether anyone remembers or not.
- Branch on whatever matters
- Build a workflow on a canvas
- Nine things it can do for you
- See every run, and why it stopped
- Six ready-made workflows
- Start from anything that happens
- Test it safely before switching it on
Assistant
16Ask in plain English, and check the answer.
- AI record summaries
- Answers drawn from your live data
- Assistant chat
- Bring your own AI provider key
- Choose the model per message
- Conversation history
- Edit and resend a message
- Let it make the change for you
- Meeting notes capture
- One-tap prompts to start from
- Per-message feedback
- Point it at a specific deal or contact
- Retry when something goes wrong
- See exactly what it did
- See what each answer costs
- Try it before adding a key
Invite your team, decide who can change what, and keep a record of every change.
- Workspaces and members17
- Your account3
- Platform and security21
Workspaces and members
17Your team, their roles, and who owns what.
- Accept an invitation
- Archive a workspace
- Cancel an invitation
- Change a member’s role
- Create a workspace
- Invite a teammate by email
- Name your workspace and its URL
- Recover from signing in as the wrong person
- Remove a member
- Resend an invitation
- Restore a removed member
- Restore an archived workspace
- See your role and team size at a glance
- Switch active workspace
- Transfer ownership
- View team members
- Workspace deletion and erasure
Your account
3Your name, your password, your email address.
- Change email address
- Change password
- Edit display name
Platform and security
21The parts you should never have to think about.
- Brute-force protection on sign-in
- Changes can set off a workflow
- Data retention
- Delete your account
- Email verification
- Every change is recorded, permanently
- Forgotten password recovery
- Hardened against common browser attacks
- Long jobs run out of your way
- Owner, admin and member roles
- Personal data kept out of our logs
- Removing someone takes effect immediately
- Search the full history
- See what is queued and what failed
- Sign in
- Sign out
- Sign up
- Sign-up and invitation emails
- Signed-out visitors reach nothing
- Workspace changes always go through our checks
- Your data stays in your workspace
Building now
31Written and tested, but not claimable. Each one names what is missing.
Upload a file
File storage is not switched on yet.
Download a file
File storage is not switched on yet.
Delete a file
File storage is not switched on yet.
Preview a file
Blocked behind the same wall as every other files.* capability: nothing here has run against a real bucket, so no `files` row has ever been created for real and there is nothing to preview. (Note that this wall is lower than it was — a working set of S3_* credentials now exists in .env.local, which is why tests/integration/files.actions.test.ts’s "the repository itself ships with no S3_* configuration" assertion fails. The path is now reachable; it has still not been walked.) The specific unverified assumption this one adds is that R2 honours `response-content-disposition: inline` inside a presigned GET signature — the same mechanism `files.download` relies on for `attachment`, exercised in the opposite direction, and both have only ever run against a mocked storage layer. Promote this the same day `files.upload` is promoted.
Currency and regional format
Changing the currency RE-LABELS existing values, it does not convert them: a deal stored as 40000 reads as $40,000 or ₹40,000 depending only on this setting, and no exchange rate is applied anywhere. The setting is also per workspace and not per person — a member in another country sees their workspace’s number and date format, not their own — and there is no way to record which currency a deal was originally quoted in beyond its own `currency` column. The date locale reaches the surfaces swept in this change; a handful of secondary timestamps still render through a fixed `en-US` or the server’s default locale and need the same treatment — the audit log, the jobs page, import history, notification and task rows, the dashboard activity feed and open-tasks list, and the dates on the assistant’s inline record cards.
Build a dashboard by describing it
The assistant proposes from scratch and cannot refine — it never sees the dashboard you already have, so asking for "the same but add revenue" replaces everything rather than adding one card. It chooses widgets and sizes but not their options, so a proposed "Revenue won" follows the page period rather than one chosen for it. Nothing is remembered between proposals, so asking twice gives two unrelated dashboards. A workspace with no AI provider key gets a plain message rather than a proposal, which is correct but is only discovered after typing the request.
Widget dashboard
Two widgets from the design are still unbuilt: stage-to-stage conversion and deal sources (as distinct from lead sources). Forecast against target now exists as a per-card gauge, but the target lives on the card rather than on the workspace, so it is set again for every card that shows it. A card can be pointed at its own target or breakdown but not at its own period — no widget exposes a range field yet, so two copies of "Revenue won" still both follow the page range. The charts use the vendored evilcharts container with plain Recharts primitives; the vendored blocks themselves (monospace bars, hover-trace bars, grid bars, radial progress) are in the tree but nothing uses them yet.
Arrange your own dashboard
The tab strip cannot be reordered from the UI even though the action exists. The Add-widget gallery filters by whether a workspace has the data, but every widget currently answers yes, so nothing is hidden yet. Layouts are stored for the large breakpoint only — narrower screens reflow by reading order rather than keeping an arrangement of their own — and there is no way to hand a dashboard to a specific colleague, only to the whole workspace or to nobody. Resize has no multi-select and no align or distribute: cards are sized one at a time, and two cards meant to match are matched by eye or by picking the same preset.
Per-card settings
Only two widgets declare fields, and only two kinds of field exist — a number and a fixed list. No widget exposes its own period yet, so every card still follows the page range picker rather than holding one of its own. The target is a plain number with no currency formatting as you type it, and it is per card rather than per workspace, so two cards showing the same target hold two copies of it.
Latency readout
Never observed against a real OpenRouter key — every path here defaults to a direct Google key, so the upstream name on hover comes from the provider package's documented metadata rather than from a response anyone has watched arrive. The chip is also silent until a turn finishes: a fresh thread shows nothing, and the first answer of a session is the one whose speed nobody can see while waiting for it.
Tools found on demand
The non-Anthropic half was rebuilt once already. It first let the model search for a tool mid-answer, and real use showed that changing the tool list part-way through throws away everything the provider had cached for that conversation — on one thread the same question cost close to three times as much. It now ranks the tools before the answer starts and does not change them, which removes that cost and one whole model request with it. What is still unmeasured: the seven always-loaded tools were chosen from the assistant's own rules and from what a CRM is usually asked, not from a record of which tools actually get called, because no such record exists yet; the telemetry that would settle it ships with this and has no data behind it. Ranking before the answer also means a tool the conversation never hinted at cannot be reached that turn. That is no longer theoretical: asked to add demo records, a workspace on a routed model was told the product could not create deals or contacts — true of the tools that turn had been given, false of CRMS. Two things now bound it. Six tools are offered whatever the ranking returns — the create and open paths for contacts, deals and companies, plus the custom field definitions the standing rules order it to read before any custom-field write — and the model is told its list is partial so it stops reporting a missing tool as a missing feature. The sixth was added after custom fields turned out to be unreachable from chat for exactly this reason: a person asks to set a renewal date, which shares no word with a tool described as listing field definitions. A confidence threshold was tried first and abandoned, and the measurement is worth keeping: against the real catalogue a meaningless request scores ABOVE a genuine one, so no threshold divides them. The same failure is still possible for any tool outside those five, and how often it happens is unknown.
Daily message allowance
The number is a constant in the code, not a per-workspace setting, so a workspace that wants 20 or 500 cannot have it without a deploy. The sidebar meter shows the count everywhere, but it only counts down — nothing warns you at a threshold, so the last few messages look like all the others, and the assistant panel itself still says nothing until the turn is refused. There is no view anywhere of who has been using what, so an owner cannot see which member exhausted a shared key. The allowance is also the only thing bounding spend: 100 short questions and 100 long tool-heavy investigations cost the same here and are wildly different bills, so it caps requests rather than money.
Social sign-in
Google sign-in works; Apple is not built yet.
Operator console
There is no in-app way to grant or revoke the platform operator role. The first one is created by `npm run operator:create` (scripts/create-operator.ts) and every one after it still needs the same script or hand-written SQL, because the console shows accounts but never changes their platform role.
Structured logging
Events carry no automatic user or workspace identity: `evlog/better-auth` is not wired, because importing the auth instance into the logger closes an import cycle through `@/lib/log`, and evlog's documented alternative is an `identifyUser` call inside every wrapped handler. Nothing has been sent to a real Axiom dataset yet either, so the field names the Logs tab reads are taken from evlog's types rather than from an observed event. Errors also now leave the process on STDOUT rather than stderr, because evlog writes with `process.stdout.write` and calls no `console` method — any host or supervisor configured to treat the two streams differently will need its own configuration changed to match.
Operator log search
Never run against a live Axiom dataset, so the mapping from event fields onto the table columns is unverified — anything unmapped still appears in the raw-event panel, but a column may read as an em dash until the mapping is corrected. There is no live tail, no saved search and no alerting; Axiom's own interface does the last of those better.
Tenant list and operator actions
Audit rows written by ORDINARY customer actions during an impersonated session still name the customer as the actor, not the operator driving it: `WorkspaceContext.impersonatedBy` is populated and `recordAudit` accepts a matching field, but no domain passes one to the other yet, so the stamp reaches only the console's own ban and impersonate rows. Threading it through every domain's actions is a separate, cross-cutting change. Nothing here grants or revokes the platform operator role either — that is still done by SQL.
Cross-tenant AI usage
Reports tokens and never money: no per-model price table exists anywhere in CRMS, and under bring-your-own-key the provider bills each workspace directly, so any cost figure would be invented. The token numbers are also read out of the `assistant_messages.metadata` jsonb column with `->>`, which no index covers — correct today, and a sequential scan that will need a real `assistant_turn_usage` table once that table is large.
Privacy policy and terms
The pages render and every link resolves, but no lawyer has read a word of them. The copy is a plain-English template describing what the code does today, which is the only claim it is qualified to make — the liability, warranty and governing-law paragraphs in the terms are generic placeholders, and there is no jurisdiction, no company address and no named data-protection contact anywhere in the three documents. Closing this means a legal review before Product 5 takes money or holds data for anyone who does not already know it is a beta.
Document presets
Inherits the same block as `forms.file-fields`: with no S3_* credentials configured, object storage is unreachable and a file field of any kind cannot function, so a preset can be added to a form but never actually collect a document. A preset also carries only its name — the accepted types and size cap are fixed defaults that have to be changed per field afterwards — and nothing checks that two presets would derive the same field key, which the builder resolves by numbering rather than by refusing.
File fields on a form
File storage is not switched on yet.
Build a workflow by describing it
No model has ever built a workflow through this. Every part is written and typechecks — the eleven canvas tools, the workspace catalogue, the repair loop that feeds a rejected step back as a sentence, the confirmation before the canvas is cleared and the approval before an email template is written — but the whole path has only been reasoned about, never run against a real provider key, so how well a model actually holds the graph in its head across a six-step build is unmeasured. The workspace catalogue is also sent in full on every request rather than being narrowed to what the workflow is about, which is correct but not cheap on a workspace with two hundred tags.
Email templates
No email provider is connected, so nothing can send.
Send a one-off email
No email provider is connected, so nothing can send.
Send an email automation action
No email provider is connected, so nothing can send.
Connect Discord
Built and tested, but never yet against a live Discord server.
Integrations browser
Discord is the only real connector; the rest are placeholders.
Calendar
No GOOGLE_OAUTH_CLIENT_ID has ever been configured on any machine this shipped from, so no real meeting has ever reached the calendar_events table this page reads — everything behind it has only ever been exercised with hand-written fixtures, never a real Google response. The specific unverified assumption: whether Google's actual event shapes — an all-day event, a cancelled instance, one row of a recurring series — lay out on the grid the way the fixtures assumed they would. Confirming this needs a real Google account synced through calendar.google-sync.
Google Calendar sync
No GOOGLE_OAUTH_CLIENT_ID has ever been configured on any machine this shipped from, so the OAuth round trip — the consent screen, the code exchange, the refresh cycle — has never run against Google's real servers, and listEvents has never received a real events.list response. The sync engine's own branching (pagination, the 410 restart, cancelled-event deletes) is covered by a unit test against a stubbed client, which is not the same thing as Google's actual JSON. The specific unverified assumption: whether Google's real 410 and nextSyncToken behaviour matches what the sync engine assumes from the API's documentation. Confirming this needs real OAuth credentials and one real Google account.
Book a meeting from CRMS
Inherits the same block as calendar.google-sync: no GOOGLE_OAUTH_CLIENT_ID has ever been configured, so insertEvent, patchEvent and deleteEvent have never sent a single real request to Google. The specific unverified assumption: whether Google's real response to a write matches the shape the upsert-from-response step assumes closely enough that CRMS never ends up storing a local copy of a meeting different from the one Google actually accepted. Confirming this needs a real Google account.
Meetings on the record
Depends on calendar.google-sync having ever run against a real account, which it has not — the attendee-matching step has only ever been exercised against hand-written event fixtures, never Google's real attendee payloads. The specific unverified assumption: whether the email formatting Google actually sends (casing, aliases, a resource calendar with no personal owner) matches a workspace's stored contact emails as cleanly as the fixtures did. Confirming this needs a real Google account and real contacts to match it against.