The problem
I had too many conversations going and was scared of dropping one.
This year I’ve been running several kinds of outreach at once: insurtech design partners and advisors, marketing conversations, and MBA recruiting in consulting and tech.
It started as a small Chrome extension that saved LinkedIn profiles into a Notion database for consulting recruiting. It hardcoded my name, two database IDs and twelve stages. The moment I had four campaigns instead of one, it fell apart.
Every morning I just wanted to know who to message today and what to say, and then get out of the tool quickly.
Before building, I checked what already existed. Every individual piece is available for free somewhere: Twenty, Huntr, Clay, Dex, folk, Streak. None of them put together what I wanted: people ranked by how well I know them, the actual message thread in the same place, and a guarantee that nothing gets sent automatically.
A tool they finish with, not one they linger in.From the product requirements I wrote before building
Capturing someone from LinkedIn. Warmth and AI enrichment are previewed before anything is saved.Who it’s for
Built for one user: me.
Early on I decided this was a personal tool, not a product. So the question stopped being whether people would pay for it, and became whether it was worth my weekends.
The only user
Me, running four campaigns
Insurtech, Marketing, MBA – Consulting and MBA – Tech, each with its own stages. Somewhere between 50 and a few hundred people, every message written by hand.
The archetype
Anyone doing warm, relationship-led outreach
Career pivots, MBA recruiting, founders looking for design partners or angels. People who need forty good conversations and have no use for mass cold email.
InferredExplicitly not
Sales teams
No bulk actions, no sequences, no automated sending, no multi-user accounts.
Deployment
Self-hosted
Runs on my machine in Docker. Keys stay on the server and never reach the browser.
Use cases
How I use it each day.
CaptureWhile on LinkedIn
The extension reads the profile I’m looking at, asks which campaigns it belongs to, and prompts for “how do you know them?”, the most useful field. It shows the exact warmth score the save will use.
Morning triageFirst thing
Due today opens with a brief: five people worth writing to, why each, and a draft for each in my voice. Then a summary of anything the AI changed overnight, with one undo for all of it.
A reply comes inAny time
I paste it in. The stage, next step and sentiment update themselves, each quoting the words that justified the change, like moving to “Call” because they wrote “Sure, send a time.”
Checking the AIWeekly
The Changes feed lists everything the AI wrote without asking. Undo any field or a whole run, and it flags anything that replaced a value I’d set myself.
Handing it to an agentOptional
An MCP server lets an AI assistant read the queue and add notes with evidence. It has no way to send anything.
The product
Five screens and an extension.
Designed first as high-fidelity mockups (six screens, 24 states, including every empty and failure state), then built against them.
A pasted reply moved Wei from Contacted to Call. The banner quotes the sentence that justified it, with undo for each field.Changes: everything the AI wrote without asking, grouped by run, one click to undo.One board per campaign. MBA – Consulting has 12 stages, handled by scrolling sideways.Designed for the week away: “42 people are due, that’s a lot.” Show the top 5, snooze the rest. Warmth, always with reasons
A score out of 100 from connection degree, mutuals, shared school or employer, how you know them, and how long it’s been quiet. It’s never shown as a bare number.
Fields come from the conversation
Stage and priority are worked out from the actual messages. Most CRMs do it the other way round.
Stages per campaign
The same person can be at “Call” for insurtech and “Referral asked” for consulting. Switching campaigns restores each.
Keyboard-first
j and k to move, o to open, c to compose, s to snooze, d for done.
How it works
Every change goes through one place, and gets logged.
Every change, whether from me, the extension or an AI job, goes through one API that records the old value, the new value, who wrote it, how confident it was and the evidence.
Capture
Chrome extension
Reads the LinkedIn page you’re on, previews warmth and enrichment.
Core
API
The only way to write. Every change is logged with its evidence. There is no send endpoint.
AI jobs
Enrich · Digest · Sweep
On capture, on a new reply, and once every morning.
Data
Postgres
Contacts, messages, notes, every change, daily briefs.
Agents
MCP server
Seven tools: five read, two write with evidence. None send.
TypeScriptFastifyPostgreSQL 16React 19 + ViteChrome extension (MV3)MCPAny OpenAI-compatible modelDocker
The contact page. The composer ends at “copy to clipboard” and “mark as sent”. There is deliberately no send button.Product decisions
The main decisions, most of them about trust.
Nothing can send, and that’s enforced in code
WhyThere’s no send endpoint at all. The agent interface has a test that fails if any tool name sounds like sending: send, email, post, invite, reply and so on. Even “log that I sent a message” was left out, because it’s the closest thing to sending the system could express.
Trade-offFollow-ups are never automated. That also keeps my LinkedIn account clear of automation crackdowns.
Let the AI write, then make every write undoable
WhyApproving every AI suggestion is tiring, and people stop reading them. So the AI writes directly, and the audit trail replaces the approval step.
Trade-offI have to trust the undo. If stage changes get annoying, those fields can go back to being suggestions.
The AI has to quote its evidence
WhyEvery AI change must quote the words behind it and clear a confidence bar of 0.55. Closing someone out needs 0.8, because a wrong close quietly removes a person from your life.
Trade-offSome real updates don’t get made, and the banner says why.
Undo won’t overwrite my later edits
WhyIf I’ve changed a field since the AI did, undoing that AI run skips it and says so. Undo is logged too, because a history you can quietly edit isn’t worth much.
Trade-offUndoing a sweep across many contacts has to be done one contact at a time.
Flags come from simple rules, not the AI
WhyLines like “stage says Call but nothing has happened for 20 days” are ones I act on without checking, so they have to be provable. The morning sweep does no web searching, to avoid confidently citing a funding round that didn’t happen.
Trade-offFewer, plainer flags.
It still works when the AI is down
WhyCaptures save without enrichment, replies save before the model is called, and the morning brief falls back to rule-based ranking. A down provider costs the drafts, never the brief.
Trade-offTwo code paths for everything the AI touches.
Stop crawling LinkedIn
WhyThe first version opened a hidden tab to fetch someone’s full education history. It felt like crawling rather than reading the page I was on, so I cut it.
Trade-offOnly the school shown at the top of the profile is captured.
Where it stands
Built in about 27 hours. Next, a real week of using it.
Each milestone had a “done when” test. The last two can’t be ticked by a build: they need a week of real outreach through the tool, and a week of morning sweeps I agree with.
Built
- Database, API and token auth
- Contacts, warmth scoring and a full change log
- Chrome extension with AI enrichment preview
- Five web screens, built from the mockups
- Reply digest with evidence, confidence and undo
- Changes feed
- Daily sweep and morning brief
- MCP server for AI agents
In progress
- A full week of real outreach through it
- A week of morning sweeps I’d agree with
- Running the AI jobs against a real model (tested so far against a stand-in)
Next
- Replies captured from LinkedIn automatically, then Gmail
- A composer that drafts in my own voice
- A settings screen
~27 hrs
from first commit to all six milestones
- 3 Aug 2026Version one: a LinkedIn-to-Notion clipper for consulting recruiting
- Early AugCompetitive research, requirements doc, mockups
- 11 AugDatabase, API, contacts and warmth, the extension
- 11–12 AugWeb screens, reply digest, undo
- 12 AugMorning sweep, brief and MCP server
- SepRunning locally; real-use week in progress
What I learned
What it taught me about AI products.
- I trust an AI change when I can trace it to a sentence. An unexplained one I’ll undo, even when it’s right.
- The most important safety features were things I left out: no send endpoint, no “log a sent message” tool, no web search.
- Some of my “done when” tests couldn’t be passed by building more, which kept me honest. Finishing six milestones didn’t mean the tool worked yet.
About the screenshots: they show the real interface running on fictional sample contacts. The AI drafts and quotes in them were written for the screenshots, not generated by the model.
Next in the lab
Simply Invoicing
A relative kept being asked to pay for the next tier to unlock one more feature. So I built exactly what they needed, and nothing they didn’t.