---
name: todoist
description: "Manage Todoist tasks and projects. Create tasks from agent outputs, read task status, list projects, complete or delete tasks. Trigger: any request to add a to-do, create a task, check Todoist, list tasks, or sync work items to Todoist."
user-invocable: true
metadata:
  { "openclaw": { "emoji": "✅" } }
---

# Todoist — Task Management Skill

Interact with Brent's Todoist account to create, read, update, and complete tasks.

**API:** Todoist REST API v1 — `https://api.todoist.com/api/v1/`
**Auth:** `Authorization: Bearer $TODOIST_API_TOKEN`

**Note:** List endpoints return `{"results": [...]}` — always extract `.results`.

---

## Core Operations

### List all tasks

```bash
curl -s "https://api.todoist.com/api/v1/tasks" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  | python3 -c "
import json, sys
tasks = json.load(sys.stdin)['results']
for t in tasks:
    due = (t.get('due') or {}).get('date', '–')
    print(f\"[{t['id']}] P{t['priority']} | due: {due} | {t['content']}\")
print(f'Total: {len(tasks)} tasks')
"
```

### List tasks in a specific project

```bash
PROJECT_ID="your_project_id"
curl -s "https://api.todoist.com/api/v1/tasks?project_id=${PROJECT_ID}" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  | python3 -c "
import json, sys
tasks = json.load(sys.stdin)['results']
for t in tasks:
    due = (t.get('due') or {}).get('date', '–')
    print(f\"[{t['id']}] due: {due} | {t['content']}\")
"
```

### List all projects

```bash
curl -s "https://api.todoist.com/api/v1/projects" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  | python3 -c "
import json, sys
projects = json.load(sys.stdin)['results']
for p in projects:
    inbox = ' (Inbox)' if p.get('is_inbox_project') else ''
    print(f\"{p['id']} | {p['name']}{inbox}\")
"
```

**Known projects:**
| ID | Name |
|----|------|
| `6g8XfxCHRfxmXRgG` | Inbox |
| `6g8XhW2jm96M2Vvq` | Getting Started |

### Create a task

```bash
# Basic task (goes to Inbox)
curl -s -X POST "https://api.todoist.com/api/v1/tasks" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Task title here",
    "due_string": "tomorrow",
    "priority": 2
  }' | python3 -c "import json,sys; t=json.load(sys.stdin); print('Created:', t['id'], '|', t['content'])"
```

```bash
# Task with description in a specific project
curl -s -X POST "https://api.todoist.com/api/v1/tasks" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$TASK_TITLE\",
    \"description\": \"$TASK_DESCRIPTION\",
    \"project_id\": \"$PROJECT_ID\",
    \"due_string\": \"$DUE_STRING\",
    \"priority\": $PRIORITY
  }" | python3 -c "import json,sys; t=json.load(sys.stdin); print('Created:', t['id'], t['content'])"
```

**Priority values:** 1=normal, 2=medium, 3=high, 4=urgent
**due_string examples:** `"today"`, `"tomorrow"`, `"next monday"`, `"in 3 days"`, `"every day"`, `"2026-04-01"`

### Complete (close) a task

```bash
TASK_ID="task_id_here"
curl -s -X POST "https://api.todoist.com/api/v1/tasks/${TASK_ID}/close" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN"
echo "Task ${TASK_ID} marked complete"
```

### Update a task

```bash
curl -s -X POST "https://api.todoist.com/api/v1/tasks/${TASK_ID}" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Updated title",
    "due_string": "next friday",
    "priority": 3
  }' | python3 -c "import json,sys; t=json.load(sys.stdin); print('Updated:', t['content'])"
```

### Delete a task

```bash
curl -s -X DELETE "https://api.todoist.com/api/v1/tasks/${TASK_ID}" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN"
# Returns 204 No Content on success
```

### Add a comment to a task

```bash
curl -s -X POST "https://api.todoist.com/api/v1/comments" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"task_id\": \"${TASK_ID}\",
    \"content\": \"$COMMENT_TEXT\"
  }" | python3 -c "import json,sys; c=json.load(sys.stdin); print('Comment added:', c['id'])"
```

---

## Agent Workflow Patterns

### Create a task from agent output

After completing research, generating a document, or any deliverable:

```bash
TASK_TITLE="Review deep research: $TOPIC"
TASK_DESC="Report: $GDOC_URL\nGenerated: $(date +%Y-%m-%d)"

TASK_ID=$(curl -s -X POST "https://api.todoist.com/api/v1/tasks" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$TASK_TITLE\",
    \"description\": \"$TASK_DESC\",
    \"due_string\": \"in 2 days\",
    \"priority\": 2
  }" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
echo "Task created: $TASK_ID"
```

### Check overdue + today tasks to inform priorities

```bash
curl -s "https://api.todoist.com/api/v1/tasks?filter=overdue|today" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  | python3 -c "
import json, sys
tasks = json.load(sys.stdin)['results']
if not tasks:
    print('No overdue or due-today tasks.')
else:
    print(f'{len(tasks)} tasks due today or overdue:')
    for t in sorted(tasks, key=lambda x: -x['priority']):
        due = (t.get('due') or {}).get('date', '–')
        print(f\"  P{t['priority']} [{due}] {t['content']}\")
"
```

### Sync conductor workshop task completion to Todoist

```bash
# Log a completed conductor task to Todoist then immediately close it
TASK_ID=$(curl -s -X POST "https://api.todoist.com/api/v1/tasks" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"✅ Completed: $WORKSHOP_TASK_TITLE\",
    \"description\": \"Conductor issue resolved on $(date +%Y-%m-%d)\",
    \"due_string\": \"today\"
  }" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")

curl -s -X POST "https://api.todoist.com/api/v1/tasks/${TASK_ID}/close" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN"
```

---

## Response Format

**Listing tasks:** Show content, due date, priority. Sort overdue first, then today, upcoming. Cap at 20; offer to filter by project.

**Creating:** Confirm with task title + ID.

**Completing:** "Done — marked '[task title]' complete in Todoist."

**Filter syntax** (`?filter=`): `today`, `overdue`, `p1` through `p4`, `#ProjectName`, `overdue|today`
