Proactive Triggers (bundled plugin, off by default; dry-run by default when on)
Rules live in config. Each rule has a schedule (every interval or a 5-field cron), an
optional condition, a cooldown, a message and a sessionKey. When a rule is due and its
condition holds, the gateway enqueues one system event for that session: the next agent turn
sees the message. With dryRun: true (the default) nothing is sent; the rule is evaluated and
proactive.dry_run is audited, so a new rule set can be watched for a day before it talks to
anyone.
Conditions (all must hold):
| key | meaning |
|---|---|
fileExists / fileMissing |
path (~ ok, relative = state root) |
fileOlderThan / fileNewerThan |
{ path, minutes } against the file’s mtime |
hoursBetween |
[from, to) local hours, wraps midnight |
weekdays |
1 = Monday … 7 = Sunday |
signalEquals |
{ name, path?, value } compared (JSON) against a plugin signal, e.g. the circadian phase |
Last-fired times persist in <state>/proactive/state.json, so a gateway restart or a plugin
reload never re-fires everything; a cron rule fires at most once per matching minute.
Config
Section titled “Config”{ plugins: { entries: { "proactive-triggers": { enabled: true, config: { dryRun: true, // set false to deliver tickMs: 30000, rules: [ { id: "inbox-nudge", every: "15m", cooldown: "1h", condition: { fileNewerThan: { path: "agents/main/inbox/latest.md", minutes: 15 }, hoursBetween: [8, 22] }, message: "New inbox item since your last turn; read agents/main/inbox/latest.md.", sessionKey: "agent:main:main", }, { id: "morning-brief", cron: "0 9 * * 1-5", message: "Morning: review the overnight audit summary and plan the day.", sessionKey: "agent:main:main", }, { id: "night-journal", cron: "30 2 * * *", condition: { signalEquals: { name: "circadian.phase", path: "phase", value: "deep-night" } }, message: "Quiet hours: write the night journal entry.", sessionKey: "agent:main:main", }, ], }, }, }, },}Invalid rules are skipped with a warning in the gateway log (duplicate id, bad duration, cron without 5 fields, missing message or session key).
Audit: proactive.dry_run, proactive.fired (source plugin:proactive-triggers, scope = the
session key). Signal: proactive.lastFired.