Proactive messages — where they come from
When Neo sends the user something without being asked (a heads-up, a briefing, a noticing), it came from one of three daemon sources. If the user asks "how often do you send these?" or "where did this come from?", use this map — do not guess from the scheduler file alone (the briefing is NOT in it).
One corpus. This is both a user-facing overview and one of Neo's runtime self-docs: it is copied verbatim to
~/.neo/docs/self/proactive-messages.mdat install time, so it is the file Neo reads to answer cadence/origin questions about itself. It is written in the second person ("you") because Neo reads it about itself.
The three sources
| Source | What it is | Where it's configured | Provenance label |
|---|---|---|---|
| Reflection | A daily cross-session "noticing" pass that surfaces things worth telling the user. | Cron row in ~/.neo/scheduler/scheduled_tasks.json (tag reflect). | reflection-job |
| Dream | Periodic memory consolidation; may surface a note. | Cron row in the scheduler (tag dream). | heartbeat-job / reflection-job |
| Workflows (e.g. AI briefing) | A multi-step Tier-2 workflow the daemon runs unattended, ending in a push. | ~/.neo/workflows/<id>/definition.yaml — NOT in the scheduler file. | the workflow id, e.g. ai-briefing |
How delivery works
All three enqueue a notice into the owner's notification outbox (~/.neo/daemon/notifications/<sessionId>/) via the notify-owner primitive. The channel bridge (running inside neo-tg / neo-wa) drains that outbox and forwards the notice to the bound chat. Each notice record carries a source: field naming the job/workflow that produced it.
Tracing a specific message
- Check the
sourcelabel on the notice if you can see it — it names the origin directly (e.g.source: ai-briefing). - Check the scheduler:
~/.neo/scheduler/scheduled_tasks.json. Reflection and dream appear here as cron rows with a schedule you can read off directly (e.g.0 3 * * *= daily 03:00). - If it's not in the scheduler, it's a workflow. List
~/.neo/workflows/*/definition.yamland read the matching one. Itstriggers:block tells you how it fires —manualmeans it only runs when explicitly invoked (or dispatched by the daemon), NOT on a fixed clock, so don't claim a cadence the file doesn't state.
Answering "how often?"
Read the actual schedule before answering. If the source is a cron job, quote the cron expression. If it's a workflow with triggers: [manual], say plainly that it has no fixed schedule and runs when invoked/dispatched — don't invent a cadence.