> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcbot.buzzchat.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Scheduling & Automation

> Task scheduling, heartbeat automation, and event-driven polling

# Scheduling & Automation

OrcBot provides three scheduling mechanisms: one-time task scheduling, recurring heartbeat tasks, and event-driven polling. Together, these enable fully autonomous operation.

## schedule\_task

Schedule a one-time task for future execution.

### Parameters

<ParamField path="time_or_cron" type="string" required>
  When to run the task. Supports:

  * Relative time: `"in 2 hours"`, `"in 30 minutes"`, `"in 1 day"`
  * Absolute time: `"2025-01-15T14:30:00Z"` (ISO 8601)
  * Cron expression: `"0 9 * * 1-5"` (weekdays at 9 AM)
</ParamField>

<ParamField path="task_description" type="string" required>
  Natural language task description
</ParamField>

### Return Value

<ResponseField name="result" type="string">
  Confirmation with scheduled time and task ID
</ResponseField>

### Relative Time Parsing

Supported formats:

* `"in N minutes"` - N minutes from now
* `"in N hours"` - N hours from now
* `"in N days"` - N days from now
* `"in N weeks"` - N weeks from now

### Cron Expressions

Standard cron format:

```
* * * * *
│ │ │ │ │
│ │ │ │ └─ Day of week (0-7, 0=Sunday)
│ │ │ └─── Month (1-12)
│ │ └───── Day of month (1-31)
│ └─────── Hour (0-23)
└───────── Minute (0-59)
```

### Example Usage

**Relative time:**

```json theme={null}
{
  "skill": "schedule_task",
  "args": {
    "time_or_cron": "in 2 hours",
    "task_description": "Send daily report to team via Telegram"
  }
}
```

**Absolute time:**

```json theme={null}
{
  "skill": "schedule_task",
  "args": {
    "time_or_cron": "2025-01-15T14:30:00Z",
    "task_description": "Deploy production release"
  }
}
```

**Cron expression:**

```json theme={null}
{
  "skill": "schedule_task",
  "args": {
    "time_or_cron": "0 9 * * 1-5",
    "task_description": "Morning standup reminder (weekdays at 9 AM)"
  }
}
```

### Response Example

```
Task scheduled for 2025-01-15T14:30:00Z (in 2 hours).
Task ID: scheduled-task-1736954400000
Description: Send daily report to team via Telegram
```

### Task Metadata

Scheduled tasks are stored in `scheduled-tasks.json` with:

* **id**: Unique task identifier
* **cronExpression**: Cron pattern
* **description**: Task description
* **nextRun**: Next execution timestamp
* **createdAt**: Creation timestamp

### Canceling Tasks

Scheduled tasks can be canceled by modifying `scheduled-tasks.json` manually (future skill planned).

### Metadata

* **isDeep**: `false`
* **isDangerous**: `false`

<Tip>
  **Use `schedule_task` for one-time future tasks.** For recurring automation, use `heartbeat_schedule` instead.
</Tip>

## heartbeat\_schedule

Schedule a recurring autonomous task.

### Parameters

<ParamField path="cronExpression" type="string" required>
  Cron expression for recurrence (see format above)
</ParamField>

<ParamField path="task_description" type="string" required>
  What the agent should do on each execution
</ParamField>

### Return Value

<ResponseField name="result" type="string">
  Confirmation with next run time and schedule ID
</ResponseField>

### Heartbeat vs Autonomy

**Heartbeat tasks:**

* Triggered by cron schedule
* Task-specific and focused
* Runs even when queue is empty
* Survives restarts (persisted to `heartbeat-schedules.json`)

**Autonomy mode:**

* Triggered by interval timer
* Context-aware and exploratory
* Only runs when idle
* Governed by `autonomyEnabled` config

### Example Usage

**Daily report:**

```json theme={null}
{
  "skill": "heartbeat_schedule",
  "args": {
    "cronExpression": "0 18 * * 1-5",
    "task_description": "Generate daily work summary and send to Frederick via Telegram"
  }
}
```

**Hourly check:**

```json theme={null}
{
  "skill": "heartbeat_schedule",
  "args": {
    "cronExpression": "0 * * * *",
    "task_description": "Check server health and alert if CPU >90%"
  }
}
```

**Weekly backup:**

```json theme={null}
{
  "skill": "heartbeat_schedule",
  "args": {
    "cronExpression": "0 2 * * 0",
    "task_description": "Backup project files to cloud storage"
  }
}
```

**Every 15 minutes:**

```json theme={null}
{
  "skill": "heartbeat_schedule",
  "args": {
    "cronExpression": "*/15 * * * *",
    "task_description": "Check for new GitHub pull requests and notify team"
  }
}
```

### Response Example

```
Heartbeat schedule created:
Cron: 0 18 * * 1-5 (weekdays at 6 PM)
Task: Generate daily work summary and send to Frederick via Telegram
Next run: 2025-01-15T18:00:00Z
Schedule ID: heartbeat-1736954400000
```

### Persistence

Heartbeat schedules are saved to `heartbeat-schedules.json` and survive agent restarts.

### Smart Heartbeat Features

**Exponential Backoff:**

When heartbeat tasks are unproductive (no meaningful work done), the interval automatically increases:

* First idle: 2x interval
* Second idle: 4x interval
* Third idle: 8x interval
* Max: 16x original interval

Productivity resets the interval to baseline.

**Productivity Tracking:**

The system tracks whether heartbeat tasks result in:

* User-visible messages sent
* Files created
* Commands executed
* Research completed

Unproductive tasks (e.g., "nothing to do") trigger backoff.

**Context-Aware Execution:**

Heartbeat tasks have access to:

* Recent conversation context
* User preferences from USER.md
* Past actions from memory
* Current time and date

### Metadata

* **isDeep**: `false`
* **isDangerous**: `false`

<Warning>
  **Heartbeat tasks run autonomously.** Ensure they have clear success criteria and don't spam users. Use `autonomyAllowedChannels` to control which channels receive proactive messages.
</Warning>

## Polling System

Event-driven condition monitoring without busy-waiting loops.

### Architecture

The polling system provides:

* **Condition checking**: Evaluate a condition function repeatedly
* **Success/failure callbacks**: Trigger actions when condition met
* **Timeout handling**: Maximum wait time before giving up
* **Interval control**: How often to check the condition
* **Event bus integration**: Emits events for monitoring

### Creating a Poll

Polls are created programmatically (not via a skill). Example:

```typescript theme={null}
import { PollingManager } from './core/PollingManager';

const pollingManager = new PollingManager();

const pollId = pollingManager.createPoll({
  condition: async () => {
    // Check if file exists
    return fs.existsSync('/tmp/deployment-complete.flag');
  },
  onSuccess: async () => {
    console.log('Deployment complete!');
    // Send notification
  },
  onFailure: async () => {
    console.log('Deployment timed out');
    // Send alert
  },
  intervalMs: 5000, // Check every 5 seconds
  timeoutMs: 300000, // Give up after 5 minutes
  metadata: { task: 'deployment-watch' }
});

// Later: cancel if needed
pollingManager.cancelPoll(pollId);
```

### Use Cases

**Wait for file creation:**

```typescript theme={null}
condition: async () => fs.existsSync('/tmp/report.pdf')
```

**Wait for API response:**

```typescript theme={null}
condition: async () => {
  const res = await fetch('https://api.example.com/status');
  const data = await res.json();
  return data.status === 'complete';
}
```

**Wait for process completion:**

```typescript theme={null}
condition: async () => {
  const { stdout } = await exec('ps aux | grep deploy');
  return !stdout.includes('deploy-script');
}
```

### Event Bus Events

```typescript theme={null}
eventBus.on('poll:created', (pollId, config) => { /* ... */ });
eventBus.on('poll:checked', (pollId, result) => { /* ... */ });
eventBus.on('poll:success', (pollId) => { /* ... */ });
eventBus.on('poll:timeout', (pollId) => { /* ... */ });
eventBus.on('poll:cancelled', (pollId) => { /* ... */ });
```

### Best Practices

<Tip>
  **Efficient polling intervals:**

  * Fast events (1-10s): 1-2 second intervals
  * Medium events (1-5min): 5-10 second intervals
  * Slow events (>5min): 30-60 second intervals
</Tip>

<Warning>
  **Set reasonable timeouts.** Polls consume memory until they complete or time out. Always set a maximum wait time.
</Warning>

## Common Workflows

### Deployment Automation

```typescript theme={null}
// 1. Schedule deployment
schedule_task("2025-01-15T18:00:00Z", "Deploy production release")

// 2. In deployment task:
run_command("./deploy.sh")

// 3. Create poll to wait for completion
pollingManager.createPoll({
  condition: async () => fs.existsSync('/tmp/deploy-complete'),
  onSuccess: async () => {
    send_telegram(teamChatId, "Deployment successful! ✅")
  },
  intervalMs: 5000,
  timeoutMs: 600000 // 10 minutes
})
```

### Daily Reports

```typescript theme={null}
// Create heartbeat for daily summary
heartbeat_schedule("0 18 * * 1-5", 
  "Search chat history for today's conversations, generate summary, send to Frederick"
)

// Heartbeat task execution:
// 1. search_chat_history(jid, query="", daysAgo=1)
// 2. generate report with LLM
// 3. send_telegram(chatId, report)
```

### Monitoring Integration

```typescript theme={null}
// Check server health every hour
heartbeat_schedule("0 * * * *", "Check server metrics and alert if abnormal")

// Implementation:
// 1. http_fetch("https://monitoring.example.com/api/metrics")
// 2. Analyze response
// 3. If CPU >90% or memory >85%: send_telegram(adminChatId, "Alert: High resource usage")
```

### Reminder System

```typescript theme={null}
// User: "Remind me to call Alice in 2 hours"
schedule_task("in 2 hours", "Send reminder to call Alice")

// At execution time:
send_telegram(userChatId, "⏰ Reminder: Call Alice")
```

## Configuration

### Autonomy Settings

```yaml theme={null}
# Enable autonomous heartbeat
autonomyEnabled: true

# Base interval between heartbeats (milliseconds)
autonomyInterval: 300000 # 5 minutes

# Maximum backlog before pausing autonomy
autonomyBacklogLimit: 5

# Channels where autonomy can send proactive messages
autonomyAllowedChannels:
  - telegram
  - discord
```

### Heartbeat Backoff

```yaml theme={null}
# Consecutive idle heartbeats before backoff
heartbeatIdleThreshold: 3

# Maximum backoff multiplier
heartbeatMaxBackoff: 16
```

### Polling Defaults

```yaml theme={null}
# Default polling interval (milliseconds)
pollingDefaultInterval: 5000

# Default polling timeout (milliseconds)
pollingDefaultTimeout: 300000
```

## Best Practices

<Tip>
  **Scheduling strategy:**

  1. Use `schedule_task` for one-time future actions
  2. Use `heartbeat_schedule` for recurring autonomous work
  3. Use polling for waiting on external events
  4. Combine all three for complex workflows
</Tip>

<Warning>
  **Avoid heartbeat spam:**

  * Set realistic cron intervals (not every minute unless necessary)
  * Use specific task descriptions so the agent knows when to skip
  * Configure `autonomyAllowedChannels` to control where messages go
  * Monitor productivity metrics to detect noisy tasks
</Warning>

<Note>
  **Heartbeat tasks have full skill access.** They can search the web, read files, send messages, and execute commands just like user-initiated tasks.
</Note>

## Troubleshooting

### "Heartbeat not triggering"

* **Cause**: Cron expression invalid or agent not running
* **Fix**: Validate cron with [https://crontab.guru/](https://crontab.guru/), check daemon status

### "Polling timed out"

* **Cause**: Condition never became true within timeout
* **Fix**: Increase timeout or check condition logic

### "Autonomy paused"

* **Cause**: Backlog limit reached
* **Fix**: Process pending tasks or increase `autonomyBacklogLimit`

### "Scheduled task not executing"

* **Cause**: Task ID collision or scheduler not started
* **Fix**: Check `scheduled-tasks.json` for duplicates, restart agent

## Related Skills

<CardGroup cols={2}>
  <Card title="Memory" icon="brain" href="/api/skills/memory">
    Store context for autonomous tasks
  </Card>

  <Card title="Orchestration" icon="sitemap" href="/api/skills/orchestration">
    Spawn agents for parallel scheduled work
  </Card>
</CardGroup>
