Resumable, streaming, offline-tolerant.
Sessions are server-owned
When you fire a trigger, SessionSpawnerService.spawnForFlow() creates a claude-code
subprocess on the orchestrator box. The session lives on the server — your phone is just a viewer.
Close the app, swap Wi-Fi, take a call: the session keeps running.
Live output over Socket.IO
The WebSocket gateway (implemented with Socket.IO) re-broadcasts each session's stdout + tool events to any subscribed client. Multiple devices can watch the same session at once. The PWA stores the last few events locally so the shell feels responsive when you reconnect.
Channel replies
Separate from the UI stream, ChannelDesk routes the session's final reply back to the inbound channel
via its MCP reply tool. So a Telegram user gets a Telegram message, a Slack user gets a
Slack message — even though both hit the same orchestrator.
Offline-tolerant UI
The Angular service worker aggressively caches the app shell. One known quirk: if your origin was ever gated by Cloudflare Access and the SW cached the challenge HTML, it will keep serving that until unregistered. ChannelDesk ships a "hard refresh" button in settings for exactly this case.
Claude-CLI login refresh
If the orchestrator is using claude CLI login (instead of a raw API key), Anthropic currently
requires a manual SSH + claude login roughly every 3 days. ChannelDesk surfaces expiry in the UI
and can ping you on a configured channel before it happens.
Same desk, in your pocket
The PWA is the same Angular app, installed to your home screen. Service-worker caching keeps the shell snappy on hotel Wi-Fi; live socket streams reconnect automatically when you come back online.