DEV Community

Cover image for Keep Your AI on Track Through Weeks of Prep
M. Alwi Sukra
M. Alwi Sukra

Posted on

Keep Your AI on Track Through Weeks of Prep

Prep can run for weeks, and keeping it in one AI conversation gets expensive fast. So I built prep-mcp, a small MCP server in Go that lets Claude read and safely write a folder of markdown notes. Any conversation can end, and the next one picks up where it left off.

This post covers why I built it, what it is, how a conversation uses it, and what two and a half weeks of daily use showed.

Why I built it

Since May I've been preparing for senior backend interviews: DSA and LeetCode, system design, DDIA, AI systems, plus my resume and LinkedIn profile. Claude has been my study partner every day, and every related conversation lived in one Claude project. After five months, three problems kept coming back:

  • Long conversations got expensive. I kept one conversation per company's hiring process, and some ran for weeks. At one point, a single new message used about 30% of my 5-hour usage limit, so three messages used it up.
  • Project memory didn't carry enough. New conversations still needed reminding of work done in other ones, and I couldn't see what Claude chose to keep.
  • Progress lived in my head. I tracked applications, learning and resume changes in my own notes, pasted them into each conversation, and often forgot to update them.

The idea

So I had an idea: move the memory out of Claude, into notes I own, and give Claude an MCP server to read and write them. Then I decide what each conversation stores and what the next one reads. Memory becomes something I can read, diff and revert, instead of something I can't see into.

That makes each problem smaller:

  • Prep for one company can run as several short conversations instead of one long one.
  • Learning (DSA, LeetCode, system design, DDIA) runs in short conversations too, with a record of what to improve, so progress is countable.
  • I stop tracking applications by hand. I ask Claude, and it answers from the notes.

The hard part is the write side: an AI writing to files I also edit by hand, without either of us losing work. That is where most of the design went.

What it is

prep-mcp is a Go binary that Claude Desktop and Claude Code start over stdio. It gives the assistant 11 tools over one folder of markdown notes, the vault. I edit the same vault in Obsidian, and every AI write lands as a git commit.

Claude and I edit the same notes, and git records every AI write. I read and edit the vault in Obsidian. Claude, in Claude Desktop or Claude Code, makes MCP tool calls to prep-mcp, a Go server with 11 tools over stdio that checks every write. prep-mcp reads and writes the vault, one folder of markdown notes with prep.config.yaml, CLAUDE.md, tags.md, templates and your documents, inside a private git repo with one commit per AI write.

Not only interviews

The server knows nothing about interviews. Two files at the vault root give it its shape:

  • prep.config.yaml defines the document types (folder, file name pattern, required fields, date field), the tag vocabulary file, and what a new conversation is shown.
  • CLAUDE.md gives the assistant its working rules in plain prose: how to start, what to log, which writes to prefer.

My vault is set up for job interviews. It has seven types: applications, prep sessions, improvements (one weakness each, with an exit criterion), stories, references, learning notes and weekly plans. My CLAUDE.md, about 7 KB, says how to run and score each kind of drill and how to log it. Change those two files and the same server tracks an exam, a certification or a language. The README's "Shape it to your vault" shows both files from the example vault.

How it works

One conversation, as the assistant runs it:

One conversation with prep-mcp in three steps. 1, Start: get_context returns CLAUDE.md, this week's plan and log, open items with their next action, recent prep sessions and the most used tags. 2, Work: read as needed with list_docs, read_doc, search_text and list_tags. 3, Log: one batch of create_doc, append_section, update_frontmatter, edit_text and replace_doc; every write is checked against the rules and if one fails nothing is written; changed files are written to the vault; one git commit, authored by the assistant. The next conversation starts at step 1, from what this one logged.

Start. get_context replaces the handover prompt I used to paste. One call returns what the config's context block names: the working rules, this week's plan and log, every open item with its next action, the last few prep sessions and the tags used most in the last 30 days.

Work. The other four read tools answer questions as they come up. list_docs does most of it: tags (AND, OR, prefix), frontmatter conditions and dates combine in one call, and group_by returns counts instead of documents. "Which applications are waiting on me?" and "which weaknesses came up most this month?" are the same tool with different arguments. list_tags shows what keeps coming back and what has gone quiet. search_text finds a phrase anywhere. read_doc returns a file with its content hash, which a later full rewrite must quote.

Log. Each write tool changes only what it names: create a file, append under a heading, patch frontmatter, replace one exact piece of text, or rewrite a whole file. A conversation usually ends with one batch: its prep session note plus a line in the week's log, as one commit.

No database, no index. Every call scans the folder: about 58 ms for 2,000 generated documents, and about 5 ms at my vault's size (an estimate from the per-document rate). A stored index would be a second copy to keep in sync with files I also edit by hand.

A day with it

My morning conversation starts with get_context, and Claude says in one line what today's plan calls for. We work through it, whether that's a drill, a design problem or a chapter of reading. At the end, Claude logs a prep session tagged with the weaknesses it saw, plus one line in the week's log. On Friday, one list_docs call counts which weaknesses came up most that week, and that shapes next week's plan. Applications live in the same vault, each with its next action and date, so following up is a question, not a memory test.

The write path

Letting the AI write is the hard part. A server that writes can overwrite my edits, break a file's frontmatter, or follow instructions hidden in a document. Each decision below has a cost.

  • Small writes over full rewrites. append_section, edit_text and update_frontmatter change only what they name. Cost: append-only documents only grow, which comes back later.
  • A guarded full rewrite. replace_doc needs the content hash from the last read. If I changed the file in Obsidian in between, the write fails instead of overwriting me. Cost: the model has to read again and redo the change.
  • One git commit per AI write, under its own author. Every change can be reviewed, diffed and reverted. batch applies up to 200 writes as one commit, or none at all. Cost: before batch existed, nine title edits made nine commits.
  • A write may not make a document worse. A write that would break a required field, a date or a tag fails and says how to fix it. A problem the file already had is only a warning, so a write can still fix it.
  • No delete, and nothing outside the vault. Any document the AI reads could carry instructions, so the tools can't remove files or reach outside the folder. Cost: when a file landed in the wrong folder, moving it took a create, a link fix and a manual git rm from me.

How I built it with Claude Code

I used prep-mcp from Claude Desktop and built it with Claude Code, so the AI was both my user and my developer. Friction in a Desktop conversation became a ticket, and a Claude Code conversation fixed it. Most changes follow the same loop:

  1. Claude asks me questions until every decision is agreed. No code before that.
  2. Tests come first, at the places the change touches.
  3. Two reviewers run in parallel: one checks the change against the spec, the other against code standards.

Result

From 2 to 19 October:

  • Claude made 272 commits to the vault. I made 3: the first import, one config edit and that manual git rm. There were 0 reverts; mistakes were fixed by a later write. I don't read every commit. I read the files in Obsidian as I use them, and git is there for when something looks wrong. The write checks are what make that safe enough.
  • The vault grew to 166 typed documents, 41 of them prep session notes. In the first full week, Claude added 3,908 lines and removed 153. The notes grew; they were hardly rewritten.
  • Small writes did nearly all the work. In that week: append_section 52, batch 47, edit_text 25, create_doc 23, update_frontmatter 15, replace_doc 3. The next week, 63 of 81 commits were batches, and replace_doc stayed at 3.
  • The Claude Desktop log shows 0 hash conflicts, up to 16 October. Git can't show this number, because a refused write commits nothing.
  • The vault is now my only application tracker. I retired the separate tool I used before.

Against the three goals:

  • A conversation covers a day now, not a company's whole hiring process. It starts from get_context instead of weeks of chat history. At the end of a weeks-long conversation, one message used to cost about 30% of my 5-hour limit. At the end of a day's conversation, the one I measured cost 6%.
  • Each weakness I'm working on has its own file with an exit criterion, and every prep session tags the ones it saw. My weekly review counts those patterns with one list_docs call, so progress comes from the notes, not from my memory.
  • "Where am I with each application?" is one question, answered from the notes with each application's next action and date.

What I learned

Daily use kept changing the design:

  • Tool descriptions are the model's UI. Once list_tags showed the whole tag vocabulary, the model checked it before writing, and the unknown-tag refusal stopped firing. When it did fire on a batch that had done everything right, the cause was a tool description promising something the code didn't do.
  • The cure for context loss has its own cost. Whatever a conversation reads from the vault stays in it and is re-read with every reply. In Claude's usage reports, the vault was about a third of a conversation's cost.
  • The expensive moment is coming back. Returning to an old conversation after a break reloads all of it, and those returns were the biggest single costs in the reports. With the vault, closing a conversation loses nothing, so the fix is a fresh one each day. The habit is the hard part.
  • A boundary is only as strong as the most powerful file left outside it. Templates were locked against prompt injection while CLAUDE.md, which steers the model more, stayed writable. So I unlocked the templates.
  • Copies drift. A check that copied git's lock rules missed a case that git's own error already names. The fix was to delete the check.

What's next

Open limits and ideas are tracked in the repo's issues. Three examples:

  • read_doc returns a whole file and get_context embeds the week's document in full, so both grow until they hit the client's 25,000-token limit for one tool result. A long log has already been cut there, and the cut lost the newest entries, the ones a new conversation needs. Reading one section by heading, or the last few, would fix it.
  • The config is read only at startup, so a change applies after a restart and nothing warns that the running config is out of date.
  • Transcribe a practice recording with whisper.cpp and compute words per minute, long pauses and time to the first full stop, so the model never has to estimate them.

Try it

The repo is public at github.com/Arkoes07/prep-mcp. The README covers install for Claude Code and Claude Desktop, and a fictional example vault to try it on.

Top comments (0)