Skip to content

Scheduled work

The scheduler wakes an agent when nobody is talking to it. Four trigger shapes, one job table.

Crona crontab expression — 0 9 * * *
Everyan interval — 15m, 2h
Atonce, at a time — 2h from now, or a timestamp
Webhookwhen a URL is called, rather than on a clock

The Schedule page

The dashboard’s Schedule page covers the first three and Webhooks the fourth. They are the same jobs seen from the two sides that matter: what fires on a clock, and what fires when something calls it.

Schedule stays daemon-wide rather than per agent, even though every job has an owner, because you usually want to see everything scheduled at once.

From the CLI

Terminal window
nouride cron # what is scheduled and enabled
nouride cron --all # including disabled ones
nouride cron run <id> # fire it now
nouride cron runs <id> # its history
nouride cron enable|disable <id>
nouride cron rm <id>

Creating one

Terminal window
nouride cron add --name "morning-brief" \
--cron "0 9 * * *" --tz Asia/Jakarta \
--agent nouva \
--gateway telegram:nouva --chat 123456789 \
--message "Summarise anything that changed overnight and anything waiting on me."
Flag
--namewhat it is called
--cron "0 9 * * *" / --every 15m / --at 2hpick exactly one
--tz <zone>which clock the schedule is read against
--agent <id>which agent owns it
--gateway <id> --chat <id>required — where the result goes
--message <prompt>wake the agent with this
--text <message>deliver plain text instead. No model call, no cost
--command <shell>run a command. No model call
--then agent…and have the agent read its output
--session <fresh|isolated|chat>what history the turn sees
--quietdo not announce the run
--keepkeep a one-shot after it fires

nouride cron update <id> takes --name, the schedule flags, --tz, --text and --message.

Three kinds of job, and the cost of each

--text is a plain reminder. Nothing calls a model, so it costs nothing. Reach for it whenever the message is the whole point.

--command runs a shell line and delivers the output. Also no model call. --then agent adds one: the agent reads the output and reports on it, which is the difference between “here is the disk usage” and “the disk is filling up, here is what is eating it”.

--message wakes the agent with a prompt. One turn, with tools, at the usual cost.

What history the turn sees

--session is the setting people most often want and least often find.

fresh (default)no history. The agent starts clean every time
isolateda private, persistent thread for this job — it remembers its own past runs, and nothing else
chatthe target chat’s own conversation, as if you had typed the prompt there

Webhooks

An endpoint that runs a job when something calls it.

Terminal window
nouride webhook # what exists, and its URL
nouride webhook add --name "deploy-finished" \
--agent nouva \
--gateway telegram:nouva --chat 123456789 \
--message "A deploy just finished. Check the health endpoint and report."
nouride webhook rotate <id> # issue a new URL; the old one stops working

Use nouride cron for rm, enable, disable, run and runs — they are the same jobs.

There is deliberately no --command for a webhook. A webhook is reachable by anything that learns its URL; an endpoint that runs argv on the host is a remote shell with a long password.

Guardrails

These exist because a model that can create jobs can create them in a loop.

min_interval_ms (60s)the floor on a recurring schedule. The difference between an agent scheduling a check and an agent scheduling a loop of provider calls
max_jobs (100)across every agent
fail_streak_limit (10)consecutive failures before a job disables itself and says why. nouride cron enable <id> clears it
catchup_window_ms (1h)how late an overdue job may be and still fire when the daemon comes back. Outside it, a recurring job moves to its next occurrence and a one-shot is recorded as missed — a daemon down for three days should not open with three days of reminders
run_retention_days (14)how long run history is kept
command_timeout_ms (10m)wall-clock ceiling on a --command payload
job_wake_max_chain (100)how many times a finished background job may wake an agent with nobody having said anything in between

That last one is worth a sentence. A job finishing wakes its agent, that turn often starts the next step, and its completion wakes it again — a chain with no human in it, each hop a provider call. It is set high on purpose: a nine-step install is nine jobs, and that chain is legitimate. At the limit the wake-up is still delivered and the agent is told to report and start nothing further; suppressing it would hide exactly the failures this guards against. Any message from a person resets the count.

Approvals at 3am

A scheduled turn that hits an approval is auto-approved by default and the decision is recorded in the audit log against the job, because a job that stops at a prompt nobody will see has not run at all. [cron] unattended_approval = "deny" makes it fail honestly instead.

Either way the hardline classes still ask, and still fail closed when nobody answers. Approvals →

Background jobs are a different thing

nouride jobs lists work an agent started during a turn — a long build, a slow script — not anything scheduled.

Terminal window
nouride jobs
nouride jobs log <id>
nouride jobs kill <id>

When one finishes it wakes the agent that started it, which is the chain job_wake_max_chain bounds.