Linell Bonnette

A Dozen-ish Agents Later

I've built a lot of personal AI agents... and almost none of them stuck. The agent was never the hard part.

Table of Contents

I’ve built somewhere north of a dozen personal agents in the last ~18 months. The only one I use daily is the least complicated one, by far: my notes in a search index, handed to Claude over MCP. The thing I keep relearning is that the agent was never the hard part. Getting my stuff in front of it, and letting it actually do something with it, is where every project went to die. This is a walk through what I built, what got in the way, and what actually helped.

What I Built

Grouped by shape rather than by name:

  • MCP servers driven by someone else’s harness. A life-coach server (goals, todos, workouts, daily briefing) in local SQLite, used from Claude Desktop. Then a Go rewrite of the same idea, multi-user, spec-first. The first lasted a week. The second got two days and a tool table that still says “Implemented? Nope.” Without a deeper level of integration, this all felt like I was just wasting time explaining what I should be doing to an AI instead of actually doing things. The point is to save time, so that’s not great. I realized this approach wasn’t even as good as Claude Code in a markdown repo.
  • Apps with an AI layer that never arrives. This mostly revolves around the problem of getting things into a format that’s easily ingested and understood by an LLM. Custom notebooks, chat interfaces, and sync daemons.
  • A Telegram assistant. Hono plus Inngest, Haiku driving a small typed tool registry, Pomodoro check-ins, an end-of-day summary, an Obsidian vault in git as memory. A turn could pause ten minutes on step.waitForEvent waiting for my reply without holding a process open. Two months of use, but it died anyway because it just wasn’t smart enough with the context it had. It wasn’t useless but it wasn’t there yet. I also did a complete rewrite of this one from TypeScript to Go, with a few vibey implementations to feel how different things worked.
  • An all-in-one notes app with user-defined agents. This was supposed to be the one. Hand-written streaming agent loop on Cloudflare Workers, per-user databases, even an architecture diagram before involving a single AI. It actually worked surprisingly well and I could feel it becoming useful… but it still died. It demanded to be my only notes app, had no mobile client, and wasn’t built to easily interact with other connectors (such as someone else’s MCP server). I realized that I would be re-building so much stuff just to give the AI a good enough context to be as useful as I wanted.
  • A budgeting app with chat on top. Pull transactions, categorize, move money between envelopes, the whole gig. Raw tool-use in a loop and then the same tools exposed as an MCP server. The budget advice genuinely helped, more than any of the tools above. It’s also where I learned that dozens of tool calls per turn blow the context long before you’ve “talked” much, which made even Opus 5 a little too dumb to use within a handful of turns. Diving into how to improve my loop so that it handled conversation compaction led me to realizing that conversation compaction isn’t at all what I wanted. I wanted AI to budget for me.
  • A notes indexing daemon. Apple Notes into a search index, exposed over MCP, with write-back to one folder. This is the one that stuck. It only syncs when my Mac is awake, recall only happens when something triggers a search, and it needs a server (more on that later)… but it’s still the least fussy “give my AI my notes” approach I’ve found. It would work just as well, and probably even better, with Obsidian or Notion. I’m using Antfly for this, so it’s more or less literally just handing notes to an Antfly DB.
  • A markdown vault with an AGENTS.md. No infrastructure at all. The lamest one, and for a while the one I actually used. Sometimes it’s hard to beat simple.

What Got in the Way

Most of this was just a pain in the butt. But it was the same pain in the butt, over and over:

  • Getting my stuff in front of the AI. My notes, my budget, my day, in a shape it could actually use. Almost every project above died somewhere in that plumbing.
  • Building my own harness. Every fully custom chat loop meant reimplementing compaction, retries, overload handling, and “edit a paragraph in the middle of a long file.” It could be a fun project, but not the one I was working on.
  • Tool calls eating the context. A few dozen tool calls and the conversation is basically over. Compaction keeps it limping along, but a longer conversation was never the goal — I wanted the budget done.
  • Talking instead of doing. One of my scheduled jobs is a 2AM weather check that tells me when to run. It’s nice to wake up to… but why not just create the calendar event? An agent that can’t act is kind of just a notification service.
  • Permissions, once it can act. I want it to create a “Caffeine Addiction” category when it notices the daily 7-Eleven run, not a “Yacht Purchase” category because I mentioned one offhand. Anything easy to undo can just happen. Anything else should ask, and answering should be a single tap rather than a typed-out message. I am interested in building my own guardrails with decision models someday, but that’s another “this isn’t what I’m working on right now” project.
  • Wanting to be the whole app. I don’t want to move my notes, my todos, and my budget into something new just so an AI can see them. I just want the machine overlords to tie into my existing systems, including other people’s MCP servers.
  • Needing a box. This is really three problems wearing one hat: my data lives on my Mac (so it has to be awake), the search index needs somewhere to live, and something has to sit around waiting for my reply. Only the last one ever felt solved.

What Actually Helped

  • Durable waits. The Telegram bot could wait ten minutes for my reply without keeping anything running.
  • Someone else’s harness. The exact same budget tools were dumb in my hand-rolled loop and good inside Claude. Every MCP server driven by a real harness was better on day one.
  • A small, typed tool registry. Easy to reason about, easy to rewrite in another language when I inevitably got distracted.
  • Searching instead of stuffing. The notes index only shows up when something asks for it, and it’s been more useful than anything I tried to pack into the prompt up front. This is dependent on stuffing enough info into the prompt to convince the model to perform the relevant searches.
  • Plain files. A markdown vault and an AGENTS.md got me surprisingly far before I wanted more.

Where I Ended Up

I’m currently using a combination of Claude and opencode. In the Claude desktop app, I’ve got a few scheduled jobs that are able to run and interact with a couple of my own MCP servers and several pre-built connectors like Slack and Linear. It’s still a little lame though, because:

  1. The notifications are just plain messages from Claude. Responding requires sending an actual message. This is obviously a nit, but it’d be nice to be able to tap “Yes” or “No” to answer a “Have you gone for your run yet?” question. Telegram had reactions and real buttons for exactly this.

  2. I do still have to run a VPS for the MCP servers that I’m running. My budgeting app could be serverless, but the search index does require a dedicated machine. This would be nicer if I had a homelab to host this and ideally run local embeddings. Currently it’s a small Droplet that handles embeddings via API.

So if I were starting the next one today, I’d want it to plug into the stuff I already use, to do things instead of just telling me about them, to ask me before anything scary with a tap instead of a paragraph, and to not need me babysitting a server.

Honestly though? I just like building these things. Every one of them taught me something, even the ones that only lasted a week, and I’ll definitely build a few more. At least now I know where the walls are.