Personal CRM

~5 min read

Personal CRM

A People/ folder that turns into a relationship-tracking system: last-touched dates, follow-up reminders, conversation history.

Convention

Each person gets a note at People/<name>.md:

---
title: "Sarah Chen"
email: sarah@example.com
twitter: "@sarahchen"
relationship: friend       # friend | colleague | family | acquaintance | mentor
first-met: 2024-03-15
follow-up-cadence: 90      # days between meaningful touches
tags: [person]
---

# Sarah Chen

## Context

Software engineer at Acme. Met at a conference in 2024.

## Interests

- distributed systems, hiking, ramen

## Conversations

(auto-populated by the trigger)

How automation fits

Triggers and schedules in Lettuce don’t run an AI — they splice a > [!ai] <prompt> directive into a note. Whatever MCP agent you have connected (Claude Desktop/Code) picks the directive up via pending_directives and does the work, proposing edits if it’s connected with a propose-only key. So the CRM “automation” below is really: drop a directive at the right moment, let your agent maintain the People notes. See Vault automation/01 Triggers and Vault automation/02 Schedules for the schemas.

A real limitation to know up front: the only trigger event is file:created — there is no file:saved, and triggers have no predicates (no body-matches / path-matches) or actions (no run-agent / move). So the conversation-logging flow below fires when you create a note, not every time you save one.

Triggers

Build the Conversations log

When you create a new note anywhere in the vault, splice a directive asking the agent to check it for People mentions and log meaningful touches:

# .lettuce/triggers.yml
- when: "file:created:**/*.md"
  prompt: |
    If this note mentions one or more People/<name>.md, then for each person:
      1. Read the surrounding context (a paragraph or two).
      2. Decide if it's a "meaningful touch" (a conversation, decision, or
         shared experience) versus a passing mention.
      3. If meaningful, propose adding a bullet to People/<name>.md under
         `## Conversations`: `- <today's date>: <one-line summary>. See [[this note]].`
    Skip trivial mentions ("I sent Sarah a link"). Use judgment.

The trigger only fires on creation, so it covers the common case of a fresh daily/meeting note that name-drops people. For notes you edit later, the agent will pick the same work up the next time it sweeps pending_directives, or you can add the > [!ai] line by hand.

Follow-up nudges

A weekly schedule drops a directive into Monday’s daily note asking the agent to surface anyone you’re overdue to contact:

# .lettuce/schedules.yml
- weekly: "Mon 09:00"
  target: "Daily/{{date}}.md"
  prompt: |
    For each note in People/, compare frontmatter.follow-up-cadence (days)
    against the date of the last entry under `## Conversations` (or `first-met`
    if there are none). For anyone where days-since-last-touch exceeds their
    cadence, append under a `## Follow-ups` heading in this note:
      `- [ ] Reach out to [[People/<name>]] (last touch: <date>, cadence: N days)`
    Create this daily note and the heading if they don't exist. Don't notify —
    just populate the note so I see it during my morning routine.

{{date}} in target resolves to the fire date (YYYY-MM-DD), so the directive lands in that Monday’s daily note. The date math (“days since last touch”) happens in the connected agent — the prompt text is spliced verbatim with no templating.

Variants

Birthday reminders

There’s no notification action in the schema — schedules only drop directives — so route a daily reminder into a single note the agent maintains:

- daily: "08:00"
  target: "Daily/{{date}}.md"
  prompt: |
    Look at every People/ note with a `birthday: MM-DD` in frontmatter.
    If any match today's MM-DD (or tomorrow's, for advance warning), append a
    line under `## Birthdays` here: `- Tomorrow is [[People/<name>]]'s birthday.`
    Do nothing if there are no matches.

You’ll see it in your daily note rather than as a macOS alert.

Relationship graph

The vault graph view (View → Graph, filter to tag:person) shows your network. Cluster sizes are signal — who’s in your “frequent” cluster vs. “outer ring”.

Email integration

Drop emails into Inbox/ as email-*.md notes. A trigger fires on creation and asks the agent to thread each into the right person’s ## Conversations:

- when: "file:created:Inbox/email-*.md"
  prompt: |
    Identify the other party from the From/To frontmatter. If a matching
    People/<name>.md exists, propose adding a `## Conversations` entry there
    with a one-line summary and a wikilink back to this email note.

Triggers can’t move files (there are no actions), so if you want the email filed under People/<name>/, ask the agent to do the move in the prompt, or move it yourself after reviewing the proposed conversation entry.

If you tag attendees in meeting notes, fire on new notes created in Meetings/:

- when: "file:created:Meetings/**/*.md"
  prompt: |
    Read the attendees from frontmatter. For each attendee, propose adding to
    People/<name>.md under `## Conversations`:
    `- <today's date>: <meeting title>. See [[this meeting note]].`

Privacy

The People folder typically contains real names, emails, sometimes personal context. Either:

  1. Don’t publish — the easy default. Notes are only exported when they carry published: true, so leaving People notes unmarked keeps them out of any lettuce publish site.

  2. Pseudonyms — if you want to write publicly about people without naming them, use first-name-only filenames and strip or anonymise the sensitive content in the note itself before marking it published: true (there’s no automatic frontmatter-stripping step).