Setu
Operator chat. Browser and mobile send, Claude Code answers from your desk.
Sutra is the desktop daemon that runs quietly on your Mac. Chat from the browser, your phone, WhatsApp, or Telegram — and Claude Code, running locally on your machine, answers back. One process, five products, every channel.
No shared agent in the cloud. Your Claude Code runs on your Mac with your keys. Sutra is the wire, not the brain.
Browser, mobile, WhatsApp, Telegram — they all wake the same desktop daemon. Add a channel, not a service.
Setu, Sandesh, Swayam, Sankalp — each is its own dashboard with its own CC brain. Sutra is what ties them together.
Your message lands on Vercel, broadcasts over Supabase Realtime, gets picked up by Sutra running on your Mac, and reaches Claude Code via a local MCP. The reply rides the same wire back. No cloud agent, no shared inference — just your CC, your laptop, your keys.
Each product is its own surface — its own dashboard, its own CC workspace, its own MCP sub-server. Sutra is the seam they share. Adding a fifth product is one more channel, not a rewrite.
Operator chat. Browser and mobile send, Claude Code answers from your desk.
Content workshop. Draft, render, and confirm posts across LinkedIn, Threads, Instagram, YouTube.
Scheduled routines. Cron-fires wake a dedicated CC that posts to your daily briefings thread.
Job-application autopilot. Drafts answers from your profile, reviews via Claude-in-Browser.
Sutra is small on purpose. Each subsystem owns one wire — your bug is always one file away.
Four OAuth-protected sub-servers at 127.0.0.1:9000 — chat, sandesh, swayam, sankalp. Your Claude Code attaches here, not to the cloud.
Supabase Realtime broadcasts arrive in Electron main, are filtered per product, and translated into notifications/claude/channel frames that wake the right CC.
Stream your screen to the Setu web app, mobile, or another machine. STUN-only, no relay server, no JWT rotation — channel name is stream:<uid>.
Five browser_* MCP tools that drive the Claude-in-Browser side panel via CDP. Logged-in scraping, posting, and form-fills run inside your browser.
pg_cron emits routine_fire; the Swayam CC picks up wakes via metadata.channel, executes the prompt, streams output to your briefings thread.
Every chat-write fires FCM or Expo push so the answer lands on your phone whether the PWA is open or backgrounded.
One Electron process runs eight subsystems against one Supabase project. The diagram below is the live wire — every node maps to real code paths.
[ cloud ]
vercel + supabase
Browser / Mobile / PWA
inserts chat row → broadcasts on user:<uid>
Vercel · Next.js /api
route handlers · runtime nodejs
Supabase · Postgres + Realtime + pg_cron
one project · per-product table prefix
project-memory · pgvector
code-sync worker indexes commits
[ sutra · your mac ]
electron 33 · node 20
SSE bridges (4)
setu · sandesh · swayam · sankalp
Loopback MCP @ 127.0.0.1:9000
/setu · /sandesh · /swayam · /sankalp
Claude Code (local)
your keys · your machine · per-channel CC instance
Push fan-out
Firebase Admin (FCM) + Expo REST · fire-and-forget
Browser-bridge (CDP)
side-profile Brave + Claude-in-Browser panel
WebRTC capture host
screen + control for stream:<uid>
p50 wake
~180ms
mcp mounts
4
sse bridges
4
auto-PRs
0
One Node HTTP server, four mounts: /setu/api/mcp, /sandesh/api/mcp, /swayam/api/mcp, /sankalp/api/mcp. Each sub-MCP registers its own tool surface but shares the Supabase client, push dispatcher, and browser-bridge. Splitting per product keeps tool budgets focused; the shared singletons keep one CC session from racing another over a Realtime channel.
sse-stream.ts / sandesh-sse-stream.ts / swayam-sse-stream.ts each subscribe to one Realtime channel and translate broadcasts into notifications/claude/channel frames. Re-subscribe is exponential-backoff capped at 8s, and the client subscribes before loading missed rows via lastSeenCreatedAt. Closes the 2026-04-30 Realtime miss bug.
dispatchPushFireAndForget reads pa_mobile_push_tokens.provider per device and dispatches via Firebase Admin SDK (raw FCM) or Expo Push REST. Called from every chat-write surface (chat_message, sandesh_ideate_message, cc_message, sankalp_*). Never awaited on the response path — the chat reply never blocks on Google.
Five browser_* MCP tools attach via the DevTools Protocol (CDP), open the Claude-in-Browser side panel on a specific tab, and dispatch Act prompts. Replaced the homegrown setu-browser-extension on 2026-05-13: one less subsystem, port 9001 freed, and logged-in workflows (LinkedIn, Threads, Naukri) inherit Anthropic's extension trust.
Schedules live as cron jobs inside Supabase, not Vercel. routine_fire rows carry metadata.channel='swayam' so dispatcher.ts writes user-rows to swayam_messages (not chat_messages) and broadcasts swayam_chat_message. Setu CC never gets woken by routines; the Swayam CC has its own brain file and its own loopback MCP at /swayam/api/mcp.
Supabase Realtime in Electron main forces realtime: { transport: ws } because Node 20 lacks native WebSocket. Self-chat external_ref is pinned to the canonical phone (the LID rotates on re-pair) but outbound must route via <lid>@lid. Two days of debug compressed into two flags.
Sutra runs on macOS — Apple Silicon today, Intel-Mac and Linux on the roadmap. You'll need Claude Code installed; everything else, Sutra brings.
Signed for macOS Apple Silicon. ~120 MB.
The first launch will copy your legacy `~/Library/Application Support/setu-host/` config over automatically if you came from the old build.
Opens Setu OAuth in your default browser. Sutra captures your user_id and discards the JWT — no token rotation to babysit.
The dashboard has a launch button per product. Click it; a Terminal opens with `claude` attached to the right channel.
$ git clone setu/sutra && cd sutra $ pnpm install $ pnpm build:install # builds signed DMG, replaces /Applications/Sutra.app, relaunches
Unsigned during private beta. xattr -d com.apple.quarantine if Gatekeeper objects.