Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nanoclaw.dev/llms.txt

Use this file to discover all available pages before exploring further.

The task scheduler enables automated execution of agent prompts on a schedule. In v2, tasks are stored as messages_in rows with kind='task' — there is no separate task table. Task operations flow through the MCP tool / delivery action pipeline.

Task model

Tasks in v2 are messages_in rows in inbound.db with:
  • kind='task'
  • process_after — ISO timestamp for when the task should run
  • recurrence — optional cron expression for recurring tasks
  • series_id — links all occurrences of a recurring task

MCP tools (container-side)

Tasks are managed via MCP tools inside the container. Each tool writes a kind='system' outbound message that the host’s delivery pipeline routes to the appropriate handler.

schedule_task

Creates a new task:
// Agent writes to outbound.db
{
  action: 'schedule_task',
  prompt: 'Check server status',
  process_after: '2026-03-01T09:00:00Z',
  recurrence: '0 */6 * * *',  // Optional cron expression
  script: '...',               // Optional pre-execution script
}
The host creates a kind='task' row in inbound.db with the specified process_after and recurrence. A series_id is set to the task’s own ID.

cancel_task

Marks all live rows in the task’s series as completed and nulls the recurrence:
{ action: 'cancel_task', task_id: 'abc123' }

pause_task

Toggles a pending task to paused status:
{ action: 'pause_task', task_id: 'abc123' }

resume_task

Toggles a paused task back to pending status:
{ action: 'resume_task', task_id: 'abc123' }

update_task

Merges content updates in-place. Matches by ID or series_id:
{
  action: 'update_task',
  task_id: 'abc123',
  prompt: 'Updated prompt',
  process_after: '2026-03-01T10:00:00Z',
  recurrence: '0 */12 * * *',
}
update_task returns 0 when no live row matches, triggering a system notification back to the agent (“no live task matched”).

Host-side processing

Host sweep

The host sweep (60s interval) handles task lifecycle:
  1. Due-message wake — finds tasks where process_after <= now and wakes containers
  2. Processing_ack sync — reads acknowledgments from outbound.db to mark tasks completed
  3. Recurrence advancementgetCompletedRecurring() finds completed rows with non-null recurrence; insertRecurrence() creates the next-run row

Sequence numbers

All host-written messages (including tasks) use even-parity sequence numbers via nextEvenSeq(). Container-written messages use odd parity. This prevents sequence number collisions.

Recurring task series

Each recurring task occurrence gets a new messages_in row:
  • All rows in a series share the same series_id
  • When a recurring task completes, the host creates a new pending row with the next process_after
  • cancel_task marks all live rows in the series as completed and nulls recurrence
  • update_task matches by series_id to hit the live next-occurrence row

Schedule types

Cron (via recurrence)

recurrence: '0 */6 * * *'  // Cron expression
Uses cron-parser with the configured TIMEZONE environment variable.

One-time (no recurrence)

process_after: '2026-03-01T14:30:00Z'
recurrence: null
Runs once when process_after is reached. After completion, no new row is created.

Task scripts

When a task has a script field, the agent-runner executes it before invoking the agent:
  1. Script runs with a 30-second timeout
  2. Script outputs JSON: { "wakeAgent": true/false, "data": {...} }
  3. If wakeAgent is false, the task completes silently
  4. If wakeAgent is true, the agent is invoked with script data

Script contract

interface ScriptResult {
  wakeAgent: boolean;
  data?: unknown;
}

Example

{
  "action": "schedule_task",
  "prompt": "Summarize new issues",
  "script": "curl -s https://api.github.com/repos/org/repo/issues?state=open | jq '{wakeAgent: (length > 0), data: .}'",
  "recurrence": "0 */1 * * *"
}
Scripts have a 30-second timeout and 1 MB output limit. For tasks running more than roughly twice a day, always include a script to minimize agent wake-ups.

Configuration

// Timezone for cron expressions (validated IANA identifier; falls back to UTC)
export const TIMEZONE = resolveConfigTimezone();
The timezone is resolved from process.env.TZ, then .env file, then system default, with IANA validation.
Last modified on April 22, 2026