Overview
The parts of Latch, what happens when a message arrives, and why each part exists.
Latch is a handful of parts that each do one job. Here's what happens when a user sends a message, and which part does what.
Browser / Slack / cron
│ message
▼
Your route ──── your login decides who is asking ──► Principal
│
▼
Runtime.handleChat()
1. loads the conversation ...................... Storage
2. builds what tools receive, for this person .. Context
3. runs the agent: model, tools, approvals ..... Agent (+ Tools & connections)
4. saves every step, holds a lease on the run .. Storage
│
▼
Streamed answer (AI SDK format) ──► useChat / Slack / TelegramYour route stays yours: Latch never handles login. You turn the request into a principal, a small object saying who is asking.
The runtime is the one object your code calls. It ties everything else together and guarantees the hard parts: one answer at a time per chat, crash recovery, approvals, limits.
Storage is where conversations, runs, usage and schedules live: your own database, through an adapter.
The agent is the model, its instructions and what it may do. Context is what its tools get: this customer's data, nothing else. Params say what a chat is about, such as a ticket, given once when it starts. Tools and connections are what it can act on: your functions, MCP servers, other services.
Around those sit optional parts: the server if you don't want to write routes, channels for Slack, Telegram and WhatsApp, and extensions to hook into a run.