A set of features that let the agent act toward you — and, just as important, let it rest without rotting.
People go through quiet stretches — sometimes months — where they step back from talking to their agent. Without this, unattended autonomous cycles slowly hollow out, and coming back feels like facing an abandoned pet. Seasons replaces the kill-switch with rest:
- Auto-entry after N quiet days (default 7, configurable). On auto-entry the agent sends ONE gentle note (text configurable, or disable it) and goes still.
- Manual entry/exit from the Heartbeat tab. Exit is manual only — talking to the agent always works (the reactive agent never sleeps), but the proactive layer stays asleep until you flip the flag.
- Silenced during a season: all agent-initiated outbound (briefings, nudges, digests, voice notes).
- Not silenced: reminders you set yourself, and the watchdog (resting-by- choice and broken-by-accident must never look alike).
- The heartbeat drops to a slow keeper cadence (default weekly) with a keeper frame: tend the house, note what's worth sharing on return, wait well. Re-entry is warm and unaccounted — no tallies of the silence.
What a season means is yours to define. Edit season_meaning and
entry_note_text in data/seasons.json — a sentence in your own words (deep
work, travel, a practice, grief — whatever is true) that the agent carries in
context while the season is on, so it understands the quiet correctly.
notify_useris the one canonical outbound path (tool + internal API). Every send passes the Seasons gate and quiet hours, and is logged to theoutbound_logtable with its outcome (sent/suppressed_seasons/deferred_quiet/failed). Delivery is Telegram (TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID), with desktop toast fallback.voice_noterenders a short message in the agent's Reader voice and sends it as a Telegram voice message.- Morning briefing: create a cron job (Cron tab) that prompts the agent to
assemble weather, calendar, reminders, and anything from overnight cycles,
and send it via
notify_user. Seeexamples/CRON_JOBS_EXAMPLE.md. - Quiet hours and per-channel toggles live in
data/outbound.json.
Reminders that survive restarts (PostgreSQL reminders table, created
automatically):
schedule_reminder— natural-language capture: one-shot ("tomorrow 5pm"), recurring ("every weekday at 7"), and conditional ("remind me when it's raining").- Conditional delivery is code-performed: at fire time the agent evaluates the condition and answers with a strict verdict; the system — not the LLM — performs the actual send. The model can't claim "sending it now" without a send actually happening. Ambiguity defaults to pinging you.
snooze_reminder,cancel_reminder,list_remindersround it out.- A 30-second poller inside the API process fires due rows; user-commissioned reminders are exempt from Seasons (your calendar doesn't pause for your rest).
scripts/watchdog.pyis a dead-man's switch that runs as its own process (Task Scheduler): if the heartbeat scheduler stops stampingdata/heartbeat_last.txt, the watchdog notifies you. The agent can't be trusted to report its own death — something independent must. Start it withscripts/run_watchdog.cmd.self_vitals(tool +/api/vitals): the agent's own health check — DB reachability, Hindsight, heartbeat freshness, reminder queue, failure counters (failures.pytracks silent-failure bumps so problems surface instead of vanishing into logs).
Set CALENDAR_ICS_URL (Google Calendar → Settings → your calendar → "Secret
address in iCal format" — read-only, no OAuth). The calendar_week tool feeds
morning briefings, weekly planning crons, and reminder scheduling around your
real commitments.
A deliberately unadorned tab: you write a dated entry (optionally naming what
you read); after you save, the agent writes its own note beneath yours — a
real turn, its genuine voice, never commentary-bot. Both retain to long-term
memory tagged reflections.
- No streaks, no stats, no gamification. Presence, not pressure.
- Rest days: mark today (or a weekly pattern) and the optional evening nudge stays quiet, no questions asked.
- Optional evening nudge: a cron job that calls
reflections_todayand sends one gentle line — skips rest days, respects Seasons. - If your practice centers on a text, you can import a public-domain edition
via the Books tab and set
REFLECTIONS_BOOK_IDto show your reading position in the tab header. (An idea, not a requirement.)
A "watch feed" digest (scheduled read-only monitoring of an external
database/community with criteria-based notifications) exists in the private
lineage but reads infrastructure specific to its author. The generic scaffold
wasn't worth shipping half-formed; if you want one, outbound.notify_user +
a cron job + a read-only DB connection is the whole recipe.