---
title: scheduler - Scheduler
description: Create and manage scheduled tasks
---

Create and manage dynamic scheduled tasks with flexible scheduling and execution modes.

## Dependencies

| Dependency | Install Command |
| --- | --- |
| `croniter` ≥ 2.0.0 | `pip install croniter>=2.0.0` |

Included in core dependencies: `pip3 install -r requirements.txt`

## Scheduling Modes

| Mode | Description |
| --- | --- |
| One-time | Execute once at a specified time |
| Fixed interval | Repeat at fixed time intervals |
| Cron expression | Define complex schedules using Cron syntax |

## Execution Modes

- **Fixed message**: Send a preset message when triggered
- **Agent dynamic task**: Agent intelligently executes the task when triggered

## Usage

Create and manage scheduled tasks with natural language:

- "Send me a weather report every morning at 9 AM"
- "Check server status every 2 hours"
- "Remind me about the meeting tomorrow at 3 PM"
- "Show all scheduled tasks"

## Test-run an existing task

Open the task in the authenticated Web console or Desktop app and click **Run
now**. After you confirm the delivery, CowAgent queues one immediate execution
to the task's configured channel and receiver. This user-initiated action is not
exposed to the agent's scheduler tool.

Manual execution works for disabled tasks and does not enable, delete, or
reschedule the task. Its original `next_run_at` remains unchanged. A task cannot
be run manually while the same task is already executing on schedule.

<Frame>
  <img src="https://cdn.link-ai.tech/doc/20260202195402.png" width="800" />
</Frame>

## Results injected into the conversation

Scheduled tasks run inside an isolated session (so internal planning and tool calls do not pollute the user's chat), but the **final output** is written back to the user's real session as a message pair. You can directly follow up — e.g. "expand on point 2 from earlier".

**Default policy**

- Output of Agent dynamic tasks is injected into the conversation
- Fixed-message tasks are not injected by default (configurable)
- Each session keeps the most recent **3 pairs** of scheduler messages; older pairs are pruned automatically. Regular user messages are unaffected

**Configuration**

| Key | Default | Description |
| --- | --- | --- |
| `scheduler_inject_to_session` | `true` | Master switch |
| `scheduler_inject_max_per_session` | `3` | Max scheduler message pairs kept per session |
| `scheduler_inject_send_message` | `false` | Whether to also inject fixed-message tasks |

```json
{
  "scheduler_inject_to_session": true,
  "scheduler_inject_max_per_session": 3,
  "scheduler_inject_send_message": false
}
```

## Context inside scheduled task execution

The isolated session for scheduled tasks retains a few recent runs of conversation history, so you can naturally do "compare with last time" or "continue from previous conclusion". To prevent prompts from growing unbounded for high-frequency tasks (e.g. a 5-minute monitor), history is auto-trimmed:

```
scheduler_keep_turns = max(1, agent_max_context_turns / 5)
```

`agent_max_context_turns` defaults to `20`, so each scheduled run keeps the most recent **4 turns** of history by default. Increase `agent_max_context_turns` if you need longer memory.

<Note>
For group-chat scenarios (Feishu / WeCom group bots / DingTalk, etc.), the user's real `session_id` looks like `user_id:group_id` — different from `receiver`. Scheduler records the correct `session_id` when a task is created. For older `tasks.json` entries missing this field, the runtime falls back to `receiver`, matching legacy behavior.
</Note>
