A lightweight, build-it-yourself CRM for solopreneurs & consultants (Bases + 2 plugins, ~1 hour)
Earlier, the thread Fully Functional Modular CRM showed a genuinely impressive solo CRM - and a year and a half of replies asking for a release.
Fair enough: most of us don’t want to build a CRM,
we want to have one. But the second-best thing to a release is a recipe you can build in about an hour, own completely, and adapt. This is that recipe. Feedback very welcome — this is a first public version. To be clear, this isn’t a plugin, it’s a recipe that uses existing functionality and existing plugins to create a first version.
It’s aimed at solopreneurs and small consulting/ professional-services practices: the kind of work where you maintain 100–300 warm relationships
and 3–15 open deals, where repeat business and referrals dominate, and where every heavyweight CRM you try silently dies after three weeks of
dutiful data entry.
Design principles
- At most two community plugins (a lesson taken straight from that thread): Templater for data entry, plus one community kanban view for Bases (pick a current one from the directory). Everything else is core Obsidian — Bases does the heavy lifting.
- Modular, one folder per module, strict naming. Drop any module you don’t need.
- Exit-friendly. All data is plain frontmatter in ordinary notes; the
.basefiles only read it. Stop using the system and you keep clean notes. - Capture where you already write. The interaction log is a by-product of the meeting notes you take anyway. That kills the #1 reason CRMs die: entry friction.
Two things this adds that most homegrown CRMs skip, and that matter most in relationship-driven work: a keep-in-touch cadence per contact and
referral-source tracking (who sent this deal your way, and who deserves a thank-you).
Folder structure
crm/
people/ # one note per person
orgs/ # one note per organisation (+ attachments)
deals/ # one note per opportunity
log/ # meeting & activity notes
reviews/ # weekly reviews
inbox/ # quick captures, to be processed
_templates/ # Templater templates
contacts.base
pipeline.base
Templates
Frontmatter keys in English with underscores (keeps Bases formulas clean).
Person (_templates/person.md):
---
type: person
org: "[[]]"
role:
segment: B # A = core, B = warm, C = broad
warmth: warm # warm | lukewarm | cold
can_refer: false
referred_by: "[[]]"
cadence_weeks: 8
last_contact:
next_touch:
email:
phone:
tags: [crm/person]
---
[Call](tel:+00000000000) · [Mail](mailto:[email protected])
## Context
<!-- how you met, talking points, interests -->
## Log
<!-- newest on top; links to notes in crm/log/ -->
Organisation (_templates/org.md):
---
type: org
sector:
status: prospect # client | past-client | prospect | partner
tags: [crm/org]
---
## People
## Documents
Deal (_templates/deal.md):
---
type: deal
org: "[[]]"
contact: "[[]]"
stage: lead # lead | conversation | scoping | proposal | won | lost
value: 0
referral_source: "[[]]"
proposal_sent:
expected_close:
next_step:
tags: [crm/deal]
---
## Notes
Meeting note (_templates/meeting.md), file name
YYYY-MM-DD meeting <name>:
---
type: log
contact: "[[]]"
org: "[[]]"
date: {{date}}
touch: meeting # meeting | email | event | newsletter
tags: [crm/log]
---
## Notes
## Agreed
- [ ]
The capture rule — ten seconds, and it is the whole system: after any contact, create a meeting note from the template and update two dates on the person’s card: last_contact = today, next_touch = today + cadence.
The two Bases files
(Bases syntax is still evolving — double-check function names against the current help docs for your Obsidian version.)
contacts.base — three views:
filters:
and:
- file.hasTag("crm/person")
views:
- type: table
name: All contacts
order: [file.name, org, segment, warmth, last_contact, next_touch]
- type: table
name: Overdue
filters:
and:
- next_touch <= today()
sort:
- property: next_touch
direction: ASC
order: [file.name, org, next_touch, cadence_weeks]
- type: table
name: Referrers
filters:
and:
- can_refer == true
order: [file.name, org, last_contact]
pipeline.base — open deals, grouped and as a kanban:
filters:
and:
- file.hasTag("crm/deal")
views:
- type: table
name: Open pipeline
filters:
and:
- stage != "won"
- stage != "lost"
group_by: stage
order: [file.name, org, value, next_step, expected_close]
- type: table
name: Quiet proposals
filters:
and:
- stage == "proposal"
- proposal_sent < today() - "14 days"
order: [file.name, org, value, proposal_sent]
- type: kanban # view type provided by the kanban plugin
name: Board
group_by: stage
Add a summary on the value column (sum) in the table view: that’s your pipeline total per stage — a pipeline report with zero moving parts.
The weekly review — the engine
One fixed slot per week (say Friday, 16:00, calendar-blocked). Template:
---
type: review
week: {{date:GGGG-[W]WW}}
---
## Who's overdue
![[crm/contacts.base#Overdue]]
## Quiet proposals
![[crm/pipeline.base#Quiet proposals]]
## Referrers — who deserves a thank-you?
![[crm/contacts.base#Referrers]]
## Actions for next week (max 5)
- [ ]
Without this ritual any CRM decays, including this one. Keep the touches small — two lines and a relevant link is a perfectly good ping. For newsletters: tag people (e.g. crm/newsletter), make a view, export as CSV to your mail tool. The CRM itself never sends anything.
What it deliberately does not do
- No email/calendar sync, no automation, no reminders that fire while Obsidian is closed — the weekly review carries that load.
- No engagement scores or auto-generated summaries (that would need a plugin; see the questions below).
- Multi-user? No. This is a single-owner system. If two people need to work the same client data simultaneously, use a real shared CRM.
- If GDPR applies to you: everything-local is a genuinely nice compliance story (no processor, “right to be forgotten” = search & delete), but disk encryption, a deliberate sync choice and yearly pruning are on you. Don’t put sensitive personal details in the Context section.
Feedback welcome!
- Does the Bases syntax above work on your setup / version? Anything that has a cleaner idiom by now?
- Which kanban-for-Bases view are people happiest with?
- Does the two-plugin constraint hold for you, or is there a third that earns its keep?
- If parts of this were a (free, local-only) plugin — automatic
last_contactwhen you link a meeting note, an “overdue” nudge outside the review, engagement scoring — which would actually matter to you? - What’s missing for your practice?