What is a scheduled task?
A scheduled task is:- A prompt that runs on a schedule (cron, interval, or one-time)
- Executed in the context of a specific group
- Has access to all agent tools (Bash, browser, MCP, etc.)
- Can send messages to the group chat or complete silently
- Tracked in the database with run history
Tasks are essentially automated agent invocations. They run the same Claude Agent SDK as interactive messages, just triggered by time instead of user input.
Schedule types
Three schedule types are supported:Cron expressions
Standard cron syntax with timezone support:0 9 * * *- Every day at 9:00 AM0 */2 * * *- Every 2 hours0 0 * * 1- Every Monday at midnight30 14 1 * *- 2:30 PM on the 1st of each month
- Defaults to system timezone (
process.env.TZorIntl.DateTimeFormat().resolvedOptions().timeZone) - Configurable via
TZenvironment variable - Uses
cron-parserwith timezone support
Cron expressions are evaluated in the configured timezone, not UTC. This ensures tasks run at the expected local time even across daylight saving changes.
Interval
Repeat every N milliseconds:3600000- Every hour (3600 * 1000 ms)86400000- Every day (24 * 60 * 60 * 1000 ms)60000- Every minute
One-time
Run once at a specific ISO 8601 timestamp:2026-03-01T14:30:00Z- March 1st, 2026 at 2:30 PM UTC2026-02-28T09:00:00-08:00- Feb 28th, 2026 at 9 AM Pacific
next_runset tonull- Task status set to
completed - Will not run again unless
next_runis manually updated and status reset toactive
Task lifecycle
Creation
- Agent calls
schedule_taskMCP tool (or user creates via IPC) - Task inserted into database with status
active next_runcalculated based on schedule type- Task becomes eligible for execution when
next_run <= NOW()
Execution
Execution flow:- Scheduler polls database every 60 seconds (
SCHEDULER_POLL_INTERVAL) - Finds tasks where
next_run <= NOW()andstatus = 'active' - Re-checks status (in case task was paused between poll and execution)
- Enqueues task in GroupQueue
- GroupQueue respects concurrency limits (tasks and messages share the pool)
- Container spawned with
isScheduledTask: trueflag - Agent executes task prompt
- Results automatically forwarded to the group chat when the agent produces output
- Run logged to
task_run_logstable with duration and result next_runrecalculated based on schedule type- Container closes after 10-second grace period
Tasks respect the same concurrency limits as interactive messages. If all 5 container slots are busy, tasks wait in queue.
Post-execution
After a task completes:- Run logged: Duration, result summary, error (if any) written to
task_run_logstable - Next run calculated:
- Cron: Next matching time according to cron expression
- Interval: Scheduled time + interval milliseconds (anchored to prevent drift)
- Once: Set to
null
- Last result updated: First 200 chars of result stored in
tasks.last_result - Container closes: 10-second grace period, then stdin closed (container exits)
Completion
Task containers close automatically after producing output:- Tasks are single-turn (no follow-up messages)
- Grace period allows final MCP calls to complete
- Much faster than idle timeout (30 minutes for interactive sessions)
- Prevents resource waste from long-lived task containers
Task context modes
Tasks can run in two context modes:Isolated context (default)
- Fresh Claude session for each run
- No conversation history from previous runs
- No conversation history from group chat
- Stateless execution (each run is independent)
- Status checks that don’t need history
- Periodic data fetching
- Health monitoring
- Any task that should start fresh each time
Group context
- Uses the group’s current Claude session
- Has access to conversation history
- Sees previous task runs in same group context
- Can reference files and context from interactive messages
- Reminders that need conversation context
- Tasks that build on previous interactions
- Context-aware notifications
- Any task that should feel like part of the conversation
Group context tasks share the session with interactive messages. This means the task’s actions (files read, tools used) become part of the group’s conversation history.
Task management operations
Tasks are managed via MCP tools (available incontainer/skills/nanoclaw.md):
schedule_task
Create a new task:list_tasks
View tasks (filtered by group):schedule_task, pause_task, resume_task, cancel_task, update_task), so list_tasks always reflects the latest state — even within the same agent session that made the change.
pause_task
Temporarily disable a task:resume_task
Re-enable a paused task:update_task
Modify an existing task’s prompt or schedule:cancel_task
Permanently delete a task:Sending messages from tasks
Tasks can send messages to their group chat using thesend_message tool:
- Tasks can only send to their own group’s chat
- Same IPC authorization as interactive messages
- Main group tasks can send to any chat
- Non-main group tasks limited to own chat
send_message, it completes silently:
- Result logged to database
- No message sent to chat
- Useful for background data collection or status checks
Task results are always logged to the database, whether or not they send a message. Check
task_run_logs table for execution history.Task run history
All task executions are logged totask_run_logs table:
id column is an auto-incrementing integer primary key in the database.
Querying history:
Group privileges for tasks
| Operation | Main Group | Non-Main Group |
|---|---|---|
| Schedule task for self | ✓ | ✓ |
| Schedule task for others | ✓ | ✗ |
| View all tasks | ✓ | Own only |
| Pause/resume own tasks | ✓ | ✓ |
| Pause/resume others’ tasks | ✓ | ✗ |
| Cancel own tasks | ✓ | ✓ |
| Cancel others’ tasks | ✓ | ✗ |
| Send message to own chat | ✓ | ✓ |
| Send message to other chats | ✓ | ✗ |
Task privileges match the group’s general privilege model. Main group can manage all tasks, non-main groups can only manage their own.
Task scheduling best practices
- Use cron for wall-clock times: “Every day at 9 AM” should be cron, not interval
- Use interval for frequency-based: “Every 5 minutes” should be interval, not cron
- Start with isolated context: Add group context only if needed
- Include error handling: Tasks should handle failures gracefully
- Use descriptive prompts: “Check website uptime” not “check status”
- Monitor task_run_logs: Failed tasks may indicate issues
- Avoid very short intervals: Respect container startup overhead (minimum ~5s)
- Clean up completed one-time tasks: Cancel or pause them to reduce clutter
Common patterns
Daily summary task
Health monitoring
One-time reminder
Background data collection
Error handling
Task errors are logged but don’t stop the schedule:- Task fails during execution
- Error logged to
task_run_logswithstatus: 'error' last_resultupdated with error summarynext_runstill calculated (task will retry on next schedule)- No message sent to chat (unless task explicitly sends before error)
- Check
task_run_logsfor error messages - Review container logs at
groups/{folder}/logs/ - Pause the task to stop the retry loop
- Fix the underlying issue (permissions, network, etc.)
- Resume the task