Skip to content

Scheduled tasks

Scheduled tasks let you automate recurring AI prompts — daily summaries, weekly reports, periodic vault maintenance — without any manual intervention. Each task runs as a headless agent session and writes its output to a file in your vault.

Overview

A scheduled task is a markdown file stored in [state-folder]/Scheduled-Tasks/. The file's frontmatter controls when and how it runs; the body is the prompt sent to the model.

text
gemini-scribe/Scheduled-Tasks/
├── daily-summary.md          ← task definition (you create and edit this)
├── Runs/
│   └── daily-summary/
│       └── 2026-04-18.md    ← output from each run
└── scheduled-tasks-state.json  ← runtime state (managed automatically)

Creating a Task

The easiest way to create a task is through the Scheduler UI:

  1. Open the command palette and run Open scheduler (or go to Settings → Gemini Scribe → Automation → Open scheduler)
  2. Click New task
  3. Fill in the slug, schedule, tool access, and prompt
  4. Click Create task

You can also create tasks manually by writing a markdown file directly:

Create a markdown file inside [state-folder]/Scheduled-Tasks/. The filename (without .md) becomes the task's slug — used in output paths and the task monitor.

Minimal examplegemini-scribe/Scheduled-Tasks/daily-summary.md:

markdown
---
schedule: daily
toolPolicy:
  preset: read_only
---

Summarize the notes I created or modified today. List the key topics and any open questions.

Frontmatter Fields

FieldRequiredDefaultDescription
scheduleYesWhen to run. See Schedule Formats below.
toolPolicyNoinherit global plugin policyPer-run tool policy (preset + per-tool overrides). See Tool Access.
outputPathNo[state-folder]/Scheduled-Tasks/Runs/<slug>/{date}.mdWhere to write results. Supports {slug} and {date} placeholders.
modelNoPlugin chat modelOverride the model for this task (e.g. gemini-flash-latest).
maxIterationsNo20Cap on agent tool-call batches per run. Raise it for long multi-step tasks that exhaust the default. See Tool Iteration Limit.
enabledNotrueSet to false to disable the task without deleting it.
runIfMissedNofalseWhen true, tasks missed while Obsidian was closed are caught up on the next startup. See Catch-up Runs.

Schedule Formats

ValueRuns…
onceExactly once, then stops
dailyEvery 24 hours from when the task was created
daily@HH:MMEvery day at the given local time (24-hour). Example: daily@16:30 for 4:30 PM
weeklyEvery 7 days from when the task was created
weekly@HH:MM:DAYSAt the given local time on the listed weekdays. DAYS is a comma-separated list of sun,mon,tue,wed,thu,fri,sat
interval:XmEvery X minutes (e.g. interval:30m)
interval:XhEvery X hours (e.g. interval:2h)

HH:MM is 24-hour and uses your local timezone. The scheduler ticks once a minute, so a task scheduled for 16:30 may fire any time between 16:30:00 and 16:30:59. Daylight saving transitions follow JavaScript Date semantics — on the spring-forward day, a daily@02:30 slot may shift by one hour.

Example — run a daily summary every weekday at 4:30 PM:

markdown
---
schedule: weekly@16:30:mon,tue,wed,thu,fri
toolPolicy:
  preset: read_only
---

Summarize the notes I created or modified today.

Tool Access

The toolPolicy block controls what the agent can do during a run. It uses the same shape as the global plugin tool policy and as project / hook / session policies — a preset baseline plus optional per-tool overrides:

yaml
toolPolicy:
  preset: read_only # one of: read_only, cautious, edit_mode, yolo
  overrides: # optional per-tool overrides
    fetch_url: deny
    write_file: allow
PresetEffect
read_onlyRead tools only — write / destructive / external tools are removed from the registry.
cautiousReads allowed; writes/destructive/external ask for confirmation. (Default global preset.)
edit_modeReads + writes execute; destructive/external still ask.
yoloEverything executes without confirmation. Use with care.

Omitting toolPolicy (or setting it to an empty object) means inherit the global plugin tool policy. The Scheduler UI exposes the same controls — picking a preset and adjusting per-tool overrides — so you usually don't need to author the YAML by hand.

Legacy note — older task files used enabledTools: ['read_only', …] instead of toolPolicy. They still load: the plugin maps the old category list onto the closest preset and rewrites the file to the new shape the first time it is read.

Tool Iteration Limit

Each run drives an agent loop that calls tools, reads the results, and calls more tools until it produces a final response. To guard against runaway loops in unattended runs, that loop is capped at 20 tool-call batches by default. A batch is one round of tool calls (which may run several tools in parallel), not a single tool call — so a task doing parallel work fits more real calls into 20 batches than a strictly sequential one.

The cap is a soft budget, not a hard cliff. As the run nears its limit, the agent is told how many turns it has left so it can wrap up cleanly instead of being cut off mid-thought. And if it runs out while still mid-task, it's granted a one-time extension (half the original budget, rounded up) with a nudge to finish — so a task that needs "just a couple more" turns isn't killed at the cap. Only when that extension is also spent does the run fail:

text
Task "<slug>" exhausted its tool-iteration budget (cap 20, ran 30) without producing a response

If a legitimately long task keeps hitting this, raise the cap with the maxIterations frontmatter key (or the Max tool iterations field under Advanced options in the Scheduler):

yaml
---
schedule: 'daily@06:00'
maxIterations: 50
---

maxIterations must be a positive whole number; blank or invalid values fall back to the default of 20. The interactive agent chat applies the same soft-budget machinery with a much higher default (50 batches), so the reminder and one-time extension also protect long interactive turns from runaway loops without getting in the way of normal multi-step work.

Managing Tasks

Open scheduler

The Scheduler modal is the primary way to manage your tasks. Open it from:

  • Command palette → Open scheduler
  • Settings → Gemini Scribe → Automation → Open scheduler

From the Scheduler you can:

ActionHow
View all tasks with next/last run timesTask list
Create a new taskClick New task
Edit an existing taskClick Edit on any row
Enable or disable a taskClick Disable / Enable
Trigger an immediate runClick Run now
Reset a paused taskClick Reset on a paused row
Delete a taskClick Delete

Create a New Task via Command

You can also open the create form directly: Command Palette → New scheduled task.

Read-Only Status View

For a lightweight read-only summary, use Command Palette → View scheduled tasks. This panel shows the same task list without edit controls.

Output Files

Each run writes a file to the resolved outputPath. The file includes a frontmatter header:

markdown
---
scheduled_task: 'daily-summary'
ran_at: '2026-04-18T08:00:00.000Z'
---

<model response here>

The {date} placeholder in outputPath is replaced with the local date (YYYY-MM-DD), so each run produces a separate file by default.

Error Handling and Pausing

If a task fails 3 consecutive times, the scheduler automatically pauses it to prevent runaway retries. The task monitor shows it with a paused badge and displays the last error.

To resume a paused task:

  1. Open Command Palette → Open scheduler
  2. Fix the underlying issue (e.g. invalid prompt, missing API key)
  3. Click Reset next to the paused task

Catch-up Runs

When Obsidian is closed, scheduled tasks cannot run. Set runIfMissed: true in a task's frontmatter to have it caught up automatically the next time Obsidian starts.

On startup, the plugin compares each task's nextRunAt against the current time. Any task with runIfMissed: true that is overdue (and not paused) is treated as a missed run. By default, a red ! badge appears on the background-tasks status bar item — click it to open the Missed scheduled runs modal, which lists each missed task with Run and Skip buttons. On mobile (where the status bar is hidden), the modal opens automatically on startup instead of waiting for a badge click.

  • Run — submits the task immediately as a background task
  • Skip — advances the schedule without running
  • Run all / Skip all — bulk actions for all listed tasks

Dismissing the modal (Escape or ✕) leaves the ! badge in place so you can reopen the modal later by clicking the badge.

Auto-run on startup

Enable Settings → Gemini Scribe → Automation → Auto-run missed scheduled tasks on startup to skip the approval modal entirely and submit all missed tasks silently on every startup.

Notes

  • Only tasks with runIfMissed: true and enabled: true are included; tasks paused due to repeated failures are excluded.
  • Only one catch-up run is submitted per task per startup, regardless of how many intervals were missed.
  • Tasks missed more than 7 days ago are considered stale and excluded.

Scheduler Timing

The scheduler checks for due tasks every 60 seconds. Task files created while Obsidian is running are discovered immediately via a vault file-creation listener. Files that exist when the plugin loads are discovered on startup.

A task is considered due when the current time is at or past its nextRunAt value stored in scheduled-tasks-state.json. The first run of a newly discovered task is triggered immediately on the next tick.

Tips

  • Keep prompts focused — scheduled tasks run without streaming UI, so concise prompts produce more reliable outputs.
  • Use read_only unless you need writes — minimises the risk of unintended vault modifications.
  • Set enabled: false to pause a task temporarily without losing its schedule state.
  • Use once for one-off automation (e.g. a migration script) — the task becomes a no-op after its first run.