cd /news/ai-agents/my-notes-app-has-no-database-just-a-… · home › topics › ai-agents › article
[ARTICLE · art-166804] src=sayjot.xyz ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

My notes app has no database, just a folder of Markdown and an MCP server

Developer Mohak Bajaj shipped Jot, a Mac note-taking app that stores every note as a Markdown file with YAML front matter in a single folder at ~/Documents/Jot, with no database, sync server or account system, and exposes the vault to AI agents through a seven-tool MCP server launched via `jot mcp` on stdio for Claude Code, Codex and Cursor. The roughly 600-line TypeScript storage layer writes atomically via temp file plus rename, caches parsed files by inode, mtime and size, and skips unparseable files rather than crashing; the MCP server deliberately omits a delete tool so agents can add, tag, finish and archive notes but cannot remove them. Two generated files, INDEX.md and SKILL.md, let any agent that can read a folder use the vault without MCP.

by read4 min views7 publishedNov 10, 2026
My notes app has no database, just a folder of Markdown and an MCP server
Image: source

blog · · Mohak Bajaj

I make a small Mac app called Jot. You select text anywhere, tap Shift twice, and it saves a note. When I started, I thought about SQLite, a sync server and an account system. I shipped none of them. All of Jot's storage is a folder: ~/Documents/Jot.

This post covers how that folder works, what broke, and why AI agents turned out to be the best reason for it.

One note is one file #

Every note is a Markdown file with YAML front matter:

~/Documents/Jot/
  2026-11-09-6tjhzv.md
  2026-11-09-gnump0.md
  INDEX.md
  SKILL.md
  attachments/6tjhzv/
  .trash/
---
archived: false
created: 2026-11-09T09:12:04.511Z
done: false
id: 6tjhzv
images: []
pin: false
section: ''
source: Safari
url: https://example.com/article
tags: [reading]
updated: 2026-11-09T09:12:04.511Z
---
A line I selected and wanted to keep.

The filename is YYYY-MM-DD-<id>.md. The id is 6 random characters from [0-9a-z]. The date at the front makes ls sort by day for free. If a file loses its created field, Jot falls back to the date in the name, so the order stays stable.

Images and audio go in attachments/<id>/. A deleted note moves to .trash/<id>/, so undo is a rename back.

The problems a database would have solved #

Half-written files. If the app crashes in the middle of a write, the note is gone. So every write goes to a temp file next to the real one (.name.<16 hex>.tmp), and then a rename puts it in place. A rename is atomic on one filesystem. The rename lives in the folder entry, so Jot also syncs the folder, or a power cut can undo it. When Jot opens the vault, it deletes temp files left by a crash.

Reading every file, every time. Each operation lists the folder again. Parsing hundreds of files with YAML on each keypress is slow. Jot keeps a cache keyed by inode, mtime and size. An atomic write gives the file a new inode, so any change misses the cache, and a file that did not change is not parsed again.

A file someone else broke. You can edit these files in Vim, Obsidian or a script. If the front matter stops parsing, Jot leaves that one file out of the list, logs why once, and keeps going. It does not crash, and it does not "fix" your file.

Changes from outside. Jot watches the folder. If another program adds or edits a file, the inbox updates by itself.

That is the whole storage layer, in about 600 lines of TypeScript.

Then agents showed up #

I added a CLI first (jot list, jot search, jot add, jot tag, jot done, jot archive). Then jot mcp started an MCP server on stdio, so Claude Code, Codex and Cursor can use the same vault.

The MCP server has seven tools:

Tool What it does
list_jots List by status, section or tag, newest first
search_jots Case-insensitive match on body, tags, source app and URL
read_jot The whole file, plus absolute paths to its images
add_jot Create a note; the first line is its title
tag_jot Add tags; existing tags stay
set_done Mark done, or open again
archive_jot Hide from the inbox; the file stays

There is no delete tool, on purpose. An agent can add, tag, finish and archive. It cannot remove anything. The worst an agent can do is leave a mess you can see in Finder.

The server also does very little. It reads the files, changes the front matter, and writes them back with the same atomic write. The app sees the change through the folder watcher. There is no IPC between the server and the app, and the app does not need to be running.

Files help agents even without MCP #

Two generated files are for agents:

  • INDEX.md lists every note as a Markdown link with its title. An agent reads one file and knows what is there.
  • SKILL.md describes the layout: where files live, what the front matter means, and how ids look. Any agent that can read a folder can use the vault correctly.

So the setup for most agents is just this: "my notes are in ~/Documents/Jot, read SKILL.md." Something like "what was I thinking about last week" becomes a grep and a read.

What I gave up #

  • Sync. Jot does not sync. If you want it, put the folder in iCloud Drive or Syncthing. I have not built conflict handling for two Macs that write at the same time.
  • Fast queries over large vaults. Search is a substring scan over parsed files. That is fine for thousands of notes. For hundreds of thousands, I would add an index.
  • Schema migrations. The front matter is now an on-disk format that other tools read, so I can only add fields, not rename them.

For a capture inbox, these trades were worth it. Your notes outlive the app, every tool you already use can open them, and ls ~/Documents/Jot is the admin panel.

Jot is a Mac app for capture and dictation. It's free for 3 days, then $9 once at the launch price. sayjot.xyz

── more in #ai-agents 4 stories · sorted by recency
── more on @jot 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/my-notes-app-has-no-…] indexed:0 read:4min 2026-11-10 · —