सूत्र · the binding thread

The bridge between you
and Claude Code.

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.

Local-first by design

No shared agent in the cloud. Your Claude Code runs on your Mac with your keys. Sutra is the wire, not the brain.

One process, every channel

Browser, mobile, WhatsApp, Telegram — they all wake the same desktop daemon. Add a channel, not a service.

Five products, one seam

Setu, Sandesh, Swayam, Sankalp — each is its own dashboard with its own CC brain. Sutra is what ties them together.

How it works

Every message you send, answered locally.

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.

Browser
/dashboard
Phone (PWA)
home-screen install
WhatsApp · Telegram
channel webhooks
Sutra
127.0.0.1:9000
MCP · SSE · push
Claude Code
on your Mac · your keys
← chat_respond_begin
← chunk · chunk · chunk
→ message_final
What it connects

Four products, one thread.

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.

Setu

bridge

Operator chat. Browser and mobile send, Claude Code answers from your desk.

setu-channel

Sandesh

message

Content workshop. Draft, render, and confirm posts across LinkedIn, Threads, Instagram, YouTube.

sandesh-channel

Swayam

self / autonomous

Scheduled routines. Cron-fires wake a dedicated CC that posts to your daily briefings thread.

swayam-channel

Sankalp

resolve

Job-application autopilot. Drafts answers from your profile, reviews via Claude-in-Browser.

sankalp-channel
Inside Sutra

Six subsystems, one Electron process.

Sutra is small on purpose. Each subsystem owns one wire — your bug is always one file away.

Local MCP server

Four OAuth-protected sub-servers at 127.0.0.1:9000 — chat, sandesh, swayam, sankalp. Your Claude Code attaches here, not to the cloud.

SSE wake bridges

Supabase Realtime broadcasts arrive in Electron main, are filtered per product, and translated into notifications/claude/channel frames that wake the right CC.

WebRTC capture host

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>.

Chrome bridge

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.

Scheduled routines

pg_cron emits routine_fire; the Swayam CC picks up wakes via metadata.channel, executes the prompt, streams output to your briefings thread.

Push fan-out

Every chat-write fires FCM or Expo push so the answer lands on your phone whether the PWA is open or backgrounded.

Engineering case study

The system, end-to-end.

One Electron process runs eight subsystems against one Supabase project. The diagram below is the live wire — every node maps to real code paths.

system map · liveone node process · eight subsystems

[ 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

Key engineering decisions
01

Loopback MCP at 127.0.0.1:9000 with sub-MCPs per product

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.

02

Per-channel SSE bridges with WS-state-aware re-subscribe

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.

03

Push fan-out provider split (Expo + FCM), fire-and-forget

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.

04

Browser-bridge via CDP + Claude-in-Browser dispatch

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.

05

pg_cron-driven routine dispatcher with channel bifurcation

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.

06

WhatsApp Baileys host: LID vs phone, ws transport on Node 20

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.

Install

Four steps, about two minutes.

Sutra runs on macOS — Apple Silicon today, Intel-Mac and Linux on the roadmap. You'll need Claude Code installed; everything else, Sutra brings.

  1. 01
    Download the DMG

    Signed for macOS Apple Silicon. ~120 MB.

  2. 02
    Drag Sutra into Applications

    The first launch will copy your legacy `~/Library/Application Support/setu-host/` config over automatically if you came from the old build.

  3. 03
    Sign in once

    Opens Setu OAuth in your default browser. Sutra captures your user_id and discards the JWT — no token rotation to babysit.

  4. 04
    Launch any CC

    The dashboard has a launch button per product. Click it; a Terminal opens with `claude` attached to the right channel.

build from source
$ git clone setu/sutra && cd sutra
$ pnpm install
$ pnpm build:install
# builds signed DMG, replaces /Applications/Sutra.app, relaunches
Download Sutra 0.1.0 — Apple Silicon

Unsigned during private beta. xattr -d com.apple.quarantine if Gatekeeper objects.