# Task Scheduler
Source: https://dorkos.ai/docs/guides/task-scheduler

Schedule agents to run on a timer, even with your laptop closed





# Task Scheduler [#task-scheduler]

<ProductShot id="tasks" alt="The DorkOS Tasks page showing scheduled agent runs with their timers and a run history of green checks" />

Tasks lets you schedule an agent to run automatically, 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, even after you close your laptop.

Tasks is on by default. Open the **Tasks** tab in the sidebar and you're ready to create your first schedule.

<Callout type="info">
  Don't see a Tasks tab? Someone turned it off. Run `dorkos --tasks`, or see [Enabling or disabling
  Tasks](#enabling-or-disabling-tasks) below.
</Callout>

## Create your first schedule [#create-your-first-schedule]

<Steps>
  <Step>
    ### Open the Tasks tab [#open-the-tasks-tab]

    It's in the sidebar. If you have no schedules 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).
  </Step>

  <Step>
    ### Pick a template or start from scratch [#pick-a-template-or-start-from-scratch]

    Click a template card to pre-fill a schedule 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 schedule.
    * **Prompt**: the instruction the agent gets each time the job runs, e.g. "Check for outdated npm dependencies and summarize what needs updating."
    * **Cron Expression** and **Timezone** (under "Schedule"): when the job runs. 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](#cron-syntax) has the full pattern if you're curious).
    * **Permission Mode** and **Max Runtime** (under "Advanced settings"): how much autonomy the agent gets and how long it's allowed to run before DorkOS stops it.
  </Step>

  <Step>
    ### Save it [#save-it]

    Your schedule shows up in the Tasks tab immediately, along with its next run time. Every run it makes lands in the run history, so you can check what happened without digging through logs.
  </Step>
</Steps>

## Will it actually run? [#will-it-actually-run]

Short answer: yes, once it's live in a real DorkOS install. Schedules always show up and you can always edit them, but a schedule 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: a scheduled 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 schedules fire. Nothing extra to do.

## Get a message when a task finishes [#get-a-message-when-a-task-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 **Channels**, and connect a channel like Telegram.
2. Bind the channel and open its **Advanced** settings.
3. Turn on **Message me when 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.

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

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

## Enabling or disabling Tasks [#enabling-or-disabling-tasks]

Tasks ships on by default, so most people never need to touch this. If someone turned it off, or you want to force it on or off for a specific run:

```bash
dorkos --tasks
```

```bash
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 [#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.

### REST API [#rest-api]

Create a schedule:

```bash
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 schedule 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`, and `permissionMode` are optional.

Pause or resume a schedule:

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

Trigger a schedule outside its cron timing:

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

Cancel an active run:

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

List available templates:

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

### MCP Tools [#mcp-tools]

Agents can create schedules 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 * * *"
})
```

<Callout type="warn">
  Schedules an agent creates for itself enter the `pending_approval` state and won't run until a
  human approves them. This stops an agent from quietly scheduling recurring work you never asked
  for.
</Callout>

### Cron Syntax [#cron-syntax]

Tasks 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)
│ │ │ │ │
* * * * *
```

<TypeTable
  type="{
  '*/5 * * * *': { type: 'preset', description: 'Every 5 minutes' },
  '*/15 * * * *': { type: 'preset', description: 'Every 15 minutes' },
  '0 * * * *': { type: 'preset', description: 'Every hour on the hour' },
  '0 */6 * * *': { type: 'preset', description: 'Every 6 hours' },
  '0 0 * * *': { type: 'preset', description: 'Daily at midnight' },
  '0 9 * * *': { type: 'preset', description: 'Daily at 9:00 AM' },
  '0 9 * * 1-5': { type: 'preset', description: 'Weekdays at 9:00 AM' },
  '0 9 * * 1': { type: 'preset', description: 'Every Monday at 9:00 AM' },
  '0 9 1 * *': { type: 'preset', description: 'First day of every month at 9:00 AM' },
}"
/>

<Callout type="info">
  For help building cron expressions, the visual builder in the UI is the fastest path. You can also
  reference [crontab.guru](https://crontab.guru) for syntax validation.
</Callout>

### Run States [#run-states]

<TypeTable
  type="{
  running: { type: 'status', description: 'The agent session is currently executing' },
  completed: { type: 'status', description: 'The agent completed the task without errors' },
  failed: { type: 'status', description: 'The agent encountered an error during execution' },
  cancelled: { type: 'status', description: 'The run was manually cancelled' },
}"
/>

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

Tasks enforces a configurable concurrency cap on simultaneous runs (1 by default, configurable up 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 schedule from starting a new run while its previous run is still active.

### Schedule States [#schedule-states]

<TypeTable
  type="{
  active: { type: 'state', description: 'The schedule is running on its cron timing' },
  paused: {
    type: 'state',
    description: 'The schedule is temporarily paused and will not trigger',
  },
  pending_approval: {
    type: 'state',
    description: 'The schedule was created by an agent and awaits human approval',
  },
}"
/>

### Tasks + Relay [#tasks--relay]

When both Tasks and [Relay](/docs/guides/relay-messaging) are enabled, a scheduled run gets dispatched as a Relay message (`relay.system.tasks.{scheduleId}`) instead of calling the agent runtime directly. 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 scheduled run gets a Relay trace ID, so you can follow the delivery path from trigger to agent execution.
* Scheduled 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.

<Callout type="info">
  When Relay is disabled, Tasks falls back to calling the agent runtime directly. Schedules still
  work the same way, you just don't get the trace ID or shared delivery metrics.
</Callout>

### Storage [#storage]

Schedule definitions and 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 schedules 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 [#next-steps]

<Cards>
  <Card title="Relay Messaging" href="/docs/guides/relay-messaging">
    How Tasks integrates with the Relay messaging layer.
  </Card>

  <Card title="CLI Usage" href="/docs/guides/cli-usage">
    See the --tasks and --no-tasks CLI flags.
  </Card>

  <Card title="Agent Coordination" href="/docs/guides/agent-coordination">
    Multi-agent workflow patterns for scheduled and interactive agents.
  </Card>
</Cards>
