Every claim, linked to where it came from.
OpenCRM stores four layers: the raw evidence, the claims taken from it, the summaries built on those claims, and the disagreements between them.
Updated
Why a field isn't enough.
01
Agents write from evidence
An agent reads an email or a call and writes a value. A plain field keeps the value and loses the sentence behind it.
02
Values change
Budgets move and dates slip. Overwriting the old value erases why anyone believed it.
03
Sources disagree
An email says one date and a call says another. When the last write wins, nobody sees the disagreement.
The model
Four layers. Nothing overwritten.
Artifacts
The raw evidence, stored as it arrived.
Emails, call transcripts, meeting notes, documents and notes are saved as artifacts with a SHA-256 hash of their content, so you can check the text hasn't changed.
- Five artifact types
- Participants, source URL and recorded date kept with each one
- No update route: an artifact is added, never edited
Observations
Each fact is a claim with a source.
Your agent records each fact as an observation that cites its artifact. When a fact changes, the new observation supersedes the old one. A wrong one is retracted and kept for audit.
- Current, superseded or retracted
- Verification status: unverified, verified or low confidence
- The whole history of a field stays readable
Briefs and conflicts
Summaries that cite, disagreements that stay open.
A brief is a summary that lists the observations it was built from. When two observations can't both be true, a conflict records both until a person resolves it with a written explanation.
- Briefs cite specific observation ids
- Conflicts are open or resolved, never auto-picked
- A resolution needs an explanation
Built for audit, not only recall.
Append-only event log
Every change to an entity is logged with its diff. Nothing updates or deletes an event.
Who made the change
Entity and relationship writes over REST can carry the agent id, tool call id and a prompt hash, stored on the event.
A source for each field
Each observation names the field it covers and cites the artifact and excerpt it came from.
Full-text search
SQLite FTS5 across your records, combined with structured filters.
Relationship graph
Typed links between contacts, companies and deals, with graph traversal.
Import and export
Entities, relationships, events and claims, in and out as JSON.
Three ways in.
All three ship in the open-source repository.
Ask Claude through MCP
Add the OpenCRM MCP server to Claude Code from the open-crm folder, then ask what changed on a deal this week.
claude mcp add opencrm -e CRM_DB_PATH=$PWD/data/crm.db -- $PWD/node_modules/.bin/tsx $PWD/src/mcp.tsCall the REST API
List the open conflicts, as JSON.
curl "http://localhost:8787/conflicts?status=open"Attribute each change
Send headers with an entity update and its event keeps them.
curl -X PATCH http://localhost:8787/entities/ENTITY_ID -H "x-agent-id: intake-agent" -H "x-tool-call-id: call_19" -H "Content-Type: application/json" -d @update.json
What each layer holds.
Read from the schema in the open-crm repository.
| Layer | What it holds | How it changes |
|---|---|---|
| Artifact | Raw email, call transcript, meeting notes, document or note, with a SHA-256 content hash | Added, never edited |
| Observation | One typed claim, the artifact it cites and a verification status | Superseded or retracted, never overwritten |
| Brief | A summary for an entity and the observation ids it cites | New briefs are added |
| Conflict | Two or more observations that can't both be true | Open until resolved with an explanation |
| Event | The diff of each entity change, with optional agent id, tool call id and prompt hash | Appended, never edited |
Entity types are fixed: contact, company, deal, interaction, task and agent. Each entity's properties are free-form JSON.
Questions.
Does OpenCRM extract facts from emails?
No. Your agent reads the evidence and decides what the claims are. OpenCRM stores the artifact, the claims and the links between them, and keeps the history.
What happens when two sources disagree?
Your agent records a conflict that lists the observations involved. It stays open until someone resolves it with a written explanation. OpenCRM never picks a winner on its own.
Can I check that a transcript hasn't changed?
Yes. Every artifact is stored with a SHA-256 hash of its content, so you can recompute the hash and compare.
Is there a user interface?
No. OpenCRM is headless: the REST API and the MCP server are the interfaces. People read it through Claude or through your own apps.
Does it have sign-in and access control?
Not yet. The open-source server has no authentication, so run it on a private network. Attri adds sign-in and access control in managed deployments.
Every fact should show its source. Start with the agents you already run.
Run OpenCRM on sample data in minutes, or have Attri deploy it inside your environment with sign-in and connectors.