TARIKH KORULA FOUNDER & COACH
← Wisdom

CoS v2 - Cloudy Visions

CoS v2 - Cloudy Visions
v3 next: VPS + Agent SDK - the runtime moves onto a server for the principal controls.

v2 of building an AI chief of staff in public. Herein lies twelve scenes from cutting loose from the desktop and learning what running it from Anthropic's cloud actually entails. In this episode I explore moving my second brain to git and my scheduled tasks to routines in Anthropic's cloud. NGL all of this was far more complicated than I had intended or anticipated – tread lightly, dear reader.


TL;DR — the v2 upgrades

  • Brain in cloud: my "second brain" (all MD files) live in a private GitHub repo which syncs every 5 minutes from my laptop; the "heartbeats" run as Anthropic cloud Routines and also post daily updates to slack, no laptop required. v1 was desktop-only.
  • Cloud Routine prompts are an IDE with no debugger and no log file. Version every paste. My routines/ folder has five dated prompt versions in five days as receipts.
  • The Routine's Slack-post leg works reliably; the repo write-back leg fails silently. Build a sibling layer (mine is a desktop Cowork task) that verifies the file actually landed.
  • An autonomous heartbeat without an interactive answer-side is a questioner that asks no one and waits forever. The autonomous prompt and the live conversation are two layers; both have to be wired.
  • macOS won't let scheduled jobs run against ~/Documents/. I had to move the brain to my home directory (or anywhere TCC doesn't guard) before wiring automation against it.
  • Three disciplines fall out of all of it: daily artifact = delta, not state. Brain = runtime log, not end-of-day archive. ASKs = direct questions in a Cowork scheduled task, not passive labels

A month ago I shipped Kubrick 1000: an AI chief of staff that runs on the desktop, in a folder, in plain markdown. It was inspired by OpenClaw and I was trying to answer the question, do I have to buy a Mac Mini or can I get some of the same OpenClaw functionality as a personal agent inside Claude Cowork's GUI?

The goal was to try and give anyone scared of the command line (and all the privacy concerns associated with OpenClaw) a chance to build a personal agent in a much more user friendly fashion. I wanted it to be a single file anyone could drop into a Cowork project to get started and have it socratically prompt them to answer all the questions it needed to completely instantiate itself in Cowork. That worked and it's v1-desktop.md.

I put a number on it to commit out loud that this project has a roadmap. v2 is intended to be the cloud version of v1: still based in Cowork, but cut loose from the laptop, running the heartbeats in the cloud so you can shut the lid and have your chief of staff still working while you sleep.

This post documents getting to v2 - Kubrick 2000 - cloud routines and a private repo for my second brain.

What follows is twelve scenes from that process. Four are desktop-migration wiring: plugins, permissions, signing, paths. Five are cloud-Routine wiring: the prompts that drive an autonomous heartbeat are an IDE of their own, and they break in ways desktop scheduled tasks never did. Three are the disciplines all of this play surfaced. The wiring beats are how I learned each lesson. The discipline beats are the lessons.


Act 1 — Desktop migration wiring

1. The off-the-shelf piece needed to get pulled

The v1 plan to migrate was simple. Install Obsidian Git, point it at a private GitHub repo, let it auto-sync every five minutes. The plugin had millions of downloads and is the canonical sync mechanism in the Obsidian world. I planned for ten minutes of setup.

Or so I thought. Unfortunately, the plugin has been deprecated. It was pulled from the community registry sometime in the last year over a community dispute. Searching "Obsidian Git" returns two dozen forks and wannabes.

Lesson: don't treat any one community plugin as load-bearing infrastructure for a system I'm building to last. The v1 doc had it as the recommended path. The v2 plan needed a different bridge.

2. Five minutes of bash beat a plugin

The replacement was a launchd job, a shell script, a plist, and a five-minute interval.

cd ~/kubrick-brain && git add -A && git commit -m "auto-sync" && git push

That's the script. The plist tells macOS to run it on a timer. No plugin, no app, no GUI. It works whether Obsidian is open or closed, whether the laptop is awake or not.

When you're building a CoS for yourself, the canonical-plugin route looks like the safer bet. It's usually not. The bash version is shorter, more legible, and survives the registry deciding to remove the thing you depended on.

That said, I had been hoping to create a solution that would live entirely in Cowork for folks that are scared of Terminal. In these early days of agentic CoS, it's just not possible not to get your hands dirty on the CLI it seems. While I wish more folks felt comfortable there, I can't imagine any serious consumer intelligence will work this way. It feels like the Altair era of Personal Intelligence.

3. macOS doesn't want your scripts in your Documents folder

The launchd job loaded fine. Then it failed every run with Operation not permitted.

The brain at that point lived in ~/Documents/Projects/CoS - v1 - Kubrick1000/. Modern macOS protects ~/Documents/ from background automation by default. Terminal has access because I granted it on first use. launchd doesn't inherit that grant. I tried to add /bin/bash to Full Disk Access via System Settings; macOS silently refused (FDA grants only go to signed .app bundles now).

I ran two rounds of debugging on this before noticing the path was the problem, not the permissions. The fix was a mv. The brain moved from ~/Documents/Projects/... to ~/kubrick-brain/. The sync worked from launchd immediately.

Modern macOS pushes any serious automation OUT of the protected user folders. If you're going to run scheduled jobs against a folder, put it somewhere TCC (Transparency, Consent, and Control) doesn't guard. Your home directory, an /opt/ path, or a dedicated workspace folder. Just not Documents.

If it hasn't dawned on you already, this v2 really got into the weeds, perhaps unnecessarily so. At a high level, I don't really think the juice has been worth the squeeze on this one and I'm really interested in moving beyond Cowork and onto a VPS. I do wonder if there are folks at Anthropic working on this kind of consumer facing chief of staff. Google just announced Spark, OAI is building off OpenClaw and Hermes has 159k stars on Github. I can't imagine Anthropic doesn't have a team working on this.

4. The git config you forgot about will eat your commits

commit.gpgsign=true was set globally on my machine. Terminal had the GPG agent in scope; launchd didn't. Commits would start, acquire .git/index.lock, fail mid-flight on the signature step, and leave a stale lock behind.

The symptom looks exactly like a race condition. Two processes both trying to commit, fighting over the lock. It isn't. It's one process, half-finishing, twice in a row.

Took me a third pass through the script to think to check global git config. If you're running git from automation, audit every global config setting against the environment you're running in. Signing, hooks, credential helpers. They look invisible from the script's perspective, and they will break you silently.

v2 is one of those mammals that swims and walks on land and does neither well. I had wanted v2 to be accessible to anyone with a Cowork sub, but here I am on the command line. Oh well 🤷


Act 2 — Cloud Routine wiring

The desktop side migrates cleanly once those four are in place. The cloud side is where I assumed I was buying off-the-shelf reliability and discovered the reliability has its own issues, still being in beta.

The unit you wire in the cloud is a Routine: a prompt that fires on a schedule, runs in a sandboxed runtime with whatever MCP connectors you've granted, and posts output to a destination (in my case, Slack). It's the cleanest analog to a cron job in a managed environment. It's also a new IDE — and an immature one.

5. There was already an autonomous routine running on my account

When I started checking calendar entries to verify the new system, I noticed an event named Weekly Call showing up on Tuesdays. Brain had no idea what this was. No person, no project, no client. A mystery capture.

It was an old routine I'd set up on claude.ai/code/routines months earlier, before Kubrick existed, that produces a daily productivity briefing at 6:30 AM. The events on my calendar were its hallucinated reminders. The brain didn't know about it because I'd built Kubrick on top of my existing setup without auditing what was already running.

A chief of staff that doesn't know what's already running on its principal's behalf is going to keep producing mystery captures. If you're building a CoS pattern, do an audit pass of every automation, every cron, every scheduled task, every connected service, before you start adding new ones. The brain has to know its own runtime environment, not just the parts it set up itself.

6. The prompt is the IDE, and it's a draft

The four Kubrick heartbeats run as cloud Routines: morning brief, weekly recap, weekly goal-set, monthly consolidation. Each is a prompt of fifty to a hundred and fifty lines. The prompts read brain files, do MCP calls, write output to Slack, and (in theory) commit results back to the repo.

Make your own routines here https://claude.ai/code/routines

The prompts didn't work the first time. They didn't work the second time. Each one took five or six rewrites to get the structure and the failure modes right.

The loop is: write the prompt, paste it into the Routine UI, wait for the next fire, read the output in Slack, find the bug, rewrite, paste again. There is no debugger. There is no log file you can tail. The only signal is the output that gets posted. If the output looks right but the side-effect (the repo commit) silently failed, you find out three days later when a sidecar conversation asks where things stand and the brain hasn't caught up.

For anyone building on this layer: treat the prompt itself as the artifact under version control. Date the versions. Keep the old ones. The differences across versions are the only history you have of why the current one is shaped the way it is. The prompt isn't config — it's the program, and the program edits in production.

7. The Routine's write-back leg fails silently

The cloud Routine fired reliably to Slack. Same prompt, same connectors, every weekday morning. The brief landed.

The Routine is also supposed to commit its output to the brain repo so the file is on disk for tomorrow's brief to read. That leg fails silently. The Slack post succeeds; the commit-and-push never lands; the file isn't on disk. There's no error message. The next morning's brief reads yesterday's file and finds it missing, and rebuilds from assumptions.

The underlying cause is that the GitHub MCP available in cloud Routines seems to run in a PR-creation mode by default — fine for collaborative pull-request workflows, useless for an unattended single-user write-back. Direct commits would need a different code path. The Routine ends without erroring because, from its perspective, all the calls it made returned cleanly.

I solved this by adding a sibling Cowork task on the desktop side: weekdays at 7 AM, fifteen minutes after the cloud Routine fires, a local task wakes up, reads the Slack channel where the cloud Routine posted its output, and writes the file to disk using the same file tools that already work. Belt-and-suspenders. Ugly, but effective. The actual fix is for the cloud-Routine MCP to gain direct-commit mode (Note: maybe it has, I'm getting inconsistent results here). Until then, the desktop sidecar closes the gap.

For anyone building on this layer: every leg of a multi-step Routine needs an explicit verification step. Did the file actually land on disk? not Did the Routine finish without erroring? The two are not the same question.

8. The Routine doesn't verify closure state

This morning, while the new sibling task was firing for the first time, I caught a related failure. Yesterday evening I'd closed ten ASKs the brain had been carrying. Updated todos.md, wrote journal/2026-05-19.md, logged shots to shots.md, created a new domain file. All committed and pushed by midnight.

Today's brief, generated by the cloud Routine at 6 AM, surfaced eight of those ten ASKs as still open. It cited one as "5th brief without an answer," another as "since 5/8, ~8th brief, protocol failure signal." Confident, structured, wrong.

The Routine had composed today's brief by rolling yesterday's structure forward. The chart, the open-ASKs list, the framing — all came from yesterday's output, not from re-reading the current brain state. Captures that closed those questions had landed on disk before the Routine fired, and the Routine didn't check them.

This is the same family as the cron-job ghost in scene 5 and the silent write-back failure in scene 7. The cloud Routine confidently asserts state without verifying it against the underlying brain. Open items get carried forward. Closed items get carried forward the same way. The Routine has no built-in default-to-uncertainty about its own previous outputs.

The fix lives in the prompt: for every ASK the brief is about to surface, grep the Done section of todos.md and the recent journal entries for a closing capture. If found, skip the ASK with a one-line note. If not, surface it. Patch goes into the next version of the prompt.

For anyone building on this layer: assume the Routine will confidently repeat yesterday's claims, including the ones that have since become wrong. Build the closure-verification step into the prompt explicitly. Pre-read on disk does not equal happened. Listed as open in yesterday's brief does not equal still open today.

9. The heartbeat fires; the conversation doesn't

The Monday goal-set Routine fires every Monday at 7 AM. It posts a prompt to Slack asking, in second person, what the two or three most important things to move forward this week are.

Monday morning I'm usually on the laptop somewhere between 7 and 9. The Routine fires; I don't see it; I open Cowork and start working on something else; the goal-set never runs. The brain never gets a weekly/YYYY-W##-goals.md file. By Wednesday the morning brief is flagging "Day 3, file not on disk," and we're working off the previous week's carry-over.

The Routine did its job. It asked. It posted the question to Slack. That's not the same as the question actually getting answered by me. An autonomous heartbeat plus a chat-side answerer is a two-layer design. The first layer asks; the second layer has to drive the answer. If only the first layer fires, the second layer never engages.

The closure pattern is a sibling layer on the desktop: a weekday 7 AM Cowork task that reads the morning brief from Slack, pulls the open ASKs into a live conversation, prompts me on them one at a time, and writes the answers to the brain in the same turn they land. On Mondays the same task drives the weekly goal-set conversation if the file is absent.

I wrote about trying to use Dispatch as a mobile walkie-talkie to my CoS. It fell down badly. This open loop, plus the lack of mobile interactive comms with the CoS is what's going to make me jump to Hermes in v3.

For anyone building on this layer: the autonomous prompt and the interactive conversation are different machines. The Routine is the alarm clock; the conversation is the meeting. Both have to be wired. A heartbeat that fires into a Slack channel nobody opens is a heartbeat that asks itself questions and waits forever.


Act 3 — The disciplines

Five wiring beats in the cloud-Routine section. They all rhyme. The brain only knows what's written to it; the Routine only re-asserts what it was last told; the alarm only matters if the meeting actually happens. Three disciplines pop out of this.

10. The daily artifact foregrounds delta, not state

The morning brief used to render a compass chart at the top. North star → 2026 → Q2 priorities → this week → today's todos → the floor of failure-mode signals. I'd been getting it every weekday for two weeks.

Day fifteen, reading it on my phone over coffee, I noticed something. The top five layers hadn't changed in the entire two weeks. I knew my north star. I knew the 2026 criteria. I'd been writing them daily, reading them daily, and they were burning twenty-five lines of every brief to tell me things I hadn't forgotten.

We compressed it into a single wayfinding line. The full state still lives in the source files for any morning I'm off-course and need to re-read. The daily view became about delta: what moved yesterday, what's on for today, what's drifting. The brief dropped from seventy lines to thirty.

The principle: state has source files. The daily view is for what moved. A chief of staff that re-renders the full picture every morning is wasting your attention on things you already know.

This was a five-minute change applied immediately, and the next morning's fire used the new format. That loop is what you want a CoS pattern to have. It gets sharper under use, not just bigger.

11. The brain is a runtime log, not an end-of-day archive

Halfway through a day of v2 migration work, a fresh Cowork conversation asked me, in effect, "where are we at on this migration?" It read the brain and reported back: two of ten steps done, eight to go.

Reality at that moment: six of ten done. The substrate had moved. All four cloud routines were live. The v1 jobs were disabled. A chart format had been compressed. Most of those state changes had happened in chat, in MCP calls, in the Routine UI. Almost none of them had reached the brain in real-time.

The new conversation wasn't wrong about what the brain said. It was wrong about what was actually true.

The fix isn't more diligence at end of day. The fix is the inversion: the brain is a runtime log, not an end-of-day archive. Every state change is a log line, written in the same turn the action lands. If it's worth saying out loud or doing as an action, it's worth being on disk before the next message.

This is the load-bearing discipline of v2 specifically. v1 ran inside a single conversation; the brain was in the room, and most state changes happened as writes. v2 runs across conversations, across the cloud, across substrates. The brain has to be the source of truth, and the only way it stays the source of truth is if the agent writes to it in real-time.

12. Labels are filing; questions are asking

The week after the substrate change, the Friday recap fired. It labeled four of five weekly goals as ASK. The brain explicitly knew it didn't have enough information to grade the week. Then it stopped. Tagged the items. Posted them to Slack. Waited.

I had to come back hours later and force the move: ask me all the open questions you have.

The brain had the list. It wasn't using the list to drive the conversation that the list required. Once the verification round ran, every open question resolved inside an hour, and surfaced material the brain would have kept missing for weeks.

Labels are the failure mode. "X status: unverified." is filing. "Did X happen?" is asking. Heartbeats that fire autonomously to Slack and can't have a back-and-forth still have to ASK in second person, in the prompt itself. Every ASK, every pending, every unverified gets rewritten as a direct question. Otherwise it compounds.

Discipline 10 is design: foreground delta.
Discipline 11 is outgoing: write everything in real time.
Discipline 12 is incoming: ask everything that's open.

All three are about closing the loop that the v2 substrate exposes. When the chief of staff runs from the cloud and can't sit synchronously in a chat with you, the discipline that used to live in the chat has to live in the prompt. Active writes on one side. Active asks on the other. Compressed daily views in the middle. Three layers, all moving.


v3 is next

v1 was the desktop version. v2 is the always-on version: brain in a repo, heartbeats in the cloud, laptop optional. The build keeps going.

v3 will move it out of Anthropic's hosted runtime onto a server I control: VPS, Agent SDK, custom code. v4 takes it past any one vendor: multi-model, brain ports.

The substrate keeps changing. The chief of staff doesn't.

Public repo: github.com/tarikh/founder-cos. v1 blueprint is in there. v2 chapter lands alongside this post here:

If you're building something like this for yourself: do the audit pass first. Move out of ~/Documents/. Disable signing on the automation repo. Treat your Routine prompts as version-controlled programs, not config. Build closure-verification into every prompt. Wire a sibling layer that turns autonomous output into interactive conversation. And design the brain to be a runtime log, not an archive.

The substrate change forces the discipline. Better to bake it in than to discover it the hard way at 4 PM on a Thursday with six steps unfiled.

That's v2. Fin.