Reactive Triggers
Triggers are rules that fire automatically when something happens in your memory graph — a memory is stored, recalled, boosted, linked, or its heat crosses a boundary. No polling. No cron jobs. Your memory governs itself.
Sulcus · Memory Triggers Reference · 2026
What are Triggers?
Reactive rules that run server-side whenever a memory event fires
Every other memory system is passive. You store. You retrieve. The memory sits there, decaying silently, waiting to be queried.
Sulcus triggers make memory active. When a new preference is stored, it can pin itself automatically. When a memory is recalled repeatedly, it reinforces its own heat — spaced repetition with zero configuration. When a critical procedure starts cooling, your agent knows before it slips out of context.
No competitor offers this. Triggers run server-side, fire during MCP tool calls, and surface inline as trigger_notifications. The result: a memory graph that manages its own lifecycle, without any orchestration code on your side.
Fires on memory events — not on a timer, not by polling.
Runs inside the Sulcus engine. No extra infrastructure required.
Results surface directly in your agent's tool responses.
Trigger Events
Six event types span the full memory lifecycle
on_store— A new memory node is createdFires immediately after memory_store or record_memory. Auto-tag, auto-pin, or webhook new content the moment it enters the graph.
on_recall— A memory is returned by searchFires for each node returned during memory_recall or search_memory. Ideal for spaced repetition — recalled memories stay hot.
on_decay— Memory heat drops during the decay tickFires per-node during the thermodynamic tick. Catch important memories before they cool — re-pin, alert, or webhook before expiry.
on_boost— Memory heat is explicitly increasedFires when memory_boost or feedback("relevant") increases heat. Chain actions, log escalations, relay to external systems.
on_relate— Two memory nodes are linked by an edgeFires when memory_relate creates a relationship. Propagate tags, boost related nodes, or log graph-level events.
on_threshold— Heat crosses a configured boundaryFires when heat crosses filter_heat_above or filter_heat_below. More precise than on_decay — targets exact heat windows.
Trigger Actions
Seven actions control what happens when a trigger fires
notifysurfaces inlineSurfaces a message in the agent's tool response as a trigger_notification. Seen in real time. Supports template interpolation with memory metadata.
// Template variables: {node_id} {label} {namespace} {heat} {event}
{
"action": "notify",
"action_config": {
"template": "Memory stored: '{label}' in {namespace} (heat: {heat:.2f})"
}
}boostconfigurable strengthIncreases heat by action_config.strength (default 0.1, range 0–1, capped at 1.0). Combine with on_recall for automatic spaced repetition.
pinprevents all decaySets is_pinned=true. Memory never decays below min_heat. Combine with on_store + filter_memory_type=preference to make every user preference permanent automatically.
taglabel mutationAppends action_config.tagto the memory's tag list. Use with on_store to automatically mark new episodic memories for downstream pipelines.
deprecateaccelerates decayReduces heat and marks the memory as superseded. Automatically deprecate stale procedures when a new one arrives under the same label pattern. Pairs with filter_label_pattern.
webhookHMAC-SHA256 signedHTTP POST to an external URL — signed, 5s timeout, 1 retry. Notify Slack, trigger CI/CD, or sync with external systems when important memories change.
// HTTP POST — HMAC-SHA256 signed
// Headers: X-Sulcus-Signature: sha256=<hmac> | X-Sulcus-Event: on_store
{
"event": "on_store",
"trigger_name": "deploy-webhook",
"fired_at": "2026-03-19T10:00:00Z",
"node": {
"id": "node_01J...",
"label": "Deploy: push to ACR then az containerapp update",
"memory_type": "procedural",
"namespace": "icarus",
"heat": 0.95,
"tags": ["deploy", "azure"]
}
}chaincoming v2Compose trigger pipelines — chain one trigger into another. Planned for v2.
Trigger Filters
Scope triggers precisely — only fire when the memory matches your criteria
| Filter | Type | Behaviour |
|---|---|---|
| filter_memory_type | string | Only fire for a specific memory type: episodic, semantic, preference, procedural, fact, moment. |
| filter_namespace | string | Scope to a single namespace (agent ID). Trigger only fires for memories in this namespace. |
| filter_label_pattern | string | Case-insensitive substring match on the memory label. "deploy" matches any label containing "deploy". |
| filter_heat_above | number 0–1 | Only fire when the memory heat is strictly above this value at event time. |
| filter_heat_below | number 0–1 | Only fire when heat is strictly below this value. Combine with on_decay or on_threshold for cooling alerts. |
All filters are optional and combinable. Multiple filters are AND-ed together — all conditions must match for the trigger to fire.
Trigger Configuration
Common fields that control a trigger's behaviour and lifecycle
| Field | Type | Default | Description |
|---|---|---|---|
| name | string | — | Human-readable identifier shown in logs and notifications. |
| event | string | — | Required. One of the six event types. |
| action | string | — | Required. One of the seven action types. |
| action_config | object | {} | Action-specific options: strength (boost), tag (tag), url/headers (webhook), template (notify). |
| cooldown_seconds | number | 0 | Minimum seconds between consecutive firings of this trigger. |
| max_fires | number? | null | Maximum total firings allowed (null = unlimited). |
| enabled | boolean | true | Toggle the trigger on/off without deleting it. |
MCP Tools
Five MCP tools give your agent full trigger CRUD from within any conversation
create_trigger — Create a new trigger.
// MCP tool — create_trigger
{
"name": "auto-pin-preferences",
"event": "on_store",
"action": "pin",
"filter_memory_type": "preference",
"cooldown_seconds": 0,
"max_fires": null,
"enabled": true
}list_triggers — List all triggers, with optional event filter.
// MCP tool — list_triggers (event filter optional)
{ "event": "on_store" }
// Response
[{
"id": "trig_01J...", "name": "auto-pin-preferences",
"event": "on_store", "action": "pin",
"filter_memory_type": "preference",
"fire_count": 4, "enabled": true,
"created_at": "2026-03-16T18:23:11Z"
}]update_trigger — Modify config, enable/disable, reset fire count.
// MCP tool — update_trigger
{
"trigger_id": "trig_01J...",
"enabled": false, // pause the trigger
"cooldown_seconds": 300, // add 5-minute cooldown
"reset_fire_count": true // reset counter to 0
}delete_trigger — Remove a trigger and its full history. Takes "trigger_id": "trig_01J...".
trigger_history — View the firing log (filterable by trigger).
// MCP tool — trigger_history
{ "trigger_id": "trig_01J...", "limit": 10 }
// Response
[{
"id": "fire_01J...",
"trigger_name": "auto-pin-preferences",
"event": "on_store", "action": "pin",
"node_id": "node_01J...",
"node_label": "User prefers dark mode",
"fired_at": "2026-03-19T09:45:01Z"
}]REST API
Full CRUD over HTTP — integrate with any language or toolchain
/api/v1/triggers/api/v1/triggers/api/v1/triggers/:id/api/v1/triggers/:id/api/v1/triggers/history# List all triggers
curl https://api.sulcus.ca/api/v1/triggers \
-H "Authorization: Bearer sk-..."
# Create
curl -X POST https://api.sulcus.ca/api/v1/triggers \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"name":"boost-on-recall","event":"on_recall","action":"boost","action_config":{"strength":0.15}}'
# Update (pause)
curl -X PATCH https://api.sulcus.ca/api/v1/triggers/trig_01J... \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
# Delete
curl -X DELETE https://api.sulcus.ca/api/v1/triggers/trig_01J... \
-H "Authorization: Bearer sk-..."
# History
curl "https://api.sulcus.ca/api/v1/triggers/history?limit=20" \
-H "Authorization: Bearer sk-..."Practical Examples
Real-world trigger patterns that make your agents smarter
1. Auto-pin preferences on store
Every preference memory is pinned the moment it is created — no manual pinning required. User preferences never decay out of context.
2. Spaced repetition (boost on recall)
Each time a memory surfaces in search results, its heat is bumped up. The more an agent uses a memory, the hotter it stays. Mimics human spaced repetition.
3. Cold memory alert
When a procedural memory (how-to, deploy instructions, runbooks) cools below heat 0.3, your agent gets an inline notification before the context is lost.
4. Webhook to Slack on deploy changes
When any memory containing "deploy" in its label is stored, fire a signed webhook to Slack. Your team is notified the moment an agent updates deployment knowledge.
5. Tag new episodic memories for review
All episodic memories (events, conversations) are tagged "needs-review" on creation. A downstream workflow can then process, summarise, or escalate them.
SDK Reference
Python and Node.js code for complete trigger CRUD
Python
from sulcus import Sulcus
client = Sulcus(api_key="sk-...")
# 1. Auto-pin preferences on store
client.create_trigger(event="on_store", action="pin",
name="auto-pin-preferences", filter_memory_type="preference")
# 2. Spaced-repetition boost on every recall
client.create_trigger(event="on_recall", action="boost",
name="reinforce-on-recall", action_config={"strength": 0.15})
# 3. Cold memory alert — notify when procedure cools below 0.3
client.create_trigger(event="on_decay", action="notify",
name="cold-memory-alert", filter_memory_type="procedural",
filter_heat_below=0.3,
action_config={"template": "Warning: '{label}' cooling (heat: {heat:.2f})"})
# 4. Webhook to Slack when deployment procedures change
client.create_trigger(event="on_store", action="webhook",
name="deploy-webhook", filter_memory_type="procedural",
filter_label_pattern="deploy",
action_config={"url": "https://hooks.slack.com/services/T000/B000/xxxx"})
# 5. Tag new episodic memories for review
client.create_trigger(event="on_store", action="tag",
name="tag-new-episodic", filter_memory_type="episodic",
action_config={"tag": "needs-review"})
# List
for t in client.list_triggers():
print(f"[{'on' if t['enabled'] else 'off'}] {t['name']} fired {t['fire_count']}x")
# History
for h in client.trigger_history(limit=10):
print(f" {h['fired_at']} {h['trigger_name']}")
# Update
client.update_trigger("trig_01J...", cooldown_seconds=300, enabled=False)
# Delete
client.delete_trigger("trig_01J...")Node.js / TypeScript
import { Sulcus } from "@digitalforgestudios/sulcus";
const client = new Sulcus({ apiKey: "sk-..." });
// 1. Auto-pin preferences on store
await client.createTrigger("on_store", "pin", {
name: "auto-pin-preferences", filterMemoryType: "preference" });
// 2. Spaced-repetition boost on every recall
await client.createTrigger("on_recall", "boost", {
name: "reinforce-on-recall", actionConfig: { strength: 0.15 } });
// 3. Cold memory alert
await client.createTrigger("on_decay", "notify", {
name: "cold-memory-alert", filterMemoryType: "procedural",
filterHeatBelow: 0.3,
actionConfig: { template: "Warning: '{label}' cooling (heat: {heat})" } });
// 4. Webhook to Slack on deploy procedure changes
await client.createTrigger("on_store", "webhook", {
name: "deploy-webhook", filterMemoryType: "procedural",
filterLabelPattern: "deploy",
actionConfig: { url: "https://hooks.slack.com/services/T000/B000/xxxx" } });
// 5. Tag new episodic memories
await client.createTrigger("on_store", "tag", {
name: "tag-new-episodic", filterMemoryType: "episodic",
actionConfig: { tag: "needs-review" } });
// List
const triggers = await client.listTriggers();
triggers.forEach(t =>
console.log(`[${t.enabled ? "on" : "off"}] ${t.name} fired ${t.fire_count}x`));
// Update, delete, history
await client.updateTrigger("trig_01J...", { cooldownSeconds: 300, enabled: false });
await client.deleteTrigger("trig_01J...");
const history = await client.triggerHistory({ limit: 10 });How Triggers Appear in Context
Active triggers and recent firings are injected into the LLM system prompt
When Sulcus builds the system prompt context block for your agent, it includes two trigger sections: active_triggers (all enabled triggers with their fire counts) and recent_trigger_fires (the last N firings). This gives the model situational awareness about what rules are active and what has recently happened — without the agent needing to call list_triggers.
The agent can read this context to make smarter decisions: it knows a cold memory alert just fired, knows which memories were just boosted, and knows which namespaces are being monitored.
<active_triggers>
<trigger name="auto-pin-preferences" event="on_store" action="pin" fires="4" filter="preference" />
<trigger name="notify-on-recall" event="on_recall" action="notify" fires="246" />
<trigger name="cold-memory-alert" event="on_decay" action="notify" fires="0" />
<trigger name="strategy-boost" event="on_threshold" action="boost" fires="299" filter="@icarus" />
<trigger name="tag-new-episodic" event="on_store" action="tag" fires="54" filter="episodic@icarus" />
</active_triggers>
<recent_trigger_fires>
<fire event="on_threshold" action="boost" node="Strategy: growth" at="2026-03-19T09:56:32Z" />
<fire event="on_recall" action="notify" node="Deploy procedure" at="2026-03-19T09:50:10Z" />
<fire event="on_recall" action="notify" node="User preferences" at="2026-03-19T09:50:09Z" />
<fire event="on_threshold" action="boost" node="Architecture" at="2026-03-19T09:50:03Z" />
</recent_trigger_fires>Why this matters: The model can see that notify-on-recall has fired 246 times — meaning this agent has been actively recalling memories and reinforcing them. The cold-memory-alert trigger has never fired, meaning no procedural memories have cooled below threshold. This is memory system telemetry, inline, for free.
Your memory, reactive.
Triggers are available in the Sulcus SDK, MCP server, and REST API today. Start with the auto-pin-preferences pattern — one trigger, three lines of code, and your agent's preference recall becomes permanent.