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

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
runtime, model and effort are newer, 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.
account picks whose Claude plan pays. If you have more than one Claude
account set up in DorkOS, a schedule can name the one its runs use, for example
to keep a client's nightly job on that client's plan. An id that is no longer set
up doesn't stop the run: it runs on the usual account, and the Activity feed
says so. A schedule that remembers its last run stays on the account it
started on, so DorkOS refuses to change it once it has run. Turn off
"Remember the last run" first.
Clearing a field puts the task back to following its agent. In the app, that is the first option in each menu: "Same as agent", "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 within seconds of you saving them, so you never restart anything — including the first one you put in a folder you have only just made.
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.
What runs without asking
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 and how it runs: its prompt, its timing (the timezone included), its name, the runtime, model and effort it runs with, the Claude account it runs on, its time limit, and whether it remembers earlier runs. Change any of those and it parks again for a fresh look. (A change you make yourself in DorkOS counts as your approval, so it keeps running, and so does a change one of your agents makes, unless the schedule came from a file or a package, or you chose Careful.) When an agent changes a schedule that came from a file or a package, or any schedule on Careful, the schedule stops in that same moment, before the new version can run, and the card says what changed, with the old and the new value side by side, for example Model: claude-sonnet-4 → claude-opus-4. Approve the same content twice, and it stays approved through every later sync. Its description and its on/off switch are not part of the approval.
A schedule that leaves its runtime, model or effort on "follow the agent" also depends on the agent's own settings. An agent can't change those through DorkOS without asking you first. It could still edit its settings file (.dork/agent.json) directly, and so could you, and DorkOS can't tell which of you did. So DorkOS checks before each run and every few minutes. When one of those settings was changed outside DorkOS, the change is recorded in Activity as Changed outside DorkOS, and every approved schedule from a file or a package that follows the agent for that setting waits for you again. On Careful, every approved schedule that follows it waits. Its card shows the change, for example Agent's model: claude-sonnet-4 → claude-opus-4. Changing the setting back doesn't restart the schedule: the card says it was changed, then changed back, and you approve it. A change you make in DorkOS, from Runs on or the agent's settings, never makes a schedule wait.
Anything you create yourself in DorkOS starts armed. Clicking save is the approval.
A schedule one of your agents makes starts armed too. You get a notification that names the agent, the task and when it runs, and Pause switches it off. The schedule keeps the agent's reason and the chat it came from, and Activity records it as scheduled by that agent. If you chose Careful in Permissions, it waits for your approval instead. A schedule that arrives over the external MCP connection always waits, because DorkOS can't tell that caller from someone outside.
Schedules that were already waiting for you when this changed stay waiting. Each one is a question to you, and DorkOS doesn't answer it for you.
Approving can also set how much it may do
A schedule you did not create yourself is held back to the careful setting, whatever the file or the agent asked for: it may edit files on its own and stops before anything riskier. That is deliberate — nothing an agent writes should be able to hand a job that runs at 3am more power than the agent has itself.
You can lift it, one job at a time, as you approve it. DorkOS looks at your own level in Control Center to work out what to offer: if it is higher than the one the job was held to, the approval card puts a second button beside the plain Approve naming that level — "Approve at Full autonomy", say. The card tells you what each one will run the job at.
What the button changes is the job's own Permissions setting, not your Control Center level and not anything about the next job. Approving at a higher level is a shortcut for opening the task afterwards and raising that setting by hand — the same dial, set at the moment you were already looking.
Because a job on a timer runs with nobody watching, giving it a level that never stops to ask puts one confirmation in front of you first, the same one you get when you choose that level anywhere else. Plain Approve asks nothing, because it changes nothing. And lifting one job never lifts the next one: the next schedule an agent proposes arrives held back exactly the same way.
One thing it cannot do: a schedule that came inside an installed package lives in that package's folder, which DorkOS will not write to. Approving it works; approving it at a higher level is turned down with a note saying why.
Changing when a package's schedule runs
You can still change when a package's schedule runs. Open it from the Schedules tab, choose Edit, and change the time or the timezone under Schedule. DorkOS keeps your timing itself, so the package's folder stays as it shipped and your choice survives the package's updates. The schedule stays approved, because you made the change.
The row then says Your timing. Open it to see the package's own timing, and choose Reset to the package's default to go back to it. If an agent changes when one of these schedules runs, the schedule stops and waits for you to approve it again.
What the schedule does, its instructions, its name and its settings, still belongs to the package, because the package's next update would put its own version back. The edit window says so as soon as you open it, and shows those fields without letting you change them. To change them, choose Make a copy: it opens a new schedule for the same agent with everything filled in, under the original's name with -copy on the end (or -copy-2 and so on, if that is taken). Change what you like and choose Create task. Switch off the package's schedule is ticked by default, so the two don't both run; untick it to keep both.
Schedules for an agent from the marketplace
You can make your own schedules for an agent you installed from the marketplace, the same way as for any other agent. DorkOS keeps them when the package updates. Two things are turned down, each with a note saying why:
- a name the package already uses for one of its own schedules, because its next update would put that schedule back; pick a different name;
- any new schedule for an agent whose package was installed by an older version of DorkOS, because DorkOS can't yet tell that package's files from yours. Choose Check files on the package in Marketplace's Installed tab (or run
dorkos marketplace check-files <package>), then try again.
If a later version of the package starts shipping a schedule with the same name as one of yours, the update keeps a copy of yours beside it (its file ends in .dork-old) and tells you. Yours stops running until you make it again under another name.
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 chat) 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.
Late and missed runs
A computer that is asleep cannot run anything. When it wakes, DorkOS runs the one scheduled time it missed most recently, if that time is still recent enough. That means under an hour ago, and less than halfway to the next scheduled time. So a daily 9:00 report still runs if you open the laptop at 9:40, but not at 11:00. A run less than a minute late always counts as on time.
The run history tells you what happened:
- Ran 40m late sits next to a run that started after its scheduled time.
- Skipped: this computer was asleep when it was due. marks a run that was too late to be worth doing. Nothing ran.
- Missed 3 earlier runs while asleep. counts the other scheduled times that came and went while the computer slept. DorkOS never runs those afterwards, so a night asleep never turns into a pile of runs at breakfast.
Times that pass while DorkOS itself is not running are not run later either, and are not counted.
When a run needs your permission
A task on a timer runs while you are somewhere else, so there is nobody to answer if the agent asks for permission to do something. DorkOS does not make it wait. The request is turned down right away, and the agent keeps going without that one tool.
You are told twice over. The run's own line in the run history names the tools it could not use, and each one lands in your activity feed on its own. Nothing pings your phone about it.
If every tool was turned down, the run is marked Blocked. That is its own outcome in the run history, next to Completed, Failed and Cancelled — not a green tick. It means the run happened, took time, and got nowhere: it was never given permission to do anything. Nothing broke, so there is nothing to debug; what it needs is the permission it was denied. A blocked run also reaches your notifications, because a schedule that quietly does nothing every night is the one thing you cannot spot for yourself.
A run that lost one tool and got on with the rest of its work still counts as Completed. It did what it could, and its summary line says what it skipped. So does a run that finished its work and only then asked you a question — being unable to reach you is not the same as being unable to act.
The agent knows this before it starts, so a well-written task tells you at the end what it skipped. If the same task keeps getting turned down, you have two ways to fix it: change the task so it does not need that tool, or open the task and raise its own Permissions setting, which is the dial that decides how much its runs may do on their own.
It has to be the task's own setting. A task's power is decided once, when the task is created, and stored on the task — so changing your Control Center level afterwards does not reach a task that already exists. That matters most for a task an agent proposed for you, which is created at the careful end of the dial and stays there until you move it.
There is one moment you can move it without opening the task: the approval itself. The card that asks you to approve an agent's proposal can also set the task's Permissions in the same click — see Approving can also set how much it may do. That still writes the task's own setting; it is only a quicker way to reach it.
Clicking Run now is different. You are watching, so its cards work normally and you can answer them.
This is only about requests that were waiting on you. A tool your agent is not allowed to use at all — because you wrote a rule against it, or because the safety check turned it down — is refused the same way it would be in any other chat, and raising the task's Permissions setting will not change that.
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:
- Open the agent, go to Connections, and add a connection like Telegram.
- Bind the connection and open its Advanced settings.
- Turn on Message me when scheduled tasks finish.
- Turn on Agent can message first. 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 chat 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 chat, 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 --tasksdorkos --no-tasksYou 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, account, and reason are optional here. On a PATCH, sending null for runtime, model, effort or account 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 that isn't you at the keyboard (an agent identity or an approval token) must send a reason, or the request is rejected with a 400. A registered agent's own token, on an install that isn't set to Careful, gets a schedule that runs right away. Any other such caller, and every caller on Careful, gets one that 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}/triggerRunning 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}/cancelList available templates:
curl http://localhost:4242/api/tasks/templatesMCP 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 runs right away, and you get a notification with Pause. If
you chose Careful, or the agent called over the external MCP connection, it enters the
pending_approval state and won't run until you approve it. reason is required either way: it
says, in the agent's own words, why the task should exist. The approval card shows it with who
proposed it and the next few times it would 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 chat, 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 support for those next. In practice, Claude Code runs dispatched through Relay:
- 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.