You are reading Nightly documentation for 0.12.4.dev0+g50bde75.

This documentation may describe behavior that differs from Stable.

Open Stable documentation

Documentation version

0.12.4.dev0+g50bde75 · Nightly

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 to selective.
  • --on-gated cancel|hold — what happens when a gated action fires unattended (default cancel; see below).
  • --misfire skip|fire-once — whether a firing missed while the host was down is skipped or fired once on return (default skip).
  • --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 8
  • every monday at 9 (any weekday name)
  • every day at 7
  • every 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-all or unrestricted is 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-gated decides: hold parks the approval and suspends the run; cancel denies 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.