> Public product help. This page has no customer entries, projects, chat transcripts, API keys, or horizon contents.
> Reading that data requires `Authorization: Bearer` (a signed-in app session JWT, or a Headless access token).
> Do not call Supabase `/rest/v1` with a Headless JWT. Data reads go through `/casc/v1/headless/v1/rest`.

# Toolchain Scheduler

Schedulers are first-class **Tools** that run either a **tool chain**
or a **generic prompt** (instructions + attached tools) on a **UTC cron**
schedule. The smallest minute step is **15 minutes**. Prefer this over
**Settings → Schedules (deprecated)** for recurring operational work.

## Create a scheduler

1. Open **Settings → Tools** and create a tool with type **Scheduler**.
2. Set a 5-field cron expression (UTC). Minutes must be `0`, `15`, `30`, or `45` (for example `*/15 * * * *`, `0 * * * *`, `0 9 * * 1-5`). Preview at [crontab.guru](https://crontab.guru/).
3. Choose **Tool chain** (no LLM) or **Prompt** (LLM uses that prompt’s text and attached tools).
4. Save — the scheduler is created **inactive**.
5. Open **Settings → Scheduler** and click **Activate** (or ask chat to activate it).

Next run is the **next clock time** that matches the cron, not “last start plus an interval”.
If a run overruns a slot, the following matching time is used. Overlap is still blocked while a job is running.

## Prompt vs tool chain

A tool chain executes configured steps in order with no model. Structured tools (filter, entry update)
need step args JSON or tool default arguments — **Run Now** does not send chat arguments.

A prompt run is a headless agent turn: the prompt’s system/user text plus optional extra instructions,
with the tools attached to that prompt. Use a project/generic prompt (not Horizon ingest, review, or
management). The scheduler tool owner’s API keys are used. Entry-update tools apply immediately on
schedule when the target row is unique.

## Entry update on a schedule

Chat still confirms field writes in a modal. Scheduled runs skip the modal. Identify the row with
exactly one of:

- A previous filter step that returns one item (`entry_id` is handed off), or
- Step args lookup, for example `{"filters":[{"key":"article_id","op":"eq","value":"12345"}],"field_updates":{"status":"Extracted"}}`

Put lookup keys such as `article_id` in the entry-update tool’s writable/return fields even if you do not write them.

## States

| Status | Meaning |
| --- | --- |
| inactive | Will not run until activated |
| active | Eligible to start when due |
| paused | Config kept; timer skipped until resume |
| running | A run is in progress (overlap is blocked) |
| error | Last run failed; retries on the next cron slot |
| needs_attention | Three consecutive failures — auto-run stopped until Clear & activate |

## Settings → Scheduler

Monitor status, pause/resume, run now, and inspect stdout / recent history. A red badge on the nav item shows the count of jobs in `error` or `needs_attention`.

## Chat control

Agents can call the scheduler tool with `action`:

- `status` (default), `activate`, `pause`, `resume`, `deactivate`
- `run_now`, `logs`, `clear_attention`

## Migrating from ingestion Schedules

**Settings → Schedules** (periodic ingestion) is deprecated. There is no automatic conversion.
Recreate operational workflows as Scheduler tools that call the tools you need (including any ingest-trigger tooling you configure).
