Scheduler and automation
Scheduler and automation
The persistent host (holaryn serve, the desktop app, or the OS service) can run the agent unattended on a schedule, or on demand from an external webhook. Jobs are stored in a SQLite database inside the state directory, so schedules survive host restarts — and unattended runs never approve their own consequential actions.
The Scheduler tab also manages durable event sources for authenticated webhooks, folder
changes, repeating timers, and connector delta feeds. These add cursor, deduplication, filtering,
rate/circuit isolation, health, and replay around the same approval-aware dispatch path. See
Event sources and trigger automation.
Creating jobs
Use the Scheduler tab in the web UI (Ctrl+7 by default), or the CLI:
holaryn schedule "<spec>" <prompt...> # add a job
holaryn schedule list
holaryn schedule cancel <job_id>
For example:
holaryn schedule "every weekday at 8" summarize my inbox and flag anything urgent
holaryn schedule "cron:30 18 * * 5" --posture selective prepare the weekly report
Flags on holaryn schedule:
--posture ask|selective|allow-all|unrestricted— the autonomy posture the job runs under. Omitted, it defers to the job's profile posture, falling back toselective.--on-gated cancel|hold— what happens when a gated action fires unattended (defaultcancel; see below).--misfire skip|fire-once— whether a firing missed while the host was down is skipped or fired once on return (defaultskip).--policy <file.toml>— a per-job autonomy policy profile that pre-authorizes or tightens specific categories and tools.--profile <name>— the config profile the job runs on (model, persona, posture, settings overrides, memory).--team <name> [--to MEMBER] [--topic TOPIC]— instead of running the agent, post the text to that team's thread as the operator at each firing (a scheduled kickoff; workers are staffed first). The agent-run flags above do not apply. See Teams.
Schedule specs
Three explicit machine forms are the guaranteed contract:
cron:M H DOM MON DOW # five-field cron, e.g. cron:0 8 * * 1-5
interval:SECONDS # recurring, e.g. interval:900
date:UNIX_EPOCH_SECONDS # one-shot at an absolute time
Plain-language phrases also work. A small fixed set is translated offline and deterministically:
every weekday at 8every monday at 9(any weekday name)every day at 7every 15 minutes,every 2 hours
Anything outside that set is offered once to your configured default model, which must answer with a single machine spec line; the answer is validated by the ordinary parser before use (the CLI prints understood as: ...). If no model is configured or the answer is unusable, the spec is rejected — scheduling never silently guesses.
Unattended runs and approvals
Scheduled runs are unattended, and the autonomy model treats them strictly:
- A job requesting
allow-allorunrestrictedis downgraded to ask-first at dispatch (with a warning) — unless the job is a dry run, where staging is already the safe mode. - When the run hits an action its policy says must ask,
--on-gateddecides:holdparks the approval and suspends the run;canceldenies the action. A held approval is never auto-approved and a suspended run is never auto-failed — it waits for you. - Parked approvals land in the Approvals tab of the web UI (the operator inbox, with a pending-count badge visible from anywhere), alongside operator questions and post-restart resume decisions. Approve or deny there, and the suspended run resumes.
For routine automations, prefer a --policy profile that pre-authorizes exactly the categories the job needs (for example "fs.write" = "notify") over a broader posture. To earn trust in a new automation first, schedule it as a dry run and batch-review its staged plan — see autonomy-and-approvals.md.
Webhook triggers
External systems (CI, home automation, Zapier-style services) can fire an existing job by POSTing to the running host — no polling:
curl -X POST http://127.0.0.1:8765/api/hooks/<job_id> \
-H "X-Holaryn-Webhook-Token: <token>"
A webhook call dispatches the job immediately with the same prompt, posture, policy, profile, and parked-approval behavior as a scheduled firing; the job's own schedule is untouched. For a webhook-only job, define it with a far-future date: spec.
Webhooks are strictly opt-in: the endpoint does not exist until a dedicated trigger token is configured, either as HOLARYN_WEBHOOK_TOKEN in the host environment (restart applies it) or via the settings API (POST /api/settings/webhooks/token, applies immediately; DELETE disables webhooks again). The token is write-only, never echoed, and independent of the LAN auth token — leaking it lets a caller trigger predefined jobs, never define new ones. Keep it in a header, out of URLs and logs.
Routing jobs to profiles
On a shared host, config profiles are the "agents" that jobs and channels route to. A job created with --profile (or the Profile select on the Scheduler page) runs with that profile's model, persona, posture, and memory; webhook firings inherit it. A job whose profile was deleted or renamed fails loudly at dispatch rather than silently degrading. Messaging channels route the same way — for example, each profile can be bound to specific Telegram chat ids.
Related pages
- event-sources.md — durable source lifecycle, filters, health, and replay
- autonomy-and-approvals.md — held actions, suspension, policy profiles, dry-run
- running-the-agent.md — keeping the host running so schedules fire
- web-interface.md — the Scheduler and Approvals tabs
- cli-reference.md — full
holaryn schedulereference