Inspiration
I came into this hackathon planning to do the obvious thing: wire an LED, a buzzer, and a button to Caspian and call it "control your home from chat." A few days in, I realized that demo didn't actually need Caspian — three webhook calls could do the same job. If the SDK's whole point is one agent identity reaching a human across many channels, the interesting question wasn't "can I turn on a light from Telegram," it was "can an agent decide, on its own, how urgently and where to reach someone — and know when to stop."
That reframing is where Asha Iris came from. I'd already built ASHA, an agentic smart-home system for my final-year capstone (ESP32, MQTT, a WhatsApp-native MCP server, a Twi speech pipeline). Caspian was the missing multi-channel front door for it — but only if I built something Caspian itself doesn't ship yet.
What it does
Iris is an agent that sits in front of every connected channel at once — Telegram and Discord for this build — and:
- Resolves one identity for a person no matter which channel they're on
- Can be told to watch for something (a physical sensor event, or just a timer) and proactively notify the right contact when it happens
- Escalates across channels if the first attempt goes unanswered, and stops the moment someone actually replies — on any channel, not just the one it messaged first Separately, Iris's messaging layer (CAAM — Caspian as an MCP) is exposed as its own MCP server, so any MCP-capable agent — Claude, Copilot, a custom agent — can send and receive through Caspian as tools, without hand-rolling channel adapters. Caspian's own roadmap lists an MCP server as something they haven't built yet; this fills that gap.
How I built it
I started by actually reading Caspian's source, not just the docs — the first real finding was that capabilities=["INITIATE"] isn't a free-text field, it's a fixed set the server validates, and Telegram/Discord/Slack don't get INITIATE at all (only SMS/iMessage can cold-start a conversation — a real platform constraint, not a Caspian gap, since bots generally can't DM someone who's never messaged them first). That single finding reshaped the whole product: "message anyone, cold, from a name" isn't possible on the free channels, so the real design became "remember everyone who's ever messaged you, and reach them there."
For the agent loop itself, I compared hand-rolling it (which I'd already done once, in TypeScript, for a WhatsApp-native version of ASHA) against adopting the OpenAI Agents SDK in Python. The SDK's tool-call loop and MCP client wiring were worth adopting; its session/memory layer wasn't a fit for what I needed, so I kept my own Redis-backed history and identity store instead of forcing everything into Sessions.
The escalation engine was the hardest design problem: an MQTT event and a task record needed to be correlated without inventing a UUID scheme, so the task ID doubles as both the Redis key and the MQTT topic suffix. A background retry loop notifies, waits, and re-checks task status — and a separate check on every real inbound message asks "does this reply resolve any open task, regardless of which channel it came in on" — which is what actually lets Iris notice you replied on Discord to an alert it sent on Telegram.
Challenges I ran into
- Caspian's
INITIATEcapability isn't available on Telegram/Discord/Slack — confirmed by testing against the live API, not assumed from docs. This ruled out the simplest version of the pitch and forced the identity/memory-first redesign that's now the actual product. - Proactive email delivery reports success but doesn't reliably land — verified across multiple fresh conversations and identities to rule out a bug on my side before concluding it's likely a platform-side gap. Documented as a known limitation rather than hidden.
- Cross-channel identity has no verification step yet — right now, telling Iris "my email is X" links it on say-so. Fine for a hackathon demo, not fine for anything real; it's the first thing on the roadmap. ## What I learned
The most useful thing I learned wasn't Caspian's API — it was to test assumptions against the real thing early. My first instinct was to design around what the docs implied Caspian could do; the actual product only became interesting once I'd hit the platform's real edges (capability limits, delivery reliability) and built around what was actually true, not what sounded true.
Log in or sign up for Devpost to join the conversation.