Repository navigation
Enable On Device Notifications
Note
Status: implemented — shipped by PLAN-proactive-delivery.md#task-3 (FRIDAY ladder feature 1, task 3 of 5); the runner-job manifest referenced in step 6 shipped in task 5 of the same plan.
Goal: Opt in to a once-daily native notification carrying the line the SessionStart brief shows, so the morning note's headline, or a night that stopped finishing, reaches you even on a day you never open a session.
Prereqs: macOS — the channel fires via osascript; a non-macOS host silently no-ops. A resolvable vault with a morning note already written, or at least one digest-ladder cycle already run (see Read the morning note and the nightly scorecard). To have the runner fire this daily, copy templates/jobs/observability-notify-daily.yaml into .harness/jobs/ (step 6 below) — until then, invoke it yourself.
scripts/health/session_notify.py is the opt-in, once-daily on-device notification channel from wiki/designs/agentm-autonomy.md's Delivery subsection. It relays the line the SessionStart hook shows — the morning note's headline, or the digest ladder's when no morning note exists — so what you see in the notification matches what you'd see at the top of your next session.
-
Opt in. Set the config key that gates the whole channel:
python3 scripts/agentm_config.py --notify-enabled trueThis writes
plugins.autonomy.notify_enabled(cmd_set_notify_enabled,scripts/agentm_config.py:213; the key itself declared atscripts/agentm_config.py:77). Confirm it took with--get plugins.autonomy.notify_enabled. -
Run the notifier. Until you register the runner job (step 6), invoke it directly:
python3 scripts/health/session_notify.py
main()(session_notify.py:169) callsrun()(session_notify.py:138), which checks the opt-in first (notify_enabled(),session_notify.py:146), resolves the vault viasession_brief.resolve_vault()(session_notify.py:149), and no-ops silently on any missing piece — disabled, no vault, or nothing to say (no morning note and no digest ever written). -
What fires.
notify_body()(session_notify.py:120-135) callssession_brief.build_brief()— the same reader the SessionStart line uses, which reads the morning note first and the digest ladder after it — and strips the leading"[agentm] "the SessionStart line carries, since a native notification banner already has its own title._fire_osascript()(session_notify.py:99-110) shells toosascript -e 'display notification "<body>" with title "AgentM"'. -
Once-a-day, not once-per-hours. A calendar-day state file at
~/.cache/agentm/telemetry/notify-state.json(default_state_path(),session_notify.py:70-71) recordslast_fired_date. A second call the same day is a no-op (_already_fired_today(),session_notify.py:80-85) no matter how many times you (or the runner job below) invoke the script — this is deliberately calendar-day anti-fatigue rather thansession_brief.py's hours-based cooldown, because a runner-scheduled job doesn't have "once per session boot" semantics. -
Turn it back off.
python3 scripts/agentm_config.py --notify-enabled falseThe channel graceful-skips the moment the key isn't
true(notify_enabled(),session_notify.py:53-67) — no notification fires, no state file is touched. -
Optional: let the runner fire it for you.
templates/jobs/observability-notify-daily.yamlis the job manifest for this channel —schedule: daily,command: python3 -m health.session_notify,dry_run: false(the opt-in config gate above is already the safety gate, so a second dry-run layer would be redundant)..harness/jobs/is gitignored, so registering it is a one-time local copy:cp templates/jobs/observability-notify-daily.yaml .harness/jobs/observability-notify-daily.yaml
The local runner (
scripts/agentm-runner.sh) then picks it up on its next daily tick. A fresh copy still fires nothing until--notify-enabled trueis set — the manifest schedules the check, not the fire.
-
test_disabled_by_default_never_firesandtest_enabled_with_osascript_fires(RunEndToEndTests,scripts/health/test_session_notify.py:157-175) prove the opt-in gate end to end. -
test_same_day_rerun_does_not_refireandtest_new_day_with_new_digest_refires(scripts/health/test_session_notify.py:192-217) prove the calendar-day anti-fatigue behavior. -
test_strips_agentm_prefix(scripts/health/test_session_notify.py:123-129) proves the notification body matches the SessionStart line minus its prefix.
-
Nothing fires and no error appears. By design —
run()swallows every exception and every graceful-skip case returnsFalsesilently (session_notify.py:145-166), so a missing vault, an unset opt-in, or a non-macOS host all look identical: nothing happens. Checkpython3 scripts/agentm_config.py --get plugins.autonomy.notify_enabledfirst. -
Non-macOS hosts.
_fire_osascript()(session_notify.py:99-110) resolves theosascriptbinary withshutil.which; its absence is a silent no-op, not an error.
- Autonomy — Delivery — the design this channel implements, and the amendment log entry with the full build detail.
-
Installer CLI — the
--notify-enabled/--email-to/--email-smtp-urlconfig-key reference row. - Enable the daily email — the sibling opt-in delivery channel, same plan; it sends the whole morning note.
-
Persist a morning report — the sibling
scripts/health/recipe for the overnight-run report the same observability rollup feeds.
🔧 How-to
- Install machine-wide (recommended)
- Your first install
- Your first Agent View dispatch
- Configure a new project
- Re-detect a configured project
- Update an installed harness
- Use auto-context in phases
- Audit the vault
- Find missing note links
- Use AgentMemory in any agent
- Drop a card in the inbox
- Tune auto-orchestration
- Run without a vault
- Choose a storage backend
- Back the vault with Google Drive
- Set up Obsidian on the vault
- Find your way around the vault
- Run the memory-root trims migration
- Run the root casing migration
- Run the projects migration
- Run the card backfill
- Run the maps and root notes migration
- Persist a morning report
- Enable on-device notifications
- Enable the daily email
- Ingest an article
- Capture from your phone
- Archive a finished project
- Tune the archive
- Read the morning note and the nightly scorecard
- Read the weekly field brief
- Review flagged memories
- Use the daily calendar