Skip to main content
A routine is a YAML object inside the routines: array on an agent’s frontmatter. This page documents every field, every supported schedule pattern, and the limits that shape what kinds of routine actually work. For the concept, see Routines. For a walkthrough, see Set up a routine.

Where routines live

Every routine is declared on the agent it runs for. Inside the agent file’s frontmatter:
Routines are a Rundock concept. The routines: array is read by Rundock’s scheduler and ignored by Claude Code. An agent file with routines works in plain Claude Code; the routines simply do not run there.

Frontmatter fields

Each entry in the routines: array is a YAML object with four fields. The whole routines block is Rundock-only. Other tools that read agent frontmatter ignore it.

Schedule format

The schedule field accepts only two patterns. Both are exact regex matches.

Examples that work

Examples that look correct but never fire

The scheduler does not raise an error on a bad schedule string. The routine registers fine and silently never runs. Always check the schedule string first when a routine appears to do nothing.

Timezone

The schedule is interpreted in the local timezone of the machine running Rundock. There is no timezone field on a routine. If you run Rundock on a VPS in a different timezone from where you live, set the schedule for the VPS’s local time, not yours.

Scheduler behaviour

The scheduler ticks every 60 seconds. On each tick:
  1. Rundock re-discovers all agents (this picks up routine changes without a restart).
  2. For every routine on every agent, the scheduler computes the next run time.
  3. If the next run time has come due, Rundock fires the routine.
Each routine has a lastRun guard. Daily routines do not re-fire the same calendar day. Weekly routines do not re-fire on the same weekday they last ran on. The guard is held in memory on the server. When a routine fires, Rundock spawns a headless Claude Code subprocess with the routine’s prompt as the input message. The subprocess runs with --dangerously-skip-permissions because there is no user available to approve tool calls in real time.
lastRun is in-memory. When Rundock restarts, the guard is wiped. If a routine fired earlier in the day and Rundock restarts before the next tick rolls past midnight, the daily-schedule branch may fire the routine a second time when it would otherwise be suppressed. Rarely matters in practice (most morning briefings are idempotent), but worth knowing.

Routines fire only while Rundock is running

This is the central limit and it shapes everything else.
A missed slot is caught up the same day, not lost. If Rundock is closed at 05:00 and you open it at 09:00, the 05:00 routine fires shortly after launch: a next-run time that has already passed stays on today rather than rolling forward to tomorrow. Run state persists to .rundock/routine-state.json, so a restart does not fire a routine twice. What catch-up cannot do is run on time, or run at all on a day you never open Rundock.
Two practical paths around this:
  • Run Rundock on a small VPS so the scheduler ticks 24/7. Reach it from any device through a browser.
  • Use Anthropic’s Claude Code Routines, Anthropic’s managed scheduling layer, for repo-bound work that can run on their cloud.
The split that tends to work in practice: keep workspace-bound routines (anything that depends on local files or a Rundock agent’s system prompt) on Rundock and host Rundock on a VPS if you need 24/7 firing. Move repo-bound work (PR triage, scheduled code review, release notes) to Anthropic’s Routines.

Where routine output goes

When a routine fires, the spawned Claude Code subprocess produces output on stdout (stream-json) and stderr.
Rundock does not capture or surface this output. The pipes are open but unread. The model’s response, any tool calls it made, any files it produced via Write or Bash: none of these flow back into a Rundock conversation or notification.
What Rundock records:
  • The routine’s lastRun timestamp.
  • The routine’s status (running, completed, failed, or interrupted). The first three follow the subprocess exit code; interrupted is written on startup when a run was still marked running when the process died, so a routine killed mid-run is distinguishable from one that failed.
  • The routine’s duration in seconds.
These three fields update in the routines panel and on the agent profile in real time over the WebSocket. The practical implication: any routine that needs to leave a trace must write that trace itself, through the agent’s tools. A morning briefing creates a file in the daily note. A research digest writes a markdown report. An end-of-day sync updates Todoist via MCP. A routine that asks the model to think out loud will produce output nobody ever reads. There is no built-in notification when a routine completes. You notice a routine ran by either seeing the timestamp update in the routines panel, or seeing the file the agent wrote, or seeing the Todoist tasks the agent created.

The routines panel

The routines panel sits at the bottom of the left sidebar, beneath the team list and the platform agent list. It is workspace-level: routines from every agent in the workspace are aggregated into one flat list. Each row shows three things:
  • The owning agent’s avatar (icon and colour from the agent’s frontmatter).
  • The routine’s name.
  • A short formatted schedule: 5:00 AM for daily, Fri 4:00 AM for weekly.
While a routine is running, the schedule text is replaced with a Running... indicator in the workspace’s working colour.
The panel is display-only. Routine rows are not clickable. There is no per-routine enable or disable toggle and no delete control. To pause a routine without deleting it, comment it out (or remove it) from the agent’s frontmatter; Rundock picks up the change on the next scheduler tick.
The agent profile page shows a richer routines card. Each entry on the profile shows the routine’s name, the raw schedule string, and a status line: Last run: <relative time> (<status>) once a run has occurred, or Not yet run before the first run.

Complete worked example

Here is a complete agent file with a single routine. Every field is present.
Notes on this routine:
  • The schedule uses the daily form, two-digit zero-padded.
  • The prompt is short. It assumes the agent’s body knows what “the morning briefing” means.
  • The description appears on the profile under the routines card. It does not affect the scheduler.

Common patterns

Five recipes that work in practice.

Morning briefing on the orchestrator

End-of-day sync

Weekly research digest

Weekly digest on a different day to avoid collisions

Multiple routines on one agent, staggered

Stagger the times. Two routines firing in the same minute spawn concurrent Claude Code subprocesses that do not share context, conversation history, or file locks.

Common pitfalls

Cron expressions silently never fire. The scheduler does not understand cron. A routine with schedule: 0 5 * * * parses fine, registers fine, and never runs. There is no error, no warning, no log line. If a routine appears to do nothing, the schedule string is the first thing to check. Hours without a leading zero never fire. The pattern is exact. every day at 9:00 does not match. Always zero-pad. Abbreviated and multi-day weekdays never fire. Capitalisation is safe: the schedule string is lowercased before matching, so every Friday at 04:00 works. But the parser only matches one full lowercased weekday word. every Fri at 04:00, every Mon-Fri at 09:00, and every weekday at 18:00 do not match. Rundock is closed for a whole day. The scheduler is in-process, and catch-up is same-day only: a daily routine missed for an entire calendar day is not replayed the next day, and a weekly routine missed on its weekday waits a week. Opening Rundock later on the same day is fine, the routine fires then. For routines that must run at a particular hour, or on days you might not open Rundock at all, host it somewhere always-on. Routines that need their output read. Rundock does not capture stdout. If the agent does not write its output somewhere durable through tools, the run produces nothing the user can find later. Always design routines so the agent writes a trace. Two routines on the same agent fire in the same minute. Both spawn Claude Code subprocesses concurrently. They do not share context or file locks. Stagger the schedules unless the routines are genuinely independent and idempotent. Routine name changed after first run. The routine’s lastRun guard is keyed on agentId:name. Renaming a routine creates a new key, which means the new name has no run history and may fire immediately on the next tick if its schedule has already passed. To rename a routine without an immediate re-fire, do it just after a known successful run rather than just before the next due time.

Where to next

Routines concept

What routines are, what they are good for, and the limits worth knowing.

Set up a routine

A walkthrough of adding a routine to an agent and confirming it fires.
The full source of truth is ROUTINES.md in the Rundock GitHub repo. It tracks any new fields and scheduler behaviour as they ship.