I Built a To-Do System Where Claude Code and My Browser Share the Same File
Every to-do app breaks the same way for me. So I built one as a single HTML file that syncs with Claude Code through a shared markdown file. No server, no database, no account.
I’ve tried every to-do app. Notion. Todoist. Linear. Apple Reminders. They all break the same way for me.
Not because they’re bad products. They break because they live in a tab I forget to open. Or behind a login I don’t feel like doing. Or they organise tasks the way THEY think I should, not the way my brain actually works.
Here’s what I actually need: I’m running 5 projects at the same time. An AI SaaS product, a workshop business, a data website, content marketing, and product builds. Some tasks are urgent. Some are important. Most feel like both, but aren’t. I need to see all of them ranked by what actually matters, not sorted alphabetically or by due date.
And here’s the thing that no to-do app handles: I work with Claude Code 8+ hours a day. Claude builds my websites. Claude writes my content pipelines. Claude deploys my projects. Half the time, a task gets completed INSIDE a Claude session. I’ll say “add street-level rankings to the block pages” and 20 minutes later it’s done.
But my to-do list doesn’t know that. It’s sitting in some other app, still showing the task as open. I have to manually go find it and check it off. Or I forget, and my list slowly fills up with ghost tasks that were finished days ago.
I wanted something where Claude could just mark things done when they’re done. No API integration. No webhook. No third-party sync. Just… update the same list I’m looking at.
The obvious solution that doesn’t work
My first idea: build a to-do list as a single HTML file. Double-click to open, see my tasks, check them off. Simple.
The first version used localStorage to save state. It works. You check a box, close the tab, reopen it, the box is still checked.
But localStorage lives inside Chrome’s internal database. It’s a LevelDB binary buried in your system files. You can’t read it. You can’t edit it with a text editor. If you clear your browser data, it’s gone. If you open the same file in a different browser, blank slate.
And Claude Code can’t reach it. The whole point was having a shared system, and localStorage is a black box that only Chrome can see.
”Can’t you just save it to a .md file?”
That was my exact question. Just write the data to a markdown file on my desktop. Claude can read and edit markdown files natively. Problem solved.
Except browsers won’t let you do that.
For good reason. Imagine if any HTML file you opened could silently read and write files on your computer. You’d visit one dodgy webpage and it could scan your Documents folder. So browsers block all local file access by default.
That left me with three options:
Export/import buttons. Download a JSON backup, re-upload it next session. Functional, but defeats the purpose. I’d have to remember to export every time. I would absolutely forget.
Run a tiny local server. A Node script that serves the HTML and handles file I/O. Works perfectly, but now I need to start a server every morning just to see my tasks. Not “double-click and go.”
File System Access API. A browser API that lets a webpage request permission to read and write a specific file on your computer. You pick the file once, the browser remembers, and it reads/writes directly. No server needed.
Option 3 won.
How it works now
Two files on my desktop. That’s the entire system.
accountability-tracker.html is the interface. Double-click to open. It renders my revenue targets, Eisenhower priority matrix, per-project task lists, sales pipeline, warm leads with copy-paste conversation starters, and a daily journal.
keith-accountability.md is the data. Plain markdown. Looks like this:
## Workshop Revenue
- Seats Sold: 2
- Revenue Collected: 200
## Tasks
### Cclarity
- [ ] DM 5 warm profile viewers this week | urgent | important
Alex, Sarah, James, Priya, Daniel. Conversation starters in Warm Leads.
- [x] Follow up with workshop sign-ups | urgent | important
Confirm attendance, send prep checklist.
### Data Website
- [ ] Pitch data story to 4 media outlets | not-urgent | important
Original research angle. One pickup = 10x traffic.
## Journal
### 2026-03-25
Sent 3 DMs today. Alex responded, wants to chat Thursday.
The first time I open the tracker, I click “Open Tracker File” and select the .md file. After that, Chrome remembers which file to use. Every change I make in the browser, checking a task, updating a pipeline number, writing a journal entry, writes back to the .md file immediately.
And here’s the part that makes it all worth it: Claude Code can read and update the same file. If I want to add a task during a coding session, I say “add this to my tracker.” Claude opens keith-accountability.md, adds the line, and saves. Next time I open my tracker in Chrome, it’s there.
Marking things done is intentionally manual. I don’t want Claude auto-checking tasks off just because some code shipped. “Shipped” and “done” aren’t always the same thing. Sometimes I want to verify. Sometimes the task was “ship AND test AND tell the client.” So Claude can add tasks, update descriptions, reorder priorities. But the checkbox stays mine.
No sync delay. No API. No account. Claude and my browser are literally editing the same text file.
Why not just use the markdown file directly?
Fair question. If the .md file is the source of truth, why do I need the HTML interface at all?
Because a raw markdown file doesn’t show me my Eisenhower matrix. It doesn’t show me a revenue progress bar filling up. It doesn’t give me a countdown telling me I have 36 days until my deadline. It doesn’t group the same tasks into two views, one strategic, one operational, without duplicating them.
The markdown file is for storage and interoperability. The HTML file is for thinking.
The Eisenhower matrix was the real unlock
Once persistence worked, I started actually using this daily. And I immediately hit a new problem: I had tasks across 5 projects and no way to see what was ACTUALLY urgent versus what just felt urgent.
I added an Eisenhower matrix at the top. Four quadrants: Do First (urgent + important), Schedule (important, not urgent), Delegate (urgent, not important), Eliminate (neither). Filter pills let me switch between all projects or drill into one.
The design decision that mattered: tasks added to the matrix ALSO appear in their project section below. Same data, two views. The matrix tells me “what should I do RIGHT NOW.” The project sections tell me “what’s the full picture for CheckHowMuch.” I don’t maintain two lists. The .md file stores each task once, with pipe-delimited priority tags:
- [ ] Task title | urgent | important
The HTML parser reads those tags and sorts tasks into the correct quadrant automatically.
Making it feel alive
The functional version worked. But it felt flat. Every number just appeared. Every interaction was instant with no feedback. It felt like a spreadsheet wearing nice clothes.
I went through my UI component library (UseLayouts and TripleD catalogues) and picked 6 targeted improvements:
Counter-up animation. When the page loads, the countdown numbers, scorecard, and pipeline all animate up from zero. Takes 600-800ms with an ease-out cubic curve. The page feels like it’s waking up.
Number pop. When you click +/- on any counter, the number briefly scales up 20% then bounces back. A tiny thing, but it makes every click feel like it registered.
Staggered task entrance. When you switch the matrix filter, tasks don’t all appear at once. They fade in one by one with 40ms delays. Makes filter changes feel smooth instead of jarring.
Checkbox draw-in. The checkmark SVG stroke animates along its path using stroke-dashoffset. Combined with a subtle scale bounce on the circle. Checking off a task feels intentional.
Progress bar shimmer. The revenue progress fills have a sweeping highlight animation. Subtle, but it draws the eye to the numbers that matter most.
Card hover lift. Every card lifts 2px on hover with a deeper shadow, using spring easing (cubic-bezier(0.34, 1.56, 0.64, 1)). Makes the whole page feel interactive without being distracting.
One bug I caught early: the staggered entrance animation was replaying every time ANY part of the page updated. Click +1 on workshop seats, and all the matrix tasks would blink. The fix was surgical rendering. Instead of calling render() (which rebuilds everything), each action only re-renders the sections it actually changes. updateSeats() only calls renderRevenue(). toggleTask() only calls renderMatrix() and renderProjects().
What I’d do differently
If I were starting over:
I’d use the File System Access API from day one. The localStorage detour taught me something, but it was time I didn’t need to spend. If your HTML tool needs persistent data and you’re the only user, this API is the answer.
I’d design the .md format more carefully upfront. I went through two iterations of the task format before landing on - [ ] Title | urgent | important with indented descriptions. Getting the parser right the first time would have saved some back-and-forth.
I’d separate render functions from the start. The “render everything on every change” pattern is fine for small apps, but the moment you add CSS animations, it creates visual bugs. Targeted rendering should be the default.
Why this actually changed my mornings
I’ve tried to-do apps that cost $15/month. I’ve tried Notion databases with 12 properties per task. I’ve tried a plain text file. None of them stuck longer than two weeks.
This one stuck because it removed every friction point that made me stop using the others.
No login. Double-click a file. No sync issues. It’s one file on my desktop. No “I forgot to add it.” Claude adds tasks for me during work sessions, so nothing falls through the cracks. No “everything looks equally important.” The Eisenhower matrix forces me to be honest about what’s urgent versus what’s comfortable.
I open it every morning now. I see 36 days until my deadline. I see which DMs I haven’t sent. I see the media pitch sitting in “Schedule” that I keep avoiding. And I see the tasks Claude added yesterday during a build session that I’d already forgotten about.
The whole system is two files. One is 97 lines of markdown. The other is an HTML file I’ll probably never touch again.
The best productivity tool isn’t the one with the most features. It’s the one you don’t have to think about using.