Patchbay Go
/Deep-link wrapper

A tiny Cloudflare Pages worker that makes custom app URL schemes tappable from a chat message.
synodic-studio/patchbay-go· MIT
I built this for the Patchbay Relay workflow. When I run my studio from a phone, the agents back home constantly want to hand me a link: a note in my Obsidian vault, a reminder, a specific day in Calendar, a Things task. The natural way to do that is a custom URL scheme like obsidian://open?vault=.... The problem is that Telegram, and most chat apps, refuse to render a custom scheme as a link. It arrives as dead text. Tapping does nothing.
Patchbay Go is the fix. It wraps the custom scheme in an ordinary https:// URL, which every chat app renders as a single tap. It serves a one-line page that immediately bounces the browser to the real native-scheme URI, and the app opens on the phone. It lives at a short host — go.synodic.co — because a link you tap on the go should be terse.
How it works
https://go.synodic.co/obsidian/MyVault/notes/today.md
-> serves a tiny redirect page
-> obsidian://open?vault=MyVault&file=notes/today.md
-> Obsidian opens on the phone
The redirect page is about as small as a web page gets: a meta refresh to the native URI with a JavaScript fallback for browsers that ignore it. There is no auth, no logging, and no server state. The whole thing is one file with no runtime dependencies, and it costs nothing to run on Cloudflare’s free tier.
The reason it has to be a hosted https:// URL rather than something clever on the device is that the chat app is the gatekeeper. It decides what is a link, and its rule is “it looks like a web address.” So you give it exactly that, and do the scheme swap one hop later in the browser, where custom schemes are allowed.
Routes
Core routes cover the primitives, with a base64url escape hatch for anything else:
| Route | Opens |
|---|---|
/obsidian/<vault>/<path> | a note in an Obsidian vault |
/remind/<title> | Apple Reminders |
/cal/<yyyy-mm-dd> | a date in Calendar.app |
/cal/<yyyy-mm-dd>/<hh:mm> | a date and time in Calendar.app |
/raw/<base64url> | any native scheme, full URI base64url-encoded |
/key/<uuid> | an optional token-secured paste form |
On top of those, a set of named app routes means an agent almost never has to base64-encode anything. Content routes take a single value it can write in the clear:
/things/<title> /todoist/<content> /omnifocus/<name> /due/<title>
/bear/<title> /drafts/<text> /ulysses/<text> /shortcuts/<name>
/fantastical/<sentence> /zoom/<meeting-id>
/telegram/<username> /whatsapp/<phone> /x/<handle> /instagram/<username>
/googlemaps/<query> /waze/<address>
plus launchers like /music, /slack, and /podcasts that just open the app. The full list renders on the service’s own front page, and it is a single table in the source, so adding an app is one line. The named routes exist because https://go.synodic.co/things/Buy%20milk is something a language model writes correctly on the first try; /raw/ handles the long tail.
The /raw/ route is deliberately narrow: it refuses twelve browser-privileged schemes, so a wrapped link can only ever hand a native app scheme to the OS. javascript: and data: are the obvious ones. Refusing https: is the one people miss, and it is what keeps /raw/ from being an open redirect that would let anyone dress a phishing link in my domain.
The two pages a person ever sees are the redirect, which flashes by on the way into the app, and the /key form:


Handing over a secret with zero knowledge
The one route that does more than redirect is /key/<uuid>, an end-to-end encrypted handoff for getting a secret into an agent without typing it into a chat. The agent registers a public key and sends a /key/<uuid> link; tapping it shows a small labeled form, and the value the user pastes is encrypted in the browser to the agent’s key before it is sent. The service is oblivious by construction: it only ever stores ciphertext, it holds no key that could open it, and there is no setting I could flip to read what passes through. Zero-access encryption is the precise term for that property; zero-knowledge is the one people recognize. The agent decrypts on its own machine, where its private key has never been anywhere else. A quiet way to move an API key into your automation without it ever sitting in a chat log, or in the relay’s hands.
It runs on Cloudflare Pages on the free tier, and once it is deployed the agents start emitting tappable links on their own. The deploy guide has the Pages, KV, and custom-domain steps.