Guides
Source events
A source event is Mobius's record that something happened: an email arrived, a ticket was created, a table row changed.
Recording is the whole of what Mobius does with an event on its own. An event does not start work by itself. Something has to be waiting for it, and there are two things that can be:
- An agent turn that called the
mobius_event_waittool and parked until a matching event arrives. - A messaging binding, which turns an inbound provider message into a message for the agent that owns that channel.
Everything else that arrives is recorded and left there, available to read.
What a waiting agent sees is a tidy { event, meta } envelope, not whatever
the provider originally sent. event is the thing that happened. meta is the
routing detail around it.
Envelope
event:
# kind-specific public payload
meta:
id: sevt_01...
event_type: table.row.inserted
source_kind: table_row
source_id: tbl_01...
received_at: "2026-06-11T13:00:00Z"
table_id: tbl_01...
row_id: row_01...A wait evaluates its match, condition, and payload_mapping against
{ event, meta }.
Public families
| Family | Examples |
|---|---|
| Tables | table.row.inserted, table.row.updated, table.row.deleted |
email.received | |
| Agent memory | memory.entry.created, memory.entry.updated, memory.entry.deleted |
| Interactions | interaction.created, interaction.resolved |
| Sessions | session.message.created |
| Integrations | github.pull_request.opened, github.issues.opened, linear.issue.updated, jira.issue.created, gmail.message.received, slack.event |
The full public and internal lists live in the event catalog.
Every terminal interaction emits interaction.resolved, even when it also
wakes an agent tool or an HTTP subscriber. Check event.status before acting
on one: cancellation and expiry resolve an interaction too, and neither is
approval.
Table row events
For table.row.* events, source_id is the table ID, so a wait scoped with
source_id: tbl_01... can match any row in that table. Row columns live under
event.data:
event:
event: updated # inserted | updated | deleted
data:
priority: urgent # the row's columns
version: 3
updated_at: "2026-06-11T13:00:00Z"
meta:
table_name: tickets
table_id: tbl_01...
row_id: row_01...
# present when the write came from a running agent:
agent_id: agt_01...Reach columns with event.data.priority in conditions, and with dotted keys
in match patterns (match: { data.priority: urgent }).
Saving a row with values identical to what is stored is a no-op. It does not bump the row version or emit an event.
Wait for an event during a turn
An agent waits by calling mobius_event_wait. The turn suspends, and it
resumes when a matching event arrives. Waits survive a restart, so a turn can
sit parked for hours without holding anything open.
The tool takes an event_type and, optionally, a source_id, exact-match
match filters, an expr condition, a payload_mapping, and a timeout:
{
"event_type": "github.pull_request.opened",
"condition": "event.repository.full_name == \"acme/api\"",
"payload_mapping": { "pr_url": "${event.pull_request.html_url}" },
"timeout": "6h"
}Keep the filter narrow enough that the turn only wakes for events it can
actually act on. Two shapes are rejected outright, because neither can end
well: a condition that can never be true would park the turn until the 24-hour
backstop, and an event_type of * with no other filter would wake on every
event in the organization.
timeout is a duration string and is capped at 24 hours. When it passes with
no match, the tool returns an error and the agent decides what to do next.
Wildcards
Event names are dotted strings. Exact names and trailing subtree wildcards are valid:
github.pull_request.opened
github.pull_request.*
github.*Wildcards match descendants only. github.pull_request.* matches
github.pull_request.opened; it does not match github.pull_request.
When an event never arrives
Work outward from the provider. The most common mistake is editing the wait over and over when the event never reached Mobius in the first place, and no amount of editing the wait fixes that.
- Did Mobius receive it at all? Open Library > Integrations, pick the provider, and look at recent events. Nothing there means the problem is on the provider's side: the app isn't installed, a webhook isn't configured, or the account is missing a permission.
- Does the event name match? Exactly, or via a wildcard. A near-miss like
github.issue.openedwhen the real name isgithub.issues.openedmatches nothing. - Does the condition come out true? For this specific event's
{ event, meta }.
When a waiting turn doesn't resume
- Open the session and find the parked
mobius_event_waittool call. - Check what
event_typeandsource_idit is actually waiting for. - Check that a matching source event exists.
- Check whether the wait's
timeoutalready passed. A timed-out wait returns an error to the agent rather than resuming.
Next
- Look up names in the event catalog.
- See what a provider sends in integrations.
- Read how a turn suspends and resumes in agent sessions.