Back to skills
SkillHub ClubShip Full StackFull Stack

telegram-todolist

Imported from https://github.com/openclaw/skills.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,125
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
F25.2

Install command

npx @skill-hub/cli install openclaw-skills-telegram-todolist

Repository

openclaw/skills

Skill path: skills/hengbo12345/telegram-todolist

Imported from https://github.com/openclaw/skills.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install telegram-todolist into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding telegram-todolist to shared team environments
  • Use telegram-todolist for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: telegram-todolist
description: Telegram bot Todo List manager. Three commands: /todo query (show tasks), /todo organize (add/delete/edit tasks), /todo execute (complete tasks). Uses TODO.md file. Perfect for task tracking in Telegram. Supports statistics, progress tracking, and organized task management.
---

# Telegram Todo List

Manage a Todo List stored in TODO.md through Telegram bot commands.

## Commands

### 1. 查询 (query)
**Usage**: `/todo query`

**Description**: Display current todo list with status

**Behavior**:
- Read TODO.md file
- Parse tasks (both completed [x] and pending [ ])
- Format and display in clean table/list
- Show statistics (total tasks, completed, pending)

**Example Output**:
```
📋 待办事项列表

今日任务 (2026-02-12)

- [ ] 学习并掌握 skill-creator 技能介绍
  - 理解技能创建的核心原则

待办总数:6 项未完成
已完成:1 项
```

### 2. 整理 (organize)
**Usage**: `/todo organize`

**Description**: Update, optimize, or restructure the todo list

**Behavior Options**:
- **Add new task**: User specifies task content
- **Delete task**: User specifies task number to remove
- **Move task**: Change task priority/order
- **Edit task**: Modify task content or check/uncheck status
- **Batch operations**: Add multiple tasks at once

**Input Format**:
``/todo organize <action> <details>
```

**Actions**:
- `add`: Add new task(s)
- `delete`: Remove task by number
- `move`: Move task to different position
- `edit`: Modify task content
- `check`: Mark task as completed
- `uncheck`: Mark task as uncompleted

**Example**:
``/todo organize add 学习Markdown语法
/todo organize delete 3
/todo organize move 1 to top
```

### 3. 执行 (execute)
**Description**: Complete a specific task

**Behavior**:
- Mark task as completed [x]
- Update timestamp
- Remove from active list
- Move to completed section
- Show confirmation

**Input Format**:
``/todo execute <task_number>
```

**Example**:
``/todo execute 1
```

## File Structure

**Storage**: TODO.md in workspace root
```
/root/.openclaw/workspace/TODO.md
```

**File Format**:
```markdown
# TODO List

## 今日任务 (2026-02-12)

- [ ] **Task 1**
  - Subtask 1
  - Subtask 2

- [ ] **Task 2**

---

## 待完成任务

### Category
- [ ] **Task 3**

---

## 已完成任务

- [x] **Completed Task**
  - 记录时间:2026-02-12 07:55 UTC
  - 内容:Task description
```

## Implementation Details

### Parsing Tasks

**Regular Expression**:
```regex
- \[([ x])\]\s*\*\*(.+?)\*\*.*?$         # Main task
  - (.+)$                                 # Subtasks
```

**Status**:
- `[x]` = completed
- `[ ]` = pending

### Display Format

**Clean Table**:
```
📋 待办事项

今日任务 (2026-02-12)
1. [ ] Task 1
2. [ ] Task 2

待办总数:2 项未完成
已完成:0 项
```

### Error Handling

**Task Not Found**:
- "未找到任务 #N"
- Ask user to verify task number

**Invalid Format**:
- "格式错误,请使用正确的命令格式"
- Show usage example

**File Read Error**:
- "无法读取 TODO.md,请检查文件权限"
- Try to recreate default template

### User Experience

**Confirmation Messages**:
- Task completed: "✅ 已完成任务 #N"
- Task deleted: "🗑️ 已删除任务 #N"
- Task added: "➕ 已添加任务"

**Progress Indicators**:
- Show real-time count updates
- Calculate completion percentage
- Highlight pending vs completed

## Tips

1. **Task Numbers**: Always reference task by number in organize/execute commands
2. **Indentation**: Keep consistent spacing for subtasks
3. **Comments**: Lines starting with `#` are ignored
4. **Status Updates**: Execute updates both visual status and file content

## Examples

### User: /todo query
Bot shows full todo list

### User: /todo organize add 学习CSS
Bot adds task and shows confirmation

### User: /todo execute 2
Bot marks task #2 as completed and updates list

### User: /todo organize delete 5
Bot removes task #5 from list


---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "hengbo12345",
  "slug": "telegram-todolist",
  "displayName": "Telegram Todo List",
  "latest": {
    "version": "1.0.1",
    "publishedAt": 1770887844215,
    "commit": "https://github.com/openclaw/skills/commit/4a2391ed3bd53bee7f20ba01a9b5319c2e262636"
  },
  "history": []
}

```

### scripts/todolist.py

```python
#!/usr/bin/env python3
"""
Telegram Todo List Manager
Manage TODO.md file through file operations and text parsing.
"""

import os
import re
from datetime import datetime
from typing import List, Dict, Tuple

TODO_FILE = "/root/.openclaw/workspace/TODO.md"


def read_todo() -> str:
    """Read TODO.md file content."""
    try:
        with open(TODO_FILE, 'r', encoding='utf-8') as f:
            return f.read()
    except FileNotFoundError:
        return create_default_template()
    except Exception as e:
        print(f"Error reading TODO.md: {e}")
        return create_default_template()


def write_todo(content: str) -> bool:
    """Write content to TODO.md file."""
    try:
        with open(TODO_FILE, 'w', encoding='utf-8') as f:
            f.write(content)
        return True
    except Exception as e:
        print(f"Error writing TODO.md: {e}")
        return False


def create_default_template() -> str:
    """Create default TODO.md template."""
    template = """# TODO List

## 今日任务 (2026-02-12)

- [ ] **学习并掌握 skill-creator 技能介绍**
  - 理解技能创建的核心原则
  - 学习渐进式披露设计模式
  - 掌握技能结构和创建流程
  - 实际创建一个简单的 skill

---

## 待完成任务

### 技能开发
- [ ] 创建第一个自定义 skill
- [ ] 学习参考文档输出模式
- [ ] 练习脚本资源的打包

### 技术研究
- [ ] 深入理解渐进式披露的实践应用
- [ ] 探索不同自由度的指令粒度选择

---

## 已完成任务

- [x] **介绍 skill-creator 技能**
  - 记录时间:2026-02-12 07:55 UTC
  - 内容:skill-creator 是一个技能开发指南,用于创建或更新 Agent 技能

---

## 临时笔记

**Skill-creator 学习要点:**
- 核心:模块化、自包含的能力包
- 原则:简洁优先、适度自由度
- 结构:SKILL.md + �script/(可选)
- 流程:6步创建流程
- 设计:渐进式披露、按需引用

**下一步:**
1. 选择一个具体场景创建 skill
2. 实践练习渐进式披露
3. 打包并测试创建的 skill
"""
    write_todo(template)
    return template


def parse_tasks(content: str) -> List[Dict]:
    """Parse TODO.md content into structured tasks."""
    tasks = []

    # Current date for "今日任务"
    today = datetime.now().strftime("%Y-%m-%d")
    section_headers = [
        f"今日任务 ({today})",
        "待完成任务",
        "已完成任务"
    ]

    current_section = None
    current_task = None
    current_subtasks = []

    for line in content.split('\n'):
        stripped = line.strip()

        # Check for section headers
        for header in section_headers:
            if stripped == f"## {header}":
                # Save previous task if exists
                if current_task and current_section == "今日任务":
                    tasks.append({
                        'section': '今日任务',
                        'main_task': current_task,
                        'subtasks': current_subtasks,
                        'completed': False
                    })
                    current_task = None
                    current_subtasks = []
                current_section = header
                break

        # Check for task lines
        if re.match(r'^-\s+\[([ x])\]\s*\*\*(.+?)\*\*.*?$', stripped):
            # Save previous task
            if current_task and current_subtasks:
                tasks.append({
                    'section': current_section,
                    'main_task': current_task,
                    'subtasks': current_subtasks,
                    'completed': stripped.startswith('[- ]')
                })
                current_subtasks = []

            # Parse new task
            match = re.match(r'^-\s+\[([ x])\]\s*\*\*(.+?)\*\*(.+)?$', stripped)
            if match:
                current_task = match.group(2)
                completed = match.group(1) == 'x'

        # Check for subtasks (indented lines)
        elif stripped.startswith('  -') or stripped.startswith('\t-'):
            subtask = stripped.replace('  - ', '').replace('\t- ', '').strip()
            if subtask and not subtask.startswith('- ['):
                current_subtasks.append(subtask)

        # Subsection headers
        elif stripped.startswith('### '):
            current_section = stripped.replace('### ', '')

    # Don't forget last task
    if current_task and current_subtasks:
        tasks.append({
            'section': current_section or '待完成任务',
            'main_task': current_task,
            'subtasks': current_subtasks,
            'completed': stripped.startswith('[- ]') if stripped.startswith('-') else False
        })

    return tasks


def format_tasks_display(tasks: List[Dict]) -> str:
    """Format tasks for display."""
    lines = []
    lines.append("📋 待办事项列表\n")

    for task in tasks:
        status = "✅" if task['completed'] else "⬜"
        lines.append(f"{status} {task['main_task']}")
        for subtask in task['subtasks']:
            lines.append(f"   - {subtask}")

        # Add section indicator
        if task['section'] != '待完成任务':
            lines.append(f"   📌 {task['section']}")

    # Calculate statistics
    total = len(tasks)
    completed = sum(1 for t in tasks if t['completed'])
    pending = total - completed

    lines.append("\n待办总数:{} 项未完成".format(pending))
    lines.append("已完成:{} 项".format(completed))

    return '\n'.join(lines)


def find_task_by_number(content: str, task_num: int) -> Tuple[int, str, bool]:
    """Find task by number and return line number, content, and status."""
    tasks = parse_tasks(content)
    if 1 <= task_num <= len(tasks):
        task = tasks[task_num - 1]
        # Find the line with this task in content
        lines = content.split('\n')
        for i, line in enumerate(lines):
            if line.strip().startswith('- [x]') and task_num == i + 1:
                return i, line, True
            elif line.strip().startswith('- [ ]') and task_num == i + 1:
                return i, line, False
    return -1, "", False


def mark_task_complete(content: str, task_num: int) -> Tuple[str, bool]:
    """Mark task as complete and return updated content."""
    line_num, line, is_complete = find_task_by_number(content, task_num)

    if line_num == -1:
        return content, False

    if is_complete:
        return content, True  # Already complete

    # Replace [ ] with [x]
    updated_line = line.replace('- [ ]', '- [x]')
    lines = content.split('\n')
    lines[line_num] = updated_line

    return '\n'.join(lines), True


def find_task_start(content: str, task_num: int) -> int:
    """Find the starting line number of a task."""
    tasks = parse_tasks(content)
    if 1 <= task_num <= len(tasks):
        current_count = 0
        for line in content.split('\n'):
            if line.strip().startswith('- [') and not line.strip().startswith('#'):
                current_count += 1
                if current_count == task_num:
                    # Find the section header line before this task
                    line_idx = content.split('\n').index(line)
                    # Check previous lines for section header
                    for i in range(max(0, line_idx - 10), line_idx):
                        if content.split('\n')[i].strip().startswith('## '):
                            return i
                    return 0  # Start of file
    return 0


def add_task(content: str, main_task: str, section: str = "今日任务", subtasks: List[str] = None) -> str:
    """Add a new task to the TODO.md file."""
    lines = content.split('\n')
    main_task_lines = [f"- [ ] **{main_task}**"]

    if subtasks:
        main_task_lines.extend([f"  - {st}" for st in subtasks])

    # Find section location
    section_index = -1
    for i, line in enumerate(lines):
        if f"## {section}" in line:
            section_index = i
            break

    if section_index != -1:
        # Insert after section header
        insert_pos = section_index + 1
        lines = lines[:insert_pos] + main_task_lines + lines[insert_pos:]
    else:
        # Add to end of content
        lines = lines + main_task_lines + ["", "---"]

    return '\n'.join(lines)


def delete_task(content: str, task_num: int) -> str:
    """Delete a task by number."""
    lines = content.split('\n')
    found = False

    for i in range(len(lines)):
        stripped = lines[i].strip()
        if stripped.startswith('- [') and stripped.startswith('- [x]'):
            task_count = int(stripped[3])  # Extract number after ' - ['
            if task_count == task_num:
                # Delete this line and any subtasks (next few lines)
                # Skip until we find a line not starting with indentation
                j = i + 1
                while j < len(lines) and (lines[j].strip().startswith('  -') or lines[j].strip().startswith('\t-')):
                    j += 1
                lines = lines[:i] + lines[j:]
                found = True
                break

    if not found:
        return content

    return '\n'.join(lines)


if __name__ == "__main__":
    # Example usage
    content = read_todo()
    tasks = parse_tasks(content)
    print(format_tasks_display(tasks))

```

telegram-todolist | SkillHub