Agent signals
Agent Signals are WednesdayAI’s lean plugin surface for non-user stimuli. They let a plugin publish structured meta-input — watcher output, commitment reminders, inbox summaries, context hints, background findings — without pretending the input came from a human conversation. Keep domain behaviour in your plugin. Core only owns flow control, dedupe, admission, and heartbeat dispatch.Modes
The current implementation supports two modes:context— stores the signal for plugin subscribers and future context collection. It does not wake a model turn.heartbeat— stores the signal, queues a session-scoped system-event summary, and requests a targeted heartbeat wake.
background, notify, and steer modes are reserved for future plumbing and currently return unsupported-mode.
Publishing a signal
Plugins access the API throughapi.runtime.signals. publish() is synchronous and never calls the model directly:
publish() returns either { accepted: true, signalId } or { accepted: false, reason }, where reason is one of duplicate, expired, queue-full, invalid, or unsupported-mode.
Signal fields
| Field | Type | Notes |
|---|---|---|
type | string | Required. Signal type, e.g. commitment.due. |
source | string | Required. Your plugin id. |
payload | unknown | Required. Structured data (kept out of transcripts by default). |
mode | "context" | "heartbeat" | Dispatch mode. |
summary | string | Concise prompt-visible summary (max ~500 chars). |
sessionKey / agentId | string | Target session/agent. |
priority | "low" | "normal" | "high" | "urgent" | Eviction ranking. |
dedupeKey | string | Suppresses duplicates against the same target. |
ttlMs | number | Expiry for stale alerts. |
requiresIdle | boolean | Defer dispatch while the agent is busy. |
Available helpers
Heartbeat dispatch
Heartbeat-mode signals bridge into the existing heartbeat system:- The signal is accepted into a bounded in-memory store.
- Core enqueues a system event on the target
sessionKey. - Core requests
requestHeartbeatNow({ reason: "signal:<type>", sessionKey }). - The heartbeat runner decides whether to run, skip, or retry based on active hours, heartbeat config, and lane/session activity.
- When the heartbeat runs, the signal summary is framed as signal-event context so isolated heartbeat sessions still see the base-session content.
skipWhenBusy.
Prompt visibility
Signals are meta-input, not user messages. Core exposes only the summary to the prompt-visible system-event queue:Availability
UsegetAvailability() to decide whether to publish now, defer, or drop:
requiresIdle: true is held while availability reports busy; re-attempt with requestWake() later.
Dedupe and bounds
The in-memory store applies conservative limits:- 100 signals globally; 20 per target session, agent, or source.
- Duplicate suppression by
dedupeKey, scoped to the target session/agent/source (the samededupeKeyagainst two different targets does not collide). WhendedupeKeyis omitted, suppression is bysource:type:agentId:sessionKey. - When a bounded target or the global store is full, the lowest-priority oldest signal is evicted; the incoming signal is rejected with
queue-fullif every eviction candidate has strictly higher priority.
Recommended pattern
Use Agent Signals as plumbing, not product policy:- Put domain logic in the plugin; publish concise summaries.
- Use
contextmode for passive context;heartbeatmode when the agent should consider acting soon. - Add
dedupeKeyfor recurring or retried stimuli, andttlMsfor stale alerts. - Avoid including secrets or large payloads.