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.

text
 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 / Telegram

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