Vibe Coding a Personal CRM in Swift (Having Never Written Swift)

Vibe Coding a Personal CRM in Swift (Having Never Written Swift)

So I had a problem. The Atlanta AI dinner series was growing, and I was starting to lose track of who I’d met, what we’d talked about, and when I should follow up. I needed a CRM, but not the enterprise bloatware you’re thinking of. Just something simple, local, and private that could help me keep track of folks and keep this thing going.

I could have probably used the free tier of a basic CRM. Hell, I could have built it in Python in an afternoon. But where’s the fun in that?

Instead, I decided to properly vibe code it. Native macOS app. Swift. The whole nine yards.

One small problem: I’ve never written a line of Swift in my life.

The Vibe Coding Manifesto

Here’s what vibe coding means to me: you pick the tools that feel right for the problem, not the ones you know. You let curiosity drive the tech stack. You trust that with the right AI pair programmer, tools, and process, you can figure it out as you go.

For this project, the vibe was clear:

  • Native macOS because I wanted it to feel like it belonged on my machine
  • Beautiful, it should look nice and professional
  • Swift because if you’re going Mac native, go all the way
  • Local SQLite database because my contact data shouldn’t live in someone else’s cloud, I don’t want to mess with deployments
  • MCP (Model Context Protocol) integration so Claude Desktop could help manage the actual data and keep it up to date

The name came easily: Evergreen. Relationships should be evergreen, constantly maintained, never allowed to wither.

Hour 0: The Setup

The first thing I do in this kind of project is ideate with ChatGPT. I like ChatGPT for this stage specifically because it writes PRDs pretty well, the deep research is helpful, and importantly the image generation works well for conceptual images, brand/design systems, and things like logos.

I try to get into that level of detail up front to help populate the initial repo with enough context for the agent to really know what’s going on. I build out a docs folder with concept images, brand guidelines, PRDs, user journey docs, etc.

For the actual coding I use claude code with 2 subagents:

  • A project manager that uses todolist-mcp to manage a long-lived Kanban of tasks
  • A QA engineer that uses makefile-mcp to run the test suite, linters, formatters, etc before any kanban item is marked done.

I open Claude Code and my first order of business: have it generate a claude.md based on all of that context.

Next we need scaffolding:

“Help me set up a new Swift macOS application project,” I typed. “I want to build a personal CRM with a local SQLite database. I’ve never written Swift before.”

Claude walked me through creating an Xcode project, explaining the difference between SwiftUI and AppKit (I went SwiftUI), and helped me understand the basic structure of a Mac app. Bundle identifiers, entitlements, sandboxing - concepts I’d never dealt with in my Python/JavaScript world.

Evergreen 1

Hours 1-3: Finding the Right Libraries

The beautiful thing about working with Claude Code is that it doesn’t just write code, it helps you discover the ecosystem by using web tools. We explored:

  • SQLite.swift for SQLite management (way nicer than raw SQL)
  • SwiftLint to keep my baby Swift code from looking too amateur
  • Swift-SDK the official model context protocol SDK for swift

Each decision was a mini-learning experience. Why SQLite.swift over GRDB? What’s the Swift way of handling async database operations? How do SwiftUI views actually update when data changes?

Claude would suggest approaches, I’d pick what felt right, and we’d iterate. True vibe coding.

Evergreen 2

Hours 4-6: The Data Model

Building the schema was where things started clicking. We built out the basic data model for contacts, interations, tags.

We built test data generation scripts.

Clean. Explicit. No wondering what shape your data might be at runtime.

Evergreen 3

Hours 7-9: The UI Comes Together

Now I’ve never written Swift, but I’m also not in anyway a frontend developer, so comparisons to javascript frameworks are totally lost on me. I do, however, know how I want something like this to look and work. So early on I iterated with ChatGPT to get highfi images of how it should work, and claude code did a decent job at aligning to that in one go.

With a couple of hours of tinkering, adjusting, and asking for changes, we got to where I wanted it to be. Having a good build/test/run setup in the makefile is very helpful here, to quickly view the changes. It’s also important to have logging set up well so that claude can debug the inevitable issues that come up.

Evergreen 4

Hours 10-11: The MCP Integration

This is where it got spicy. I wanted Claude Desktop to be able to manage my CRM data directly. So we built an MCP server that could:

  • Query the SQLite database
  • Add new contacts and interactions
  • Set reminders for follow-ups
  • Generate relationship insights

The MCP runs as a separate process, communicating with the Swift app through the local database. The two runtimes share a common database manager so they are talking the same language.

Now I can tell Claude Desktop things like “Add a coffee meeting with Sarah from yesterday about her startup” and it just works. This was hard because again, I have no idea how Mac OSX apps are packaged. The first attempt ran into issues with OSX sandboxing permissions, but after a bit of debugging (logging saved the day here), we were able to figure out what was going on and get the shared database placed and permissioned correctly, and the app all bundled into one *.app that contained both the UI and the MCP. Clean.

Hour 12: Polish and Ship

The last hour was pure polish. App icon (designed by ChatGPT, naturally). The little touches that make it feel like a real Mac app.

Then came the moment of truth: we did an AtlantaAIDinner and I had updates to make.

Evergreen.app was Sitting in my Applications folder like it belonged there. It was connected to Claude Desktop like any other MCP. I let Claude know who was there and what we did, and right away we were up to date. EZPZ.

The Aftermath

I’ve been using Evergreen daily for a few weeks now. It’s already helped me stay on top of follow-ups for the AI dinner.

The MCP integration means I can update it conversationally, after a dinner, I just tell Claude who I met and what we discussed. I can also combine tools, Claude can research people or topics on the web to help build out better profiles, it can connect to my gmail to find new contacts or update existing ones. It really works quite well.

But more than the utility, this project proved something to me: the barrier between “I want to build this” and “I built this” has basically disappeared. I went from zero Swift knowledge to a working native Mac app in a week of occasional effort during coffee time.

What’s Next

Evergreen is far from done. As I use it I stumble across little bits of polish or new features that I can add. One day I may release it for other to try.

But that’s the beauty of vibe coding your own tools they grow with you, shaped by your actual needs rather than product manager assumptions.

If you’re sitting on an idea for a tool you wish existed, stop waiting. Pick the stack that feels right, open Claude Code, and start vibing. You might surprise yourself with what you can build.

Subscribe to the Newsletter

Get the latest posts and insights delivered straight to your inbox.