Skip to main content

← BlogObsidian · MCP · Cloudflare

Obsidian moved into my AI hub: one connection to every service, and diagrams the agent draws

My Obsidian vault now lives on Cloudflare, and kosh is one MCP connection to tasks, notes, Telegram, Go-Alpha, Instagram and my Mac. The agent draws Excalidraw diagrams right in the vault. How it is built, and where it stops.

Published Oct 31, 20267 min read

TL;DR

My Obsidian vault no longer lives on my Mac. It lives on Cloudflare, in kosh-vault. The Mac and the iPhone sync with it through the Self-hosted LiveSync plugin.

kosh is my personal AI hub. It is one MCP connection with all my services behind it: tasks, notes, Telegram, Go-Alpha, Instagram, my Mac's watchdog and a shell on it.

And the agent now draws Excalidraw diagrams right in the vault. I open Obsidian and see its thinking as a picture. I can fix it by hand, and the agent sees my edits.

What hurt

There were two problems. Under each: how it was, and how it is now.

1. Every service was its own connection

BEFORE — 5 connections:

Claude ──▶ tasks
Claude ──▶ Telegram
Claude ──▶ Go-Alpha
Claude ──▶ Instagram
Claude ──▶ notes (Mac only)

NOW — 1 connection:

Claude ──▶ kosh ──▶ all of these services

It was the same in every client: Claude Code, claude.ai, the phone. A new service had to be added to each one separately. And Claude could edit notes only on the Mac.

2. The agent's edits took the long way to my notes

BEFORE:

agent ──▶ GitHub ──(up to 2 min)──▶ Mac ──(iCloud)──▶ iPhone

NOW:

agent ──▶ kosh-vault ──(~1 s)──▶ Mac and iPhone

Before, the Obsidian Git plugin pulled the edit from GitHub — up to two minutes, and only while Obsidian on the Mac was open. To reach the iPhone, it also had to go through iCloud. Now the vault is in the cloud, and the Mac can sleep.

The vault moved to the cloud

I wanted one source of truth. One that does not fall asleep with the laptop.

I found a ready-made project: livesync-workers, a backend for the Self-hosted LiveSync plugin on Cloudflare Workers. I forked it and called it kosh-vault.

The truth is now an SQLite database in a Durable Object. Obsidian on the Mac and on the iPhone holds a live connection to it and gets every change in about a second. Obsidian over websockets, really.

The Mac can sleep — the vault is still there for agents. Every other copy just follows the cloud: an hourly backup to GitHub and a read-only mirror in iCloud.

One setting without which “live” does not work: LiveSync needs keepReplicationActiveInBackground: true. Otherwise sync pauses while the Obsidian window is hidden behind others, and the agent's edits arrive only when I look.

kosh — one door

kosh is a few Workers on Cloudflare. The name comes from the Cossack kosh, the headquarters of the Sich.

Inside, every service stayed separate. Telegram and Go-Alpha run in Cloudflare Containers. Instagram is a plain Worker. Notes are kosh-vault. But from the outside there is one entrance: /mcp.

What it means in practice:

  • The hub gathers every service's tools into one list under their own names. A client sees one connection.
  • Services talk to each other over Cloudflare service bindings, not over public URLs with a shared token.
  • I paste third-party keys on one connections page. They are stored encrypted, and nothing ever displays them again.
  • When a service is down, its tools stay in the list, and a call honestly answers “unavailable”.

The whole point of kosh was that all my services are reachable through it, instead of connecting each one separately.

Tasks are just markdown

My only task system is notes in the vault. One zone, one file. Priority is an Obsidian Tasks emoji on the line.

The agent adds, moves and closes tasks with the tasks_* tools. Every write is checked against the content hash: if the file changed underneath, the operation runs again. And every edit lands as a line in the journal.

kosh draws the task board itself, in an Excalidraw file. I change a list by hand, and within a minute a cron notices and redraws the board. It writes the board only when something on it really changed.

The agent draws diagrams

This is the newest part. Four tools: drawing_list, drawing_read, drawing_create, drawing_edit.

I ask: “draw how this process works”. The agent creates an .excalidraw.md file in the vault. A second later it is on my Mac, and the Excalidraw plugin opens it as its own.

agent
  │ asks to change the diagram (drawing_edit)
  ▼
kosh
  │ writes the drawing file
  ▼
kosh-vault (Cloudflare)
  │ LiveSync delivers it, ~1 s
  ▼
the open drawing in Obsidian updates

The Excalidraw plugin has its own CLI. But it needs Obsidian running on the Mac. So kosh writes the file itself, in the plugin's format, and works even while the Mac sleeps. Every rule below was tested against the real plugin:

  • Every changed element gets a new version, no lower than the current time in seconds. Otherwise an open drawing silently ignores the edit.
  • Delete with the isDeleted flag. An element that simply vanished from the file stays in the open view and comes back with the next save.
  • Text changes in two places: the JSON and the Text Elements section. Text Elements wins.
  • The file is written compressed, the way the plugin writes it. Then an open view has no reason to save it again.

The agent does not have to work out the layout: there is an automatic one. 80 blocks and 118 arrows in six sections are laid out in 2.9 seconds. I looked at the first real diagram in my Obsidian and said: “yes, it's all great”.

Honest limits

The weakest spot is a drawing open on my screen while the agent edits it.

After the first outside edit the plugin saves the drawing once more. If the agent writes again before that save has reached the cloud, LiveSync ends up with a conflict.

A conflict loses nothing: LiveSync keeps both versions. But the note freezes on disk, and a “Conflicting changes” dialog pops up. Here is what a live test showed, with edits one after another to an open drawing:

Pause between editsWrites acceptedConflict dialogs
15 s250
5 s301
1 s31
no pause61

The samples are small. It is a tendency, not statistics. A pause is not a guarantee.

So kosh learned to merge these conflicts itself. It takes the common ancestor of the two versions and compares them element by element. I changed block C, the agent changed block A? Both changes stay, and the dialog closes on its own in about 10 seconds. The same test after the fixes:

Pause between editsWrites acceptedConflict dialogs
5 s240
1 s291 — closed itself in 12 s

What kosh deliberately does not merge: both sides changing the same element. Both versions may be my own work, so that dialog is left to me. kosh also leaves a conflict between two of my devices alone — it only touches one where a version is its own.

Traps I stepped on

  • Linter broke drawings. One of its rules lowercased section headings. The Excalidraw plugin looks for them case-sensitively, so it stopped seeing them, and every save appended one more section. Fix: exclude .excalidraw.md from Linter.
  • Do not start a second Obsidian on the same Mac. A test copy with a separate home folder raised a system dialog offering to reset my Keychain.
  • The shell on the Mac is not a sandbox. kosh can run a command on my laptop as me. So anything that deletes, installs, pushes or touches keys goes only after my “yes” to that exact command. And I can switch the channel off with a file on the Mac itself.
  • livesync-workers is a young project with one author. Hence the fork, and the hourly backup to GitHub.

What it gives me

I open any Claude client — on the Mac, in the browser or on the phone. It already has everything: tasks, notes, Telegram, research, the Mac's health.

And what is hard to keep in my head, the agent puts on a canvas. I look, fix it by hand, and the agent sees my edits.

One connection, one source of truth, and a diagram instead of a wall of text.

Spot a mistake?

A wrong fact, an off translation, something that reads false in this article? Tell me — in your own language.