Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Run if missed (cron catch-up)

A per-job switch, off by default, that makes a cron job catch up once when Omniscio was closed across its scheduled time — instead of quietly skipping the missed fire as it does today. Covers where the toggle lives, why every missed window collapses into a single run, the seven-day limit, and what a catch-up run still respects.

What it is

Omniscio's cron scheduler only fires a job when Omniscio is actually running at the scheduled minute. If your laptop was asleep, Omniscio was closed, or you were away for a few days, a job scheduled for "every day at 9 AM" simply doesn't run for the days Omniscio was off — by default Omniscio notices the missed fire, writes a log note, and quietly moves the schedule forward to the next future run without running it. (That default is deliberate: it stops a job that was missed hundreds of times from firing hundreds of times the moment you open the app.)

Run if missed is a per-job toggle, off by default, that changes that one decision for the job you turn it on for: when Omniscio was closed across the job's scheduled time, the job runs once the next time you open Omniscio, catching up misses from the last 7 days.

This is the catch-up behavior Windows Task Scheduler calls "Run task as soon as possible after a scheduled start is missed" — now available on Omniscio's own cron jobs, so you get Omniscio's friendly schedule presets, AI-by-chat scheduling, inbox failure alerts, and self-healing without having to split your automations between Omniscio and Task Scheduler.

Where to find it

It is not a global switch — it belongs to one job. Open the Cron Jobs view from the Cron row in the sidebar, click the job you want, and Run if missed sits in that job's editor alongside the other per-job toggles. Tick it and save; the setting is stored with the job and travels with it.

How it behaves

How to use it

  1. Open the job's editor. In Omniscio's Cron Jobs virtual project, click any job to bring up its editor dialog. "Run if missed" lives below the other per-job toggles in the same form.
  2. Flip on "Run if missed." The row is labelled Run if missed with the description "If Omniscio was closed at the scheduled time, run once on next open (catches up misses from the last 7 days)." Off by default — existing jobs keep their current behaviour until you opt in.
  3. Save. That's it. The next time you open Omniscio after a missed fire, the job runs once within about a minute of launch.

The toggle is hidden for one-time jobs ("run once at a specific date/time"). A one-off has no recurring schedule to resume, so catch-up doesn't apply to it — only recurring and limited (run-N-times) jobs show the toggle.

What to expect

  • One catch-up run, not one per missed day. However many scheduled fires were missed while Omniscio was closed — three days of a daily job, a whole weekend of an every-5-minutes job — the job runs exactly once on next open. All the missed windows collapse into that single catch-up, then the schedule resumes normally from the next future time. So the "an every-minute job would fire hundreds of times" worry doesn't happen.
  • Only misses from the last 7 days catch up. If a job was missed longer ago than a week (an automation that lay dormant while you were away for two weeks), it is not caught up — it just resumes on its normal schedule, same as the default. The 7-day window covers a long weekend or a normal vacation without resurrecting something stale.
  • It respects everything a normal run respects. The catch-up run goes through Omniscio's normal scheduled-run path, so:
    • Approval still applies. If the job requires approval, the catch-up run waits in your inbox for your tap, exactly like a normal fire — it is never auto-fired around the gate.
    • It won't double-run. Omniscio's at-most-once guards apply, so a catch-up can't fire the same job twice.
    • Cost applies once. For paid jobs (ones that run a recipe or spawn a Claude session), the catch-up is one billable run, not one per missed window. If you opt several paid jobs into catch-up and you've been away a while, expect each to fire once when you open Omniscio — that's the intended behavior of opting in.

For agents

How it works (for the curious / for agents)

When Omniscio starts, the cron engine runs recomputeAllNextRuns() (src/main/services/cron/cron-recovery.ts). For every active job whose next_run_at is now in the past (a fire window elapsed while Omniscio was closed):

  • Default (catch-up off): advance next_run_at to the next future fire and log a "missed while Omniscio was closed (not re-fired)" warning. (This is the long-standing F129 anti-thundering-herd behavior.)
  • Catch-up on (and the job is recurring/limited, and the miss is within 7 days): leave next_run_at in the past. That's the entire mechanism — nothing re-fires the job directly. Because the cursor is left in the past, the engine's next 60-second tick selects the job via listDueCronJobs and runs it once through the ordinary dispatch path. When that run starts, the dispatch claim (claimCronJobFire → getNextRun(now)) advances the cursor to the next future fire, which is what collapses every missed window into the single catch-up run.

Because catch-up is just "let the normal tick fire it," the approval gate (listDueCronJobs only returns jobs whose approval_status is not_required or approved), the per-job in-flight guards, retries, and the claim-before-dispatch idempotency all apply with no extra code. See cron-self-healing.md and create-cron-job-with-ai.md for the surrounding cron machinery.

The cursor claim must not advance before the run row

The whole catch-up mechanism above depends on one ordering inside the engine: the durable cursor advance (claimCronJobFire) happens AFTER the run row is created, never before it. Both halves of recovery need that. listDueCronJobs selects on next_run_at IS NOT NULL AND next_run_at <= asOf, and recomputeAllNextRuns skips one_off outright — so a cursor advanced at selection time leaves a fire that is neither selectable nor re-armable, and a run row is the only thing jobsToResumeAfterRestart can find.

This was broken once, on 2026-09-28, by hoisting the claim into the tick's critical section to stop the tick racing itself. Everything above stayed written as it is now while the code no longer matched it, so a crash between the claim and the run row silently lost a one-off reminder with nothing failing loudly enough to say so. The self-race is closed instead by a process-local reservation taken inside the critical section (tickReservedJobs in src/main/services/cron/cron-engine-service.ts) — it touches no durable state, so a crash while it is held advances nothing and the fire is simply still due. tests/integration/cron-claimed-fire-survives-restart.test.ts fails if the claim moves ahead of the run row again.

The toggle is backed by the cron_jobs.catch_up_if_missed column (per-job, default 0), surfaced as CronJob.catchUpIfMissed, and is settable through both the in-app editor and the CLI control server's POST /cron/jobs + PATCH /cron/jobs/:id (so an external AI can turn it on when it creates or edits a job, approval-gated like any other CLI cron change).

Related

The surrounding cron machinery — how jobs are created and what the engine's regular tick does — is on the create a cron job with AI page. Its sibling opt-in, which repairs a job after it fails rather than after it is missed, is cron self-healing, and what you see when a run fails for good is on cron failure alerts.

Last verified 2026-09-28