Skip to main content

Autonomous Jobs on a Timer

The heartbeat is how Wolffish does things on its own — a morning briefing at 8, an inbox sweep every 15 minutes, a one-off reminder in 2 days. Jobs live in brain/brainstem/heartbeat.md, parsed by the brainstem module and run through the full agent pipeline when they fire. You rarely edit this file by hand. Just ask Wolffish — “every morning, summarize my unread emails” or “in 2 days remind me to renew my domain” — and it creates, edits, and removes jobs for you through its automations capability (automation_list, automation_create, automation_edit, automation_delete, automation_check, automation_run). Hand-editing still works, and the format is below.

How It Works

Each ## heading in heartbeat.md defines a job. The heading is the schedule (e.g. ## Daily (08:00)) — there’s no separate job name. The body below it is the instruction, sent to the agent as a user message when the schedule fires.

Schedule Formats

All times use your system’s local timezone, 24-hour format. There’s no UTC conversion — Daily (09:00) means 9 AM wherever you are.

One-time (runs once, then deletes itself)

After a one-time job runs, it removes its own entry from the file.
In (15m) / In (2h) / In (2d) is not a heading format — the brainstem never parses In (...) from heartbeat.md, so writing it as a ## heading does nothing. It’s shorthand you use when asking Wolffish (“in 2 days, remind me to renew my domain”): the automations capability resolves the relative delay to an absolute Once (...) at creation — a relative countdown couldn’t survive a restart — so what actually lands in the file is always a Once (...). To hand-write a one-time job, use Once (...).

Recurring (fires until you remove it)

Out-of-range schedules are rejected up front — Every (0m), Daily (99:99), or a Once (...) in the past won’t be silently accepted and then never fire. If you hand-edit a malformed heading, it shows up flagged when Wolffish lists your automations.

Job Execution

Heartbeat jobs run through the full agent pipeline — same brain, same capabilities, same memory. What differs from a normal conversation:
  • Auto-approval: Tool calls bypass amygdala confirmation (no approval dialogs).
  • Sealed conversation: Each run creates its own conversation, visible in history.
  • No streaming: Responses are generated in the background without UI interruption.
Because heartbeat jobs auto-approve every tool call, be careful what you schedule. A job that says “delete old files” will execute without asking. Write defensive instructions — “list files older than 30 days and tell me what you’d delete” beats “delete files older than 30 days.” See What to Schedule for the full safety decision layer.

Job setting markers

A job’s body may start with setting-marker lines — they’re settings, not instruction text, and are stripped before the instruction reaches the agent:
You rarely write these by hand: the Automations page sets them from its editor, and Wolffish sets them itself when you ask it to schedule something (automation_create / automation_edit take optional mode and icon; the automation_* tools preserve marker lines automatically when editing).

Up to three at once, queued — never dropped

Jobs run up to three at a time, side by side. If a job fires while all three slots are busy, it queues and runs as soon as a slot frees rather than being skipped. The queue is coalesced per job — a job that fires while it’s already running or waiting folds into the pending run instead of stacking copies — so a slow job can’t pile up a backlog of its own ticks. You don’t need to spread jobs out to avoid collisions.

Missed runs catch up

If Wolffish was closed when a job was due, it runs once on the next launch — collapsed: a recurring job that missed several fires during the downtime runs a single catch-up, not one per missed tick. Only misses within the last 24 hours are replayed; older ones are dropped. A one-time job past its time runs if it’s within that window, then deletes itself; if it’s older, it’s quietly retired without running.

The Automations Page

The in-app home for the heartbeat is the Automations page, rebuilt in v1.0.224 around cards: each job is a card wearing an emoji of its own — 📧 for the inbox sweep, 📰 for the news digest — with its schedule in plain English, its instruction, and its last-run status in view. Editing opens a proper dialog:
  • Schedule chips for the common shapes — daily, weekday, weekly, monthly, interval, hourly, startup, one-time, and full cron — so you pick a form instead of remembering syntax.
  • A real time input rather than a text field to get HH:MM right.
  • A live next-run preview that shows exactly when the job will fire, computed from the schedule you’re building, before you save.
  • Autosave with the same discipline as the procedures editor — no Save button, just Done.
The raw markdown view of heartbeat.md stays one click away for hand-editing, and everything below about the file format remains true — the page and the file are two views of the same jobs. The card’s emoji is stamped on every conversation the job’s runs create, so automation runs are recognizable at a glance in the conversations rail and History.

Watching runs live

A firing job never takes over the app. It surfaces as a floating live card pinned over the top of whatever screen you’re on — pulsing icon, the job’s label and its Single/Workflow mode, and a live feed of what it’s doing right now — while the rest of Wolffish stays fully usable. When runs overlap, up to three cards sit side by side, and a row beneath them counts and names anything queued behind a full pool. Click a card to expand the full activity panel — started-at time, elapsed timer, the job’s instruction, and a step-by-step log; press Escape or click outside to fold it back to the card. The run keeps going either way, and reopening the panel mid-run loses none of the log. On the page itself, a job that’s currently running or queued says so on its card, and its Run now button rests until the run ends — pressing it again would only fold into the pending run anyway. A run that fails raises a toast naming what broke. The phone sees the same thing: a run in flight arrives as a card in a stack over whatever screen you’re on, with its prompt a tap away. It shows up the moment the phone connects — including for a run that started while the phone was asleep — and disappears when the connection does.

A run you can open and watch

Before v1.0.236 an autonomous run happened somewhere you couldn’t reach. Its conversation appeared in the list only once the run was over, and if the app quit halfway everything the run had written was lost. Every autonomous run — automations and procedures alike — now creates its conversation before it starts:
  • It takes its place in the conversations rail immediately, with the same processing pulse a Telegram turn gets.
  • You can open it and watch the reply arrive live, exactly like a chat you typed.
  • The Stop button works on it — the same button, the same gesture, for a run nobody typed.
  • Progress is written to disk while the run works, so quitting or crashing halfway leaves a real transcript rather than a bare prompt.
  • Reopening the app mid-run finds the automation still going instead of sitting idle.

Edit stamps

Each card shows when its job was last edited — and the stamp comes from the engine watching heartbeat.md itself, not from the page. Any writer counts: the card editor, the raw markdown view, Wolffish’s own automation_* tools, an external editor, even an edit made while the app was closed. Toggling a job on or off deliberately doesn’t restamp it — only a real change to the schedule, settings, or instruction does. The page also refreshes itself live when the file changes underneath it: ask Wolffish mid-chat to add an automation and watch the card appear.

Managing Jobs

Just talk to it:
  • “What automations do I have?” → lists them with their schedule and last-run status
  • “Every weekday at 7:45, give me a morning briefing” → creates a recurring job
  • “In 2 days, remind me to renew my domain” → creates a one-time job that self-deletes
  • “Change the morning briefing to 8am” / “Delete the PR watcher” → edits or removes
  • “Run my email check now” → fires a job immediately to test it
Changes apply live — the brainstem reloads the schedule as soon as the file changes, no restart needed.

By hand

Edit heartbeat.md directly. To disable a job without deleting it, comment it out with HTML comments:
The brainstem watches heartbeat.md and reloads on save, so hand edits take effect without restarting. The commented examples shipped in the file are a menu — uncomment one to activate it.

Practical Examples

Morning Briefing

Email Triage

PR Monitoring

One-time Reminder

This fires once at 11:30 PM on Dec 31, then removes itself from the file.

Memory Compaction

Memory compaction (hippocampus consolidation) is a separate scheduled process configured in Settings > Knowledge > Compaction, not in heartbeat.md. The brainstem runs it on its own daily/weekly schedule, and it won’t appear when Wolffish lists your automations.
Compaction consolidates daily episodes into weekly summaries and promotes important information to knowledge files. It runs independently of heartbeat jobs.

Full Example File

See Also