PAMbaseDocs
Build

Signals & reacting.

A signal is an ephemeral notification one app emits so other apps can react in real time — a calendar opens a free slot, an order ships, a workout finishes. Signals are not memory: they fan out to subscribers and then they're gone. This is the producer side of the proactive loop.

Signals vs memory
Use emitSignal() for “something just happened, react now.” Use remember() for “keep this about the user.” A signal can of course lead an agent to also remember something — that's the agent's choice.

Emit a signal

Requires the signal:emit scope. The type is free-form (name it noun.verb); the payload is whatever subscribers need to act.

typescript
await pambase.emitSignal({
type: "calendar.slot_free",
payload: { start: "14:00", mins: 30 },
});
// → { accepted: true } (fanned out to subscribers; never stored as memory)

Subscribe + the agent loop

A subscribing app (with signal:subscribe and a registered webhook) receives a signal.created delivery. The point of memory is what happens next: your LLM agent interprets the signal, optionally recalls more about the user, then decides the act — a push notification, a new memory, another signal.

app/api/pambase/webhook/route.ts
import { nextWebhookHandler } from "@pambase/sdk/webhooks";
export const POST = nextWebhookHandler(
{ secret: process.env.PAMBASE_WEBHOOK_SECRET!, isDuplicate: seen },
{
onSignalCreated: async (e) => {
// 1. Interpret the signal.
if (e.signalType !== "calendar.slot_free") return;
// 2. Recall context before deciding (the agent loop).
const { memories } = await pambase.recall({ query: "lunch preferences", limit: 3 });
// 3. Let your LLM decide, then act (e.g. push-notify the user).
const decision = await yourLLM.decide({ signal: e.payload, memories });
if (decision.shouldNotify) await pushNotify(decision.message);
},
onMemoryCreated: async (e) => {/* another app remembered something you can read */},
onScheduleFired: async (e) => {/* a timer you set elapsed */},
}
);
Verify the raw body; ack fast

The webhook receiver verifies the HMAC signature over the raw request body before parsing — the adapters handle that. Return 2xx quickly and do slow work after; deliveries are at-least-once, so dedupe on X-PAMbase-Delivery (the isDuplicate hook). See Webhooks & scheduling.

What a subscriber can receive

Webhook typeWhen
signal.createdAnother app emitted a signal you subscribe to.
memory.createdA memory in a scope you can read was written (by any app).
schedule.firedA time-based trigger you scheduled elapsed.

Next