DorkOS
Guides

Scheduled tasks

Put any skill on a timer and let your agent run it without you

Scheduled tasks

The DorkOS Schedules page showing scheduled tasks with their timers and a run history of green checks

A scheduled task runs an agent on a timer, instead of you kicking it off by hand every time. Set it up once ("check for outdated dependencies every Monday at 10am") and DorkOS handles the rest, without you at the keyboard.

Any skill can become a scheduled task. A skill is a folder with a SKILL.md file in it that teaches an agent how to do one job. Add a few lines of timing to the top of that file and the same skill now also runs on its own.

Scheduled tasks fire whenever the DorkOS server is running: on your laptop while it's awake, or around the clock if you run DorkOS on a machine that stays on, like a desktop, a home server, or a cheap cloud box.

Scheduled tasks are on by default. Open the Schedules tab on Home and you're ready to create your first one.

Don't see a Schedules tab? Someone turned it off. Run dorkos --tasks, or see Turning scheduled tasks on or off below.

Put a skill on a timer

Open the skill's SKILL.md and add a schedule: block to the block of settings at the top:

---
name: daily-health-check
description: Runs lint, tests, and type checks and reports what broke
schedule:
  cron: '0 9 * * 1-5'
  timezone: 'America/New_York'
---
Run lint, the test suite, and the type checker. Report anything that failed.

That's the whole switch. The block's presence is what makes the skill a scheduled task, and deleting the block turns it back into a plain skill. Nothing else about the file changes, so the skill still works when you or your agent call it by hand.

The block takes a handful of settings. Only cron is worth learning first:

Prop

Type

Pick where it runs

Those last three are new, and the honest advice is to skip them. Leave all three out and the task runs wherever its agent runs, which is what you almost always want. Set one when you want this job somewhere else: a nightly review on Codex while the agent itself works on Claude Code, say, or a chatty summary task on a cheaper model.

Two things worth knowing before you set one.

A model belongs to one runtime. gpt-5.5 means something to Codex and nothing to Claude Code. Write the id the way the runtime you picked writes it. DorkOS does not check the spelling when you save, because the list of models lives on the other end and that end can be offline while you type. Instead, a line under the Model box says so when the model you named isn't one that runtime offers, and the run says so too if you save it anyway.

A runtime you haven't turned on stops the run. It never quietly runs somewhere else. A run on a different runtime is a different run, billed to a different account, with different tools, and you would have had nothing on screen to tell you.

Clearing a field puts the task back to following its agent. In the app, that is the first option in each menu: "Agent's runtime", "Agent default".

A schedule that comes from a marketplace package can't carry these three yet. Install the package, then set them on the task.

Where DorkOS looks

DorkOS reads two places for skills that carry a schedule: block:

  • ~/.dork/skills/ for tasks that belong to no particular project.
  • <your project>/.agents/skills/ for tasks that belong to one agent. The run happens in that project's folder.

A skill without a schedule: block is simply a skill, and DorkOS leaves it alone. New files are picked up as you save them, so you never restart anything.

DorkOS never reads .claude/skills/ for scheduled tasks. That folder is a copy DorkOS writes for you from .agents/skills/, and reading both would find every task twice.

Nothing runs until you approve it

A schedule that shows up in a file has to ask before it runs. It lands on the Schedules page marked Waiting for approval, and it stays parked until you say yes. That is true even when the file says enabled: true. The file states an intention; you grant the permission.

This matters because a git pull, a marketplace install, or an agent writing its own skill can all put a new timer on your machine. None of them can start one.

Your approval is tied to what the task actually says. Change its prompt or its timing and it parks again for a fresh look. Approve the same content twice, and it stays approved through every later sync.

Anything you create yourself in DorkOS starts armed. Clicking save is the approval.

Create one in DorkOS

Prefer buttons to files? The Schedules tab builds the same thing for you.

Open the Schedules tab

It's in the row of tabs across the top of Home. If you have nothing scheduled yet, you'll see a gallery of ready-made templates, things like "Daily Health Check" (run lint, tests, and type checks every weekday morning) or "Weekly Dependency Audit" (check for outdated packages every Monday).

Pick a template or start from scratch

Click a template card to pre-fill a scheduled task you can edit, or click "Start from scratch" to build your own. Either way, you land on a form with:

  • Agent: which agent runs the job, and in which project. This also decides the job's working directory.
  • Name and Description: what to call this scheduled task.
  • Prompt: the instruction the agent gets each time it runs, e.g. "Check for outdated npm dependencies and summarize what needs updating."
  • When it runs and Timezone (under "Schedule"): a cron expression is just a compact way to say "every Monday at 10am" or "every weekday at 9am." The visual builder in the form writes it for you, so you don't need to memorize the syntax (though the reference below has the full pattern if you're curious).
  • Runs on (under "Advanced settings"): which runtime, model and effort this job uses. All three start at "follow the agent", which is the right answer for most tasks. See Pick where it runs.
  • Permissions and Stop after (under "Advanced settings"): how much autonomy the agent gets and how long it's allowed to run before DorkOS stops it.

Save it

It shows up on the Schedules tab right away, along with its next run time. DorkOS writes it out as a real skill file, so your agent can read and use it like any other skill. Every run lands in the run history, which records the runtime and model that run actually used, so a task you move next week doesn't rewrite what its old runs did.

Will it actually run?

Short answer: yes, once it's live in a real DorkOS install. Scheduled tasks always show up and you can always edit them, but one only actually fires (starts an agent session) in a real production install of DorkOS, the one you get from the normal install, not a developer preview build. That's a deliberate safety rail: an unattended job can edit files and run commands on its own, so DorkOS won't let a test or development build fire one by accident.

If you're following this guide in a normal DorkOS install, you're already in the environment where they fire. Nothing extra to do.

Get a message when one finishes

DorkOS can message you the moment a scheduled task wraps up, so you do not have to sit and watch it. The message names the task, how long it took, and the first line of what it produced. This works on its own. The agent does not have to do anything.

To turn it on:

  1. Open the agent, go to Connections, and add a connection like Telegram.
  2. Bind the connection and open its Advanced settings.
  3. Turn on Message me when scheduled tasks finish.
  4. Turn on Agent can start conversations. This is the real switch. Nothing gets sent until you allow the agent to reach you.

Failures always reach you. Successful runs reach you only while the switch is on, so you can mute the routine "all good" pings and still hear about breaks.

A chat app like Telegram will not let a bot text you until you have messaged it first. Until you do, the connection shows a one-line reminder to "message your bot once." After your first message, notifications start flowing.

Cancelled runs never send a message, since you cancelled them yourself. Scheduled tasks that are not linked to an agent do not send a message yet.

Coming from an older version

Older versions of DorkOS kept scheduled tasks in their own folders, ~/.dork/tasks/ and <your project>/.dork/tasks/. You do not have to move anything. DorkOS rewrites those files into the new format and moves them to the skills folders above.

It happens the first time the new version starts, for every project registered with DorkOS at that moment. Register a project later and its old folder is migrated right then, as it registers, so a project you add next month gets the same treatment without waiting for a restart.

A file that already sits in a skills folder but still lists cron at the top level, rather than inside a schedule: block, is folded into the block in the same pass. DorkOS was ignoring it before; now it runs.

Anything you had already approved stays approved and keeps its timing. One exception, and it is the same rule as everywhere else on this page: if you edited a schedule's file while DorkOS was switched off, what it says no longer matches what you approved, so it parks for you to read again rather than arming itself on content nobody has seen.

Two cases park with a note instead of moving quietly:

  • A name that is already taken. If a skill of the same name already lives in the skills folder, that skill keeps its name, and the schedule arrives as <name>-migrated. It parks with a note naming both the folder it wanted and the one it got, so you can check it is still what you want before approving it.
  • A file too damaged to read. DorkOS leaves it exactly where it is and parks it on the Schedules page with a note naming the file, so nothing disappears quietly.

How this differs from Claude Code's /loop

Claude Code's /loop repeats a prompt inside the chat you are sitting in. Close that session and the loop is gone with it.

DorkOS Pulse, the scheduler behind this page, is the durable one. Your scheduled tasks live in files, survive restarts, and fire whether or not you have a chat open. Each run starts its own fresh session, and the history of every run is kept.

When a scheduled task tells the agent to use another skill

One gotcha is worth knowing. A skill can carry disable-model-invocation: true, which means "never pick this up on your own; only run it when asked directly."

That flag belongs on the scheduled task itself, not on the skills its prompt tells the agent to use. Scheduled runs are unaffected by the flag, because DorkOS sends the prompt straight to the agent. But if your prompt says "use the changelog skill," and the changelog skill carries the flag, the agent will not reach for it, and the run quietly does less than you asked.

Turning scheduled tasks on or off

They ship on, so most people never need to touch this. If someone turned them off, or you want to force them on or off for a specific run:

dorkos --tasks
dorkos --no-tasks

You can also set DORKOS_TASKS_ENABLED=true (or false) as an environment variable; it takes the same effect as the flag. Whichever you set last wins.


Reference

The rest of this page is for people who want the API, the exact data model, or the implementation details. If you just wanted to schedule an agent, you're done, go create something.

Names on the wire kept their old spelling on purpose: the REST paths are still /api/tasks, and the MCP tools are still tasks_*. Only the words people read changed.

REST API

Create a scheduled task:

curl -X POST http://localhost:4242/api/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "name": "weekly-dependency-check",
    "description": "Check for outdated npm dependencies",
    "prompt": "Check for outdated npm dependencies and create a summary of what needs updating.",
    "target": "global",
    "cron": "0 9 * * 1",
    "timezone": "America/New_York"
  }'

target is either an agent id (the task runs in that agent's project directory) or the literal string "global" (runs in the server's default working directory). description and prompt are required; cron, timezone, maxRuntime, permissionMode, runtime, model, effort, and reason are optional here. On a PATCH, sending null for runtime, model or effort clears it, so the task goes back to following its agent. Leave permissionMode out and the run starts at the level you chose for new chats, worked out for the runtime this task resolves to. If you never chose one, it starts where scheduled runs have always started: able to edit files, but stopping for anything riskier. There is one exception to the optional list: a caller creating a scheduled task it can't approve on its own (an agent identity or an approval token, rather than you at the keyboard) must send a reason, or the request is rejected with a 400. It then parks at pending_approval with the reason attached, the same as one proposed through the MCP tool below.

Pause or resume:

curl -X PATCH http://localhost:4242/api/tasks/{id} \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

Run one outside its cron timing:

curl -X POST http://localhost:4242/api/tasks/{id}/trigger

Running one on demand is yours to decide, so this call answers 403 for a caller that identifies itself as an agent or presents an approval token. That is the same bar that decides who may set permissionMode or status. You can trigger any scheduled task, including one still parked at pending_approval: running a proposal once is how you find out what it does before you approve it.

Cancel an active run:

curl -X POST http://localhost:4242/api/tasks/runs/{runId}/cancel

List available templates:

curl http://localhost:4242/api/tasks/templates

MCP Tools

Agents can propose scheduled tasks for themselves using the tasks_create MCP tool.

tasks_create({
  name: "nightly-test-suite",
  description: "Run the full test suite overnight",
  prompt: "Run the full test suite and report any failures.",
  target: "global",
  cron: "0 2 * * *",
  reason: "Catches regressions before the day starts, without anyone waiting on it interactively."
})

A scheduled task an agent creates for itself enters the pending_approval state and won't run until a human approves it. This stops an agent from quietly scheduling recurring work you never asked for. reason is required: it's the whole reason to make the task up front, in the agent's own words, since it's the only thing the person deciding whether to approve it has to go on. The approval card also shows who proposed it and the next few times it would actually run.

Cron Syntax

DorkOS uses standard five-field cron expressions:

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *

Prop

Type

For help building cron expressions, the visual builder in the UI is the fastest path. You can also reference crontab.guru for syntax validation.

Run States

Prop

Type

Click any run in the history to open the full agent conversation, every tool call, response, and output the agent produced during that run.

DorkOS enforces a configurable concurrency cap on simultaneous runs (4 by default, and anything from 1 to 10 in Settings). If the cap is reached, new triggers are skipped with a warning log. Overrun protection (via croner's protect option) stops a scheduled task from starting a new run while its previous run is still active.

Schedule States

Prop

Type

To pause a scheduled task yourself, switch it off. That is saved in the skill file, so it sticks. paused is DorkOS telling you something is missing, and it is not something you can set.

Scheduled tasks + Relay

When both scheduled tasks and Relay are enabled, a run on Claude Code gets dispatched as a Relay message (relay.system.tasks.{scheduleId}) instead of calling the agent runtime directly. A run on Codex or OpenCode calls its runtime directly for now; Relay grows adapters for those next. Multi-agent coordination through Relay is shipped but still working toward full end-to-end verification, so treat this integration as functional, not battle-tested. In practice it means:

  • Each run gets a Relay trace ID, so you can follow the delivery path from trigger to agent execution.
  • Runs share Relay's delivery machinery (retries, backpressure handling, a dead-letter queue for messages that can't be delivered) with every other message on the bus.

When Relay is disabled, DorkOS falls back to calling the agent runtime directly. Scheduled tasks still work the same way, you just don't get the trace ID or shared delivery metrics.

Storage

The skill files are the source of truth. Their derived rows and the run history live in SQLite at ~/.dork/dork.db, using WAL mode so reads and writes don't block each other.

Two guarantees hold even if more than one DorkOS server points at the same ~/.dork:

  • Single firer. Only one process fires schedules at a time; others display them but stay quiet. If the firing process exits, another takes over within seconds.
  • Fire-once. A given scheduled occurrence dispatches at most once, even across processes, so a shared data directory can never double-run a job. Manual "trigger" calls are exempt and always run.

Next Steps