Schedules & refresh
How cron schedules work in Pulsaria: presets, accepted syntax, the 60-second tick, catch-up after the app was closed, manual refresh and the daily reminder.
Connector, HTTP and Bash KPIs can carry a cron schedule. While Pulsaria is open on your Mac, a scheduler wakes up once a minute, works out which of those KPIs are due, and fetches them. This page covers the schedule field, the cron syntax it accepts, what happens after the Mac was asleep or the app was closed, and the two ways to fetch by hand.
How the scheduler works
The scheduler starts with the app window. The first check runs immediately when the app opens, then every 60 seconds for as long as Pulsaria stays open. Each check does three things in this order: fetch the auto-KPIs that are due, send the daily reminder if it is time, run the daily auto-export if it is enabled.
Only KPIs that have a non-manual source and a non-empty cron field are considered. Manual KPIs are never touched, and an automatic KPI with an empty schedule is never fetched on its own — you can still run it by hand.
Due KPIs are fetched one after another, never in parallel. Every fetch:
- writes the value as today’s entry, keyed to your local calendar date,
- writes one record to the Fetch log, whether it succeeded, failed or was skipped,
- raises a status alert if the KPI moved to at risk or off track.
Open screens update while the run is in progress — the Dashboard and the Fetch Log refresh themselves, no reload needed. Every KPI that fails produces one error toast titled Auto-KPI failed with <KPI name>: <error> underneath and a View details action that opens the Fetch Log.
There is no background agent, no menu-bar helper and no login item that fetches on its own. The scheduler lives inside the app window: quit Pulsaria and nothing is fetched until you open it again. If you want it running most of the day, turn on Launch at Login in App Settings.
Automatic fetching is macOS only. On any other platform the fetch step returns immediately — that includes Connector and HTTP KPIs, not only Bash.
The schedule field
The field sits at the bottom of the source section in the KPI dialog, labelled Cron schedule (optional). It looks the same for all three automatic sources.
- Open a KPI and press Edit, or create a new one and pick Connector, HTTP or Bash.
- Fill in the source configuration.
- Pick a preset from the dropdown, or choose Custom… and type an expression into the text box below it.
- Save.
The text box is locked unless the dropdown says Custom…, so a preset cannot be edited by accident. Under the box, Pulsaria shows Next run: with the next firing time formatted in your app language, for example Next run: Mon, 27 Jul 2026, 09:00. If the expression cannot be parsed, that line reads Invalid cron expression in red and the KPI cannot be saved until you fix or clear it.
Presets
| Dropdown entry | Expression | Runs |
|---|---|---|
| Every hour | 0 * * * * | every hour, on the hour |
| Every 6 hours | 0 */6 * * * | 00:00, 06:00, 12:00, 18:00 |
| Daily at 08:00 | 0 8 * * * | every day at 08:00 |
| Daily at 09:00 | 0 9 * * * | every day at 09:00 |
| Weekdays at 08:00 | 0 8 * * 1-5 | Monday to Friday at 08:00 |
| Custom… | whatever you type | unlocks the text box |
Metrics from the Connector Library arrive with a schedule already filled in: 0 9 * * * for almost all of them, and 0 9 2 * * for the Search Console metric Previous month clicks, which waits until the 2nd of the month so the previous month is complete. You can change it like any other.
Cron syntax
Pulsaria uses standard five-field cron, evaluated in your Mac’s local time zone. There is no time-zone setting: if you travel or the clock changes for daylight saving, the schedule follows the machine.
| Position | Field | Values |
|---|---|---|
| 1 | minute | 0–59 |
| 2 | hour | 0–23 |
| 3 | day of month | 1–31 |
| 4 | month | 1–12 or JAN–DEC |
| 5 | day of week | 0–7 (0 and 7 are Sunday) or SUN–SAT |
Operators inside a field: * for every value, 5-9 for a range, 1,15 for a list, */15 for a step, and combinations such as 1-5,0.
Beyond the classic five fields these also parse: the macros @hourly, @daily, @weekly, @monthly, @yearly; L in the day-of-month field for the last day of the month; 5#2 in the day-of-week field for the second Friday; and a six-field form whose first field is seconds. A seconds field will not buy you anything — the scheduler only wakes once a minute, so one minute is the finest resolution you can get, and anything more frequent simply fires on every check.
Common expressions
| Expression | Meaning |
|---|---|
0 9 * * * | every day at 09:00 |
0 8 * * 1-5 | Monday to Friday at 08:00 |
0 * * * * | every hour, on the hour |
*/15 * * * * | every 15 minutes |
0 */6 * * * | every six hours, starting at midnight |
0 9,17 * * * | twice a day, at 09:00 and 17:00 |
30 7 * * 1 | Mondays at 07:30 |
0 9 1 * * | the 1st of each month at 09:00 |
0 9 2 * * | the 2nd of each month at 09:00 |
0 9 1,15 * * | the 1st and the 15th at 09:00 |
0 0 L * * | the last day of the month at midnight |
0 0 1 1 * | 1 January at midnight |
Catch-up after a break
The scheduler does not wait for the clock to match the pattern exactly. For each automatic KPI it takes an anchor — the timestamp of the newest Fetch Log record for that KPI, or, if there is none, the KPI’s creation time — and asks when the schedule would next fire after that anchor. If that moment has already passed, the KPI is fetched now.
The practical effect: a KPI set to 0 9 * * * that was missed because your Mac was asleep or Pulsaria was closed at 09:00 is fetched on the first check after you open the app, not skipped until tomorrow. Since the first check runs immediately on launch, this usually happens within a second of the window appearing.
Two things to know about how far catch-up goes:
- Missed runs are collapsed, not replayed. If the app was closed for three days, a daily KPI runs once on the next launch, not three times. The value is always stored under today’s date; Pulsaria does not backfill the days you were away.
- A manual run counts as a run. Any fetch writes a Fetch Log record, which moves the anchor. Running a
0 9 * * *KPI with Run now at 09:05 means the 09:00 slot is done and the KPI will not fire again until tomorrow.
A failed attempt also counts as an attempt: the anchor moves and the KPI waits for its next slot. There is no retry, no backoff and no auto-disable for a KPI that keeps failing — a broken source will keep failing at its usual time until you fix it, with one Fetch Log record per attempt.
The Fetch Log holds the newest 500 records. If a rarely-fetched KPI’s records get pushed out of the log, its anchor falls back to the creation date and it is fetched once on the next check.
The daily reminder has no catch-up. It only fires if the app is running at that exact minute.
What stops automatic fetching
| Situation | What happens |
|---|---|
| Pulsaria is not running | nothing is fetched; the schedule resumes with catch-up on the next launch |
| Not on macOS | the fetch step returns immediately for every source, and the Refresh and Run now buttons are not rendered |
| Trial expired or licence revoked | auto-fetch is paused entirely until you activate a licence — see Trial & licence |
| Cron field left empty | the KPI is never picked up automatically; Refresh and Run now still work |
| Bash or HTTP KPI never approved | the attempt is logged as skipped, with the message “Command not approved — please confirm in KPI settings” |
| Command or HTTP config changed after approval | the attempt fails with “Command changed — please re-approve” |
Connector KPIs have no approval step at all, so they are never skipped for that reason. Approval is explained under Shell commands and Custom HTTP sources.
Fetching by hand
Refresh, for everything at once
The Refresh button sits in the top right of the Dashboard header. It fetches every automatic KPI, ignoring cron schedules — including KPIs whose schedule field is empty. They run one after another, and the button shows a spinner while it works.
Afterwards a toast summarises the run, with counts joined by a middle dot: 3 successful · 1 failed · 1 skipped. If something was skipped, the toast offers an Approve action that jumps straight to that KPI’s edit dialog. If something failed, it offers Details, which opens the Fetch Log. With no automatic KPIs configured at all, you get No auto KPIs configured.
In read-only mode the button is disabled and its tooltip reads “Requires a license or active trial”.
Run now, for a single KPI
Every automatic KPI carries a play button. On a Dashboard card it sits next to the source badge (BASH, HTTP or CONNECTOR) and is always visible. On the KPI detail page the same action appears as a button labelled Run now.
It runs exactly the same code as the scheduler: same value, same Fetch Log record, same alerts. On success you get KPI updated with <name>: <value>; on failure Auto-KPI failed with the error and a View details action. Manual KPIs do not show the button.
Unlike the Dashboard’s Refresh, the per-KPI play button is not disabled in read-only mode. Pressing it there produces an Auto-KPI failed toast whose description is “Trial expired” or “License revoked”.
The daily reminder
Pulsaria can send one native macOS notification a day to remind you that today’s numbers are still missing.
- Open App Settings from the sidebar and find the Reminders card.
- Turn on Daily reminder. macOS asks for notification permission the first time.
- Set the Time — the default is
18:00. - Decide whether Only if today is still empty stays ticked (it is on by default).
- Optionally press Send test notification to see what it looks like.
The notification is titled “Pulsaria” and reads “You haven’t recorded today’s KPIs yet.” The test notification uses the same title with the body “Test notification — this is what your reminder looks like.”
Only if today is still empty looks at manual KPIs only. The reminder is suppressed when any manual KPI already has an entry for today — and also when you have no manual KPIs at all, since there would be nothing to remind you about. Values fetched automatically neither suppress it nor trigger it.
Permission is requested when you switch the toggle on and checked again before every send. If macOS denies it, the settings page shows “Notifications were denied by the system.” for a few seconds; you can grant it later under System Settings → Notifications.
Known limits, plainly:
- No catch-up. The app must be open at that exact minute, otherwise the reminder is skipped for the day.
- Exactly one reminder per day. No weekday selection, no snooze, no per-KPI reminders.
- Moving the time to a later hour on the same day can produce a second notification, because the once-a-day guard is keyed to the configured time as well as the date.
- The reminder is not affected by read-only mode; it keeps firing when auto-fetch is paused.
- Nothing else uses notifications. Failed fetches and status changes stay inside the app as toasts and banners.
Where to go next
- Fetch log — every attempt, with stdout, status codes and errors
- Connectors — ready-made metrics and their default schedules
- Custom HTTP sources and Shell commands — the approval model
- Settings — Launch at Login, reminders, auto-export