Your Mastra agents can now receive Ring doorbell events using Ring signals.
Each Ring event arrives in the agent's thread as a notification signal with a priority you can configure. The agent can then fetch a snapshot or video clip from the Ring API and decide what to do when there's someone at your door.
Ring signals turn a doorbell into an event source agents can act on. A home security agent could watch for human motion, view the snapshot, and flag visits that might need urgent attention. A delivery assistant could use package_delivery motion to let you know a parcel has arrived, or a driveway agent could log vehicle motion to track which cars pull up.
Agents are usually configured to respond to software events, like messages from Slack, Discord, iMessage, and other supported channel providers. Ring signals extend that functionality, making it possible to interact with the real world. With memory enabled, you can teach your agent about what it's seen, telling it which people, vehicles, and activity to recognize, so it remembers them for future events.
By default, the agent receives a snapshot image of each event. Set visibleToModel: true on tools.clip and use a model capable of receiving video input, and the agent can watch the videos too.
Get started
Ring signals need a Ring developer app linked to your Ring account. Follow the setup in the Ring integration guide, then install the following dependencies:
npm install @mastra/ring-signals @mastra/libsql @mastra/memoryAdd RingSignals to your agent's signals:
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { RingSignals } from "@mastra/ring-signals";
export const homeSecurityAgent = new Agent({
id: "home-security-agent",
name: "Home Security Agent",
instructions: "Watch the front door and say briefly whether each event needs attention.",
model: "google/gemini-3.8-flash",
memory: new Memory({
options: {
observationalMemory: true
}
}),
signals: [
new RingSignals({
events: {
button_press: { priority: "high", summary: "Doorbell was pressed." },
motion_detected: {
priority: "medium",
summary: "Motion was detected at the front door.",
attributes: (event) => ({
...event.data.attributes,
location: "front door"
})
},
device_offline: {
priority: "low",
summary: "Device went offline.",
coalesce: true
}
},
tools: {
clip: { visibleToModel: true, durationMs: 15_000 }
}
})
]
});observationalMemory: true: Turns on observational memory.events: Sets the priority and summary for each Ring event.attributes: Adds attributes the agent sees on the notification.coalesce: true: Merges repeats of an event into one notification.visibleToModel: true: Passes the clip to the model. (Requires a model that accepts video input).durationMs: Sets the clip length in milliseconds.
Register the agent and a storage adapter on your Mastra instance:
import { Mastra } from "@mastra/core";
import { LibSQLStore } from "@mastra/libsql";
import { homeSecurityAgent } from "./agents/home-security-agent";
export const mastra = new Mastra({
agents: { homeSecurityAgent },
storage: new LibSQLStore({
id: "mastra-storage",
url: "file:./mastra.db"
})
});Multi-player alerts
By default, RingSignals sends events to its own thread, but you can also configure RingSignals to subscribe to an existing channel thread using the target property.
Channels
This example uses iMessage. The channel and RingSignals share the same resourceId and threadId, so Ring events arrive in the iMessage conversation.
Install the iMessage adapter:
npm install @photon-ai/chat-adapter-imessagePoint the iMessage channel and RingSignals at the same thread:
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { RingSignals } from "@mastra/ring-signals";
import { createiMessageAdapter } from "@photon-ai/chat-adapter-imessage";
const resourceId = "home-security-agent";
const threadId = "ring-alerts";
export const homeSecurityAgent = new Agent({
// ...
id: resourceId,
channels: {
resolveResourceId: () => resourceId,
resolveThreadId: () => threadId,
adapters: {
imessage: { adapter: createiMessageAdapter() }
}
},
signals: [
new RingSignals({
target: { resourceId, threadId }
})
]
});Mastra client SDK
A web app can also follow the same thread using subscribeToThread() from the Mastra client SDK:
npm install @mastra/client-jsSubscribe to the thread with the same resourceId and threadId used by the channel and RingSignals:
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient({ baseUrl: "http://localhost:4111" });
const subscription = await client.getAgent("home-security-agent").subscribeToThread({
resourceId: "home-security-agent",
threadId: "ring-alerts"
});
await subscription.processDataStream({
onChunk: (chunk) => {
console.log(chunk.type, chunk);
}
});For more information and full configuration options, see:
- Ring integration guide
- RingSignals reference
- Signals
- iMessage integration guide
- Notification signals
- Channels
- Observational memory
- Mastra client
- Client SDK agents reference
Signals workshop
For a deeper look at signals, watch the Wake, Notify, and Steer Long-Running Agents with Signals workshop:
