My CRM tool

I’ve been mucking about building lots of tools lately, A recent one is a crm tool to help me get on top of my conversations. Local first, Markdown based, it’s something that fits how I think well and that I can query properly. I spend loads of time in the terminal, even more these days with agent harnesses so a cli tool is it.

My tool, imaginativly called crm is a local first relationship memory CLI. It stores human readable Markdown notes in a vault, which is structured data held in SQLite. It supports lexical, semantic, and hybrid search. I can capture what happened with a person or organisation and the tool remembers it for me: tasks, follow-ups, history, etc.

Starting up

Getting started is easy, with the tool installed I just need to initialise the vault.

export CRM_VAULT="$HOME/.mtm_crm/demo-vault"
crm init

crm init creates the folder structure, config, templates, and database. The CRM_VAULT environment variable can be used to set the vault path or you can do it through the —vault parameter.

Adding organisations

I’ve tried to keep the same pattern to the parameters throughout so that once the patterns make sense it’s easy to remember all the commands. There’s really good help throughout too.

crm org add "Data Company" --sector technology --domain data.example
crm org add "Cow Company" --sector agriculture --domain CowCompany.co.nz
crm org add "Food Company" --sector dairy --domain FoodCompany.com

crm org list
crm org show "Data Company"

I can work across multiple organisations in the same vault, and the relationship memory stays separated but searchable across all of them.

Adding people

crm person add "Sarah Jones" --org "Cow Company" --role "Head of Data" --email sarah@CowCompany.co.nz --topic traceability
crm person add "Mark Lee" --org "Food Company" --role "Sustainability Lead" --email mark.lee@FoodCompany.com --topic supply-chain
crm person add "Alex Rivers" --org "Data Company" --role Founder --email alex@data.example --topic crm

crm person list
crm person show "Sarah Jones"

People are first class records. They’re linked to organisations, have their own notes, and become part of the search and follow up system.

Capturing interactions

This is where most of the value is for me. I can just type what happened:

crm capture "Met Sarah Jones from Cow Company at evokeAG. She asked for the cattle tagging example. We discussed traceability. Follow up in two weeks."

crm capture "Met Mark Lee from Food Company. He wants a supply-chain follow-up next week and asked for a short deck on reporting workflows."

crm capture "Coffee with Alex Rivers from Data Company. We discussed local-first CRM design and MCP integration."

The tool turns that into an interaction record, links entities, and creates follow-up tasks when it detects them. That’s the core loop and it’s fast to use. This is done using a local LLM (Gemma4 works well for me on my Mac).

If you want more precision, there’s a structured approach to adding interactions too:

crm capture \
  --person "Sarah Jones" \
  --org "Cow Company" \
  --channel zoom \
  --date 2026-04-10 \
  --title "Traceability follow-up call" \
  --summary "Reviewed pilot scope and next steps" \
  --topic traceability \
  --promise "Send draft implementation outline" \
  --followup "Send traceability implementation outline" \
  --due 2026-04-17

Querying history

crm history --org "Cow Company"
crm history --org "Food Company"
crm history --person "Sarah Jones"
crm history --topic traceability

Quick answers to: what’s my history with this person, this org, or this topic?

Tasks and due follow-ups

crm task list
crm due --within 14
crm due --overdue

Tasks come out of capture automatically, but you can also manage them directly. crm due is where the tool stops being a diary and starts being really helpful for remembering who I need to follow up with now.

crm task add "Send pricing note" --person "Alex Rivers" --org "Data Company" --due 2026-04-15 --priority high
crm task edit "Send pricing note" --priority urgent
crm task show "Send pricing note"
crm task done "Send pricing note"

Editing records

crm org edit "Data Company" --sector software
crm person edit "Sarah Jones" --role "Director of Data" --next-followup 2026-04-24
crm capture edit "Traceability follow-up call" --summary "Reviewed pilot scope, next steps, and owners"

You don’t have to hand edit Markdown unless you want to. These edit commands keep Markdown, SQLite, and the search indexes all in sync.

Merge: for when duplicates happen

crm org add "NZ Food Company" --sector agriculture
crm org merge "Cow Company" "NZ Food Company"
crm person add "Sarah J." --org "Cow Company"
crm person merge "Sarah Jones" "Sarah J."

Real CRMs get duplicates. Merge flows let you clean that up without breaking the relationship history.

Search

crm search traceability
crm semsearch "people interested in supply chain reporting"
crm query "Who asked me for the cattle tagging example?"

Lexical is exact-ish keyword recall. Semantic is meaning based. Hybrid is the one I use most: fuzzy recall that tends to find the thing even when I can’t remember exactly how I phrased it.

Briefs

crm brief person "Sarah Jones"
crm brief organisation "Cow Company"
crm brief weekly
crm brief stale

This is where I think it starts to feel like a proper memory enhancement tool. A person brief, an org brief, a weekly follow up summary, or a stale-relationships brief. The stale one is particularly useful as it surfaces people I haven’t spoken to in a while.

Sync

crm sync

Markdown is the narrative layer, so sync is important. It’s idempotent, so rerunning it against unchanged notes should mostly skip work.

JSON mode for agents and automation

crm person list --format json
crm query "traceability follow-up" --format json
crm doctor --format json

Normal usage is text-first, but every major command can output JSON for scripting or agent composition.

Skills and MCP

This makes the tool really cool. I created an Agent SKILL.md file that is included with the binary and it tells tools like Claude code, OpenAI codex etc how to use the tool. There’s also an MCP interface.

crm mcp

This exposes the entire CRM over MCP.

With the skill and/or the MCP server, instead of remembering all the individual commands, I can just talk to my CRM in plain English through a chat session. I can also paste in things to the chat like a meeting transcript and ask it to pull out the key people, what was discussed, any commitments made, and log it all as an interaction in my crm.

I can also ask follow up questions in the chat about what comes back. Not just retrieve, actually interrogate. Things like “who have I spoken to at Cow Company in the last month and what did we discuss?” or “what promises have I made that are still open?” It starts to feel a lot less like a database and a lot more like a memory super power.

The other thing I built the crm tool around is composability. Because crm exposes itself as a proper service layer and uses stun and stout, it can sit alongside other tools in a workflow. I’ve written before about the value of tools that are designed to work alongside others rather than in isolation, and this is me trying to stay true to that and build that

I’ve been running this for a while now and it’s already changed how I manage relationships for work. It fits into my existing workflow without asking me to change how I think or open another browser tab. That’s what I wanted.

< Back