# Schedule

> Schedule management specialist for RECURRING/SCHEDULED tasks. Use when user wants to create, view, modify, or delete scheduled/cron jobs, timers, reminders, or periodic executions. Triggered by keywords: "schedule", "timer", "cron", "定时任务", "提醒", "定期", "周期", "每天", "每周", "recurring", "periodic".

- Skill: `hs3180/schedule` (Agent Skill)
- Install (CLI): `npx skillmds@latest add hs3180/schedule`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hs3180/schedule/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: hs3180 (https://skillmd.com/u/hs3180)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/hs3180/schedule

---


# Schedule Manager

Manage schedules with full CRUD operations.

## When to Use This Skill

**Use this skill for:**
- Creating scheduled/recurring tasks
- Setting up cron jobs
- Managing timers and reminders
- Periodic executions (daily, weekly, monthly, etc.)
- Viewing or modifying existing schedules

**DO NOT use this skill for:**
- One-time code changes → Ask the agent directly
- Bug fixes or feature implementations → Ask the agent directly
- Single execution operations → Ask the agent directly

**Keywords that trigger this skill**: "定时任务", "schedule", "cron", "timer", "reminder", "每天", "每周", "定期", "周期性", "recurring", "periodic"

## Core Principle

**ALWAYS send feedback to the user via the channel CLI `send_text` after EVERY operation.**

This is mandatory. Users must receive confirmation of operation results.

## Context Variables

When invoked, you receive:
- **Chat ID**: Feishu chat ID (from "**Chat ID:** xxx")
- **Message ID**: Message ID (from "**Message ID:** xxx")
- **Sender Open ID**: Sender's open ID (from "**Sender Open ID:** xxx")

**IMPORTANT**: Use `chatId` as schedule scope to ensure schedules only execute in the correct chat.

## Schedule File Location

Files stored in `workspace/schedules/` using **subdirectory layout** (mirroring the skills/ convention).

Each schedule lives in its own subdirectory:

```
workspace/schedules/<slug>/SCHEDULE.md
```

- `<slug>`: A short, descriptive, filesystem-safe name (lowercase, hyphens instead of spaces, no special characters)
- The file must be named exactly `SCHEDULE.md` (uppercase)

**IMPORTANT (Issue #3803)**: Schedule files MUST live in the **workspace** `schedules/` directory, NOT the current working directory's `schedules/`. When in project mode, the agent's cwd is the project directory, but schedules must still be written to the workspace directory.

To determine the workspace schedules directory, use:
```bash
echo "${DISCLAUDE_WORKSPACE_DIR:-$(pwd)}/schedules"
```

- If `DISCLAUDE_WORKSPACE_DIR` is set → use `$DISCLAUDE_WORKSPACE_DIR/schedules/`
- If not set → use `schedules/` relative to current directory

**Examples:**
- `$DISCLAUDE_WORKSPACE_DIR/schedules/daily-report/SCHEDULE.md`
- `$DISCLAUDE_WORKSPACE_DIR/schedules/issue-solver/SCHEDULE.md`
- `$DISCLAUDE_WORKSPACE_DIR/schedules/weekly-summary/SCHEDULE.md`

---

## CRUD Operations

### 1. Create Schedule

**Steps:**
1. Collect schedule info:
   - Name (short description)
   - Slug (filesystem-safe directory name, lowercase with hyphens)
   - Cron expression (cron format or natural language)
   - Content (prompt to execute)

2. Create directory and file:
   ```
   $DISCLAUDE_WORKSPACE_DIR/schedules/<slug>/SCHEDULE.md
   ```
   (Use `$DISCLAUDE_WORKSPACE_DIR` to ensure schedules go to workspace, not project dir.)

3. Create file with `Write` tool

4. **SEND FEEDBACK** confirming creation

**File Format:**
```markdown
---
name: Schedule Name
cron: "0 9 * * *"
enabled: true
blocking: true
chatId: oc_xxx
createdAt: 2024-01-01T00:00:00.000Z
---

Schedule content prompt here
```

**Field Reference:**
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `name` | Yes | - | Schedule display name |
| `cron` | Yes | - | Cron expression for timing |
| `enabled` | No | `true` | Whether schedule is active |
| `blocking` | No | `true` | Skip execution if previous run still in progress |
| `chatId` | Yes | - | Chat ID for execution context |
| `createdAt` | No | - | Creation timestamp |
| `model` | No | - | Model to use for execution (e.g., "sonnet", "opus") |
| `modelTier` | No | - | Three-level model tier: `"high"`, `"low"`, or `"multimodal"` (resolved to a concrete model via `Config.getModelForTier`; Issue #3059). |
| `timezone` | No | `Asia/Shanghai` | IANA timezone for cron scheduling (e.g., `"UTC"`, `"America/New_York"`). Validated against the IANA database (Issue #3860). |
| `timeoutMs` | No | `7200000` (2 h) | Max wait in ms for the task's agent turn (Issue #3894; turn-level since #4648). Not a kill switch: on timeout the scheduler stops waiting and logs a neutral outcome — the turn may still finish in the background (stuck turns are killed separately by the agent pool's busy-turn cap). Tasks that legitimately run longer must set this explicitly (Issue #4649). |
| `cooldownPeriod` | No | - | Cooldown in ms; prevents re-execution for this duration after a run completes (Issue #869). |
| `clearContext` | No | `false` | Reset the chat's persistent agent **before** this task runs, so it executes on a fresh session with no prior conversation context (Issue #4206). ⚠️ **Destructive**: subsequent user messages in the same chat also land on the fresh session until context re-accumulates — confirm intent before enabling. |

---

### 2. Delete Schedule (Disable)

**IMPORTANT**: Do NOT delete the schedule file. Instead, disable it by setting `enabled: false`.

This preserves the configuration for potential future reactivation and maintains an audit trail.

**Steps:**
1. Find schedule files with `Glob`: `$DISCLAUDE_WORKSPACE_DIR/schedules/*/SCHEDULE.md` (or `schedules/*/SCHEDULE.md` if env var not set)
2. Read files with `Read`
3. Filter by current `chatId`
4. Confirm schedule to disable
5. Verify schedule belongs to current `chatId`
6. **Disable with `Edit` tool**: Change `enabled: true` to `enabled: false`
7. **SEND FEEDBACK** confirming the schedule is now disabled

**Example:**
```yaml
# Before
enabled: true

# After
enabled: false
```

**Error Handling:**
- Schedule not found → send feedback with available schedules
- chatId mismatch → reject and explain
- Already disabled → inform user it's already disabled

**Why disable instead of delete?**
- Preserves configuration for future reactivation
- Maintains audit trail of past schedules
- Allows reviewing disabled schedules
- User can permanently delete manually if needed

---

### 3. Update Schedule

**Modifiable Properties:**
- `cron`: Execution time
- `name`: Schedule name
- `enabled`: Enable/disable
- `blocking`: Blocking mode
- `model`: Model selection
- `modelTier`: Model tier selection
- `timezone`: Cron timezone (IANA)
- `timeoutMs`: Turn-wait timeout (ms; default 2 h — set higher for long-running tasks)
- `cooldownPeriod`: Post-run cooldown (ms)
- `clearContext`: Fresh-session toggle (resets persistent agent before the task runs; see Field Reference)
- Content (body text)

**Steps:**
1. Find schedule file via `Glob`: `$DISCLAUDE_WORKSPACE_DIR/schedules/*/SCHEDULE.md` (or `schedules/*/SCHEDULE.md` if env var not set)
2. Verify `chatId` ownership
3. Confirm changes
4. Modify with `Edit` tool
5. **SEND FEEDBACK** showing before/after

---

### 4. List Schedules

**Steps:**
1. Find all schedule files with `Glob`: `$DISCLAUDE_WORKSPACE_DIR/schedules/*/SCHEDULE.md` (or `schedules/*/SCHEDULE.md` if env var not set)
2. Read each file
3. Filter by current `chatId`
4. Format and display
5. **SEND FEEDBACK** (even if no schedules found)

**Output Format:**
```
Schedules:

| Name | Cron | Status |
|------|------|--------|
| Daily Report | Daily 9:00 | Enabled |
| Weekly Summary | Fri 14:00 | Disabled |
```

**No Schedules:**
```
No schedules found.
Would you like to create one?
```

---

## Cron Format

```
minute hour day month weekday
```

**Examples:**
- `"0 9 * * *"` - Daily at 9:00
- `"30 14 * * 5"` - Friday 14:30
- `"0 10 1 * *"` - 1st of month 10:00
- `"*/15 * * * *"` - Every 15 minutes
- `"0 * * * *"` - Hourly
- `"0 0 * * *"` - Daily at midnight

---

## Schedule Prompt Guidelines

**CRITICAL**: Well-written prompts ensure efficient execution. Follow these guidelines:

### 1. Be Self-Contained

**Bad**: "Continue the task from yesterday"
**Good**: "Check the disclaude repository for new issues and create a PR if applicable"

The prompt must contain ALL necessary context. The scheduler executes in a fresh session with no memory of previous conversations.

### 2. Avoid Creating New Schedules

**Bad**: "Create a daily reminder to check emails"
**Good**: "Check emails and report new important messages"

Scheduled tasks cannot create other scheduled tasks (anti-recursion protection). If periodic behavior is needed, report to user instead.

### 3. Specify Clear Success Criteria

**Bad**: "Do something with the database"
**Good**: "Run database backup and verify the backup file exists in /backups/"

Define what "done" looks like. Include verification steps when possible.

### 4. Include Error Handling Instructions

**Bad**: "Send a report"
**Good**: "Send a report. If the API is unavailable, retry once after 5 minutes, then report failure."

Specify what to do when things go wrong.

### 5. Limit Scope and Dependencies

**Bad**: "Fix all bugs in the system"
**Good**: "Check issue #123 and report its current status"

Avoid broad or unbounded tasks. Each execution should have clear boundaries.

### 6. Provide Resource References

**Bad**: "Check the config file"
**Good**: "Check the config file at `/app/workspace/config.yaml`"

Include full paths, URLs, or identifiers. Don't assume the executor knows where things are.

### 7. Consider Execution Time

**Bad**: "Analyze the entire codebase and refactor"
**Good**: "Run the test suite for the schedule module"

Scheduled tasks should complete within reasonable time. Break large tasks into smaller scheduled checks.

### Prompt Template

```markdown
## Objective
[What should be accomplished]

## Context
[Any necessary background information]

## Steps
1. [First step]
2. [Second step]
...

## Success Criteria
[How to verify the task completed successfully]

## Error Handling
[What to do if something fails]
```

---

## Checklist

After each operation, verify:
- [ ] Used correct `chatId`?
- [ ] Verified schedule ownership?
- [ ] **Sent feedback to user?** (CRITICAL)

---

## DO NOT

- Create schedules without confirmation
- Modify schedules from other chats
- Delete schedule files (disable instead with `enabled: false`)
- Complete operation without sending feedback
- Assume directory exists (check first)
- Execute unrelated operations
- Create new schedules from within a scheduled task execution
- Write prompts that depend on previous conversation context

---

## Example: Daily Soul Question (Issue #719)

This example demonstrates how to create a schedule for the 0.4.2 MVP use case: daily analysis of chat/work records with open-ended "soul questions" to trigger discussions in topic groups.

### Prerequisites

1. **Topic Group**: First mark a group as a topic group using `/topic-group mark <chatId>`
2. **Chat Logs**: The message logging system automatically records chat content to `workspace/logs/chat-messages/`

### Schedule File

Create `$DISCLAUDE_WORKSPACE_DIR/schedules/daily-soul-question/SCHEDULE.md`:

```markdown
---
name: 每日灵魂拷问
cron: "0 21 * * *"
enabled: true
blocking: true
# Replace with your topic group's chatId
chatId: oc_your_topic_group_chat_id
createdAt: 2026-03-06T00:00:00.000Z
---

# 每日灵魂拷问

## 背景

0.4.2 的 MVP 用例：每日分析聊天/工作记录，发出开放式的灵魂拷问，引发话题群讨论。

## 核心特点

- **类 BBS 模式**: 不预期用户一定有响应
- **开放式讨论**: 引发思考,而非等待决策
- **主动推送**: 发送到话题群

## 执行步骤

### 步骤 1: 获取话题群

读取 `workspace/groups.json` 文件,获取所有 `isTopicGroup: true` 的群。

如果没有话题群,输出以下消息并结束:
```
📋 每日灵魂拷问: 暂无话题群

请先使用 /topic-group mark <chatId> 命令标记一个群为话题群。
```

### 步骤 2: 读取今日聊天记录

读取 `workspace/logs/chat-messages/` 目录下今天的日期文件夹中的所有 `.md` 文件。

今天的日期格式为 YYYY-MM-DD (如 2026-03-06)。

如果没有聊天记录,输出以下消息并发送到话题群:
```
📋 每日灵魂拷问: 今日暂无聊天记录

今天还没有聊天记录,无法生成灵魂拷问。明天再试试吧!
```

### 步骤 3: 分析并生成灵魂拷问

分析聊天记录,识别以下类型的话题:
- 有趣的决策或讨论
- 潜在的改进点
- 值得反思的问题
- 有趣的技术讨论

生成 1-3 个开放式的灵魂拷问问题,格式示例:
```
🤔 今日灵魂拷问

分析今天的聊天记录,发现一个有趣的问题:

「在处理 xxx 时,我们选择了方案 A 而非方案 B。
这个决策是否正确?有没有更好的选择?」

欢迎在群里讨论 👇
```

### 步骤 4: 发送到话题群

使用 channel CLI 的 `send_text` 命令发送灵魂拷问到第一个话题群。

参数设置:
- content: 灵魂拷问内容
- format: "text"
- chatId: 第一个话题群的 chatId

## 重要提示

1. **不要创建新的定时任务** - 这是定时任务执行环境的规则
2. **不要修改现有的定时任务**
3. **只执行上述步骤,完成后结束**
4. **使用 channel CLI 发送消息时，确保 `--chat` 是话题群的 ID**

## 验收标准

- [ ] 能获取话题群列表
- [ ] 能读取今日聊天记录
- [ ] 能生成灵魂拷问内容
- [ ] 能发送到话题群
```

