Events
Events let apps react to external triggers. When something happens outside your system - an email arrives, a webhook fires, a calendar event starts - events let you handle it.
How Events Work
Events follow a pub/sub pattern:
- Source app defines events it can emit
- Subscriber app subscribes to those events
- When the event occurs, the subscriber's handler runs
This creates loose coupling between apps. The email app doesn't need to know who cares about new emails. It just emits events.
Defining Events
Events are defined in events.json:
{
"new_email": {
"description": "Fires when a new email arrives",
"capabilities": ["storage", "event"],
"tokens": {
"@my-org/auth": {
"account": ["accountId", "email"]
}
},
"payload": {
"type": "object",
"properties": {
"from": { "type": "string" },
"subject": { "type": "string" },
"snippet": { "type": "string" },
"messageId": { "type": "string" }
},
"required": ["from", "subject", "messageId"]
}
}
}
Event Fields
| Field | Required | What It Does |
|---|---|---|
description |
Yes | Explains when this event fires |
capabilities |
Yes | What event handlers can access |
tokens |
Yes | Token fields used for subscription matching |
payload |
Yes | Schema for the event data |
Token-Based Matching
The tokens field determines who receives events. It specifies which token fields create the subscription key:
"tokens": {
"@my-org/auth": {
"account": ["accountId", "email"]
}
}
This means:
- Subscribers need an
accounttoken from@my-org/auth - The
accountIdandemailfields form the subscription key - When an event fires for
[email protected], only subscribers with that email receive it
Event Handlers
When you define events, you need three handler files:
src/events/new_email/
├── start.ts # Runs when first subscriber joins
├── handler.ts # Processes incoming triggers
└── stop.ts # Runs when last subscriber leaves
start.ts
Called when the first subscriber subscribes. Use this to set up webhooks or polling:
export default async function start(
capabilities: Capabilities
): Promise<void> {
// Register webhook with external service
await registerGmailWebhook({
url: capabilities.webhookUrl,
topic: 'new_email'
});
}
handler.ts
Called when an external trigger arrives (like a webhook). Process the data and emit events:
export default async function handler(
input: WebhookPayload,
capabilities: Capabilities
): Promise<void> {
// Parse the webhook data
const email = parseGmailNotification(input);
// Send event to matching subscribers
await capabilities.event.send('new_email', {
toSubscribers: {
email: email.recipient
},
payload: {
from: email.from,
subject: email.subject,
snippet: email.snippet,
messageId: email.id
}
});
}
stop.ts
Called when the last subscriber unsubscribes. Clean up resources:
export default async function stop(
capabilities: Capabilities
): Promise<void> {
// Remove webhook registration
await unregisterGmailWebhook();
}
Subscribing to Events
Other apps subscribe to events using the event capability:
export default async function subscribe_to_emails(
input: Input,
capabilities: Capabilities
): Promise<Output> {
await capabilities.event.subscribe(
'@my-org/email', // Source app
'new_email', // Event name
'handle_new_email' // Handler tool in your app
);
return { subscribed: true };
}
When a new_email event fires, your handle_new_email tool runs with the event payload.
Handling Received Events
Create a tool to handle events you've subscribed to:
// src/tools/handle_new_email.ts
export default async function handle_new_email(
input: NewEmailPayload,
capabilities: Capabilities
): Promise<Output> {
// Process the email event
await capabilities.storage
.use('@my-org/inbox')
.put(`/notifications/${input.messageId}.json`, {
from: input.from,
subject: input.subject,
received: Date.now()
});
return { processed: true };
}
Unsubscribing
Stop receiving events:
await capabilities.event.unsubscribe(
'@my-org/email',
'new_email'
);
Event Flow
Here's the complete flow when an email arrives:
- Gmail sends webhook to your email app's handler
- Handler parses the notification
- Handler calls
event.send()with subscriber matching info - Event service finds subscribers with matching tokens
- Each subscriber's handler tool runs with the payload
- Subscribers process the event independently
[IMAGE: Flow diagram showing External Trigger -> Handler -> Event Service -> Subscriber Tools]
Use Cases
Events are useful for:
- Email notifications - React to incoming emails
- Calendar reminders - Trigger actions before meetings
- Webhook integrations - Connect to external services
- Real-time updates - Push changes to subscribers
- Background processing - Handle long-running tasks
Lifecycle Management
The start and stop handlers manage resources efficiently:
- First subscriber triggers
start(sets up webhook once) - Additional subscribers share the same webhook
- Last unsubscribe triggers
stop(cleans up webhook)
This means you don't have duplicate webhooks for multiple subscribers.