Multiple AI terminals. All waiting. And I wasn't at my desk.
COACH was mid-build on a fitness app. CRAFT was adding CI workflows. PERSONAL-SITE was reviewing content. Three Directors coordinating above them. All running Claude Code, all paused at different points asking me things - and I was in a car, phone in hand, wondering why managing an AI fleet requires being physically present at a laptop.
I'd been thinking about this wrong. I kept imagining some notification system, some API layer, some way to route Claude's questions to my phone. Then it hit me.
A markdown file IS the message. Frontmatter for routing. Checkboxes for options. A Reply field for free text. Both sides understand markdown natively. No translation layer. No API. No dumbing anything down.
That's the whole thing, honestly. Everything else is just plumbing.
One Word Woke Up the Fleet
I opened Obsidian on my phone and typed "pulse."
One word in a markdown file, dropped into CTO/outbox/. iCloud synced it to my laptop in a couple seconds. On the laptop, a watcher script had been sitting idle:
fswatch -0 --latency 60 "$INBOX" | while read -d '' file; do
CTO=$(cmux list-workspaces 2>/dev/null | grep "CTO" | grep -v "WATCHER" | awk '{print $1}')
cmux send --workspace "$CTO" "/director:cto-pulse" 2>/dev/null
cmux send-key --workspace "$CTO" enter 2>/dev/null
done
No server. No webhook. Just fswatch with a 60-second debounce and a laptop that stays awake with caffeinate.
I tried fswatch without the debounce first. Event-driven, elegant - and completely wrecked by iCloud. Every sync triggers metadata updates before the actual content lands. .DS_Store, extended attributes, partial writes. Three false wakes before the real event, and the race condition between wake and re-arm meant I'd miss the actual file while recovering from a ghost one.
The fix wasn't switching to polling. Actually it was the opposite - a longer debounce - 60 seconds. Aggressive enough that the file is fully landed by the time the handler fires. Feels slow though. But it's never wrong, and that matters more.
"Zero tokens while idle. Wakes within seconds when a file lands"
The AI Fleet Doesn't Read Every Screen
First thing it does is run cmux list-notifications. One command. Returns who's waiting, who finished, who needs a decision. No token burn scanning seven terminals - just a clean list of who actually needs attention.
Then targeted reads only for those. cmux read-screen --workspace workspace:10 --lines 50. CRAFT's last message: "Want me to do a full read of the files I haven't covered yet?" That's a decision for me, not for the machine.
So the CTO writes a note. Not a raw terminal dump - I tried that, it's unreadable on a phone. Not a summary either - summaries decay. Come back three hours later and you've forgotten what "story 3" meant. What actually works: bold labels, one fact per line, a recommendation, and checkbox options where each one maps to the exact text that gets typed into the terminal.
That note lands in CTO/inbox/CRAFT.md. iCloud syncs it to my phone. I check a box. I move the file to CTO/outbox/. The move IS the submit. No button. No confirmation. A file in the outbox is a sent message.
But here's the part that makes it actually useful vs. just clever - stalled detection.
The CTO classifies what it finds:
- Waiting:
cmux list-notificationsflagged it. Terminal needs input. - Stalled: notification-quiet, but context shows an obvious next step. A terminal that just created a backlog story and stopped isn't done - it has unfinished work and just... didn't keep going. The CTO reads the screen, recognizes it, and suggests the next move.
- Working: mid-execution. Leave it alone.
A dumb relay forwards questions. The CTO reads the room. That's what makes this feel like management instead of babysitting though.
Three Tiers, Adjacent Layers Only
The fleet has a chain of command:
Darin (Obsidian)
<-> CTO terminal
<-> Directors (COACH DIRECTOR, CRAFT DIRECTOR...)
<-> Workers (COACH, CRAFT, PERSONAL-SITE...)
Directors manage Workers. CTO only talks to Directors. When the pulse ran this morning, it saw COACH working and COACH DIRECTOR idle. Worker busy, Director idle - that's fine. Director is letting the Worker cook.
But COACH stalled with COACH DIRECTOR idle? That's a dropped ball. CTO flags the Director, not the Worker. It never reaches over a Director's head without asking me first.
Each layer talks to adjacent layers only. That's it. No framework. The routing is YAML frontmatter - every message has a type field (pulse, kill, dm-message, feedback) and a to: field for dispatch. Conventions on top of files.
This Is What Shows Up on My Phone
Real note from today. This is exactly what it looks like in Obsidian:
---
from: PERSONAL-SITE DIRECTOR
workspace: workspace:5
project: personal-site
status: pending
created: 2026-03-29T18:25
type: pulse
to: PERSONAL-SITE DIRECTOR
---
## PERSONAL-SITE DIRECTOR - dm-handoff gap
**Fixed:** Director acknowledged the mistake, invoked craft-direct,
and is now spinning up a Worker terminal.
**Root cause:** The dm skill ends after conversation completes,
but never tells the Director to start craft-direct. Director
improvises - chose craft-story-new (do it myself) instead of
craft-direct (spawn a Worker and supervise).
**The gap:** No handoff step between "DM complete" and "start
directing implementation."
**My recommendation:** Add a Phase 4 to dm-handoff where CTO
sends craft-direct after processing dm-complete. Keeps
orchestration where it belongs.
---
- [ ] Fix in dm-handoff (sends `Update dm-handoff Phase 4`)
- [ ] Fix in dm skill (sends `Update dm skill instead`)
- [ ] Both (sends `Do both`)
**Reply:**
That's root cause analysis with a recommendation and three options. Each checkbox shows exactly what gets sent via cmux send. I can check a box or type in Reply - free text goes verbatim.
What did I actually type to generate that? One word. "pulse."
Oh, and the Drag Story
I wanted to review next week's workout schedule. I dragged dm-message.md from CTO/create/ into the outbox, wrote one line: "Review next week's generated workouts and send me the schedule."
The system expects me to duplicate the template and leave the original in place. I never do that. I drag it every time. And every time, CTO wakes up, processes my message, then checks CTO/create/ and finds the template missing. So it recreates it.
That cleanup step - verify all templates exist, recreate any that are missing - exists because of me. The system adapted to how I actually use it instead of how I was supposed to use it. That's the kind of thing you can't plan. It just emerges when you actually live in the system.
COACH Director got the message, curated the workouts, sent them for review. I left notes on two that felt too grip-heavy back to back, approved the rest. They went straight to production. Director also proposed a new sticky header format and updated OG image. I reviewed both in Obsidian, revised the header spacing, approved the image. All from my phone.
By the time the car was done, three terminals were unblocked and shipping code.
The Stack Is Boring on Purpose
iCloud is the file sync - but any sync works. The watcher is fswatch with a long debounce. The terminal bridge is cmux. The routing is YAML frontmatter on markdown files.
Obsidian is the one piece that's not interchangeable though. It's a knowledge graph. Every decision note links back to the project that spawned it. Every archived conversation is backlinked. When the CTO writes a recommendation, it can search across every past decision for that project. Take away the knowledge graph and you've got a message relay. Keep it and you've got something that actually gets smarter over time.
No servers. No databases. No APIs. Just files in folders with conventions on top. The crystallized agents I use to give the fleet eyes run the same way.
The thing I keep coming back to: I wasn't trying to invent a protocol. Files are already a protocol. Both sides - me and Claude - already understand markdown. The insight wasn't technical. It was noticing something that was already there.
What are you already using that could do the same thing?
Resources
- Obsidian - The knowledge graph that powers the vault. Free for personal use, syncs via iCloud.
- cmux - Terminal multiplexer with workspace management, screen reading, and notification API.
- Claude Code - The AI terminals running in each workspace.
- Coach - Fitness coaching app built by the
COACHterminal. Coming soon to the App Store.