Lists, reads, creates, completes, and deletes Google Tasks via the Tasks v1 REST API. Useful for surfacing overdue/pending items, grouping by list, or weekly task recaps.
How this skill is triggered — by the user, by Claude, or both
Slash command
/acedatacloud-ai-media:google-tasksWhen to use
Trigger when the user wants to inspect or manage their Google Tasks — list task lists, surface pending items, group by due date, pull details for one task, add new todos, mark items complete, re-order or delete tasks. The installed connector always grants `tasks.readonly`; the user opts in to the broader `tasks` scope (full read + write) at install — confirm before destructive writes.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Drive Google Tasks via `curl + jq`. The user's OAuth bearer token is
Drive Google Tasks via curl + jq. The user's OAuth bearer token is
in $GOOGLE_TASKS_TOKEN; every call needs it as
Authorization: Bearer $GOOGLE_TASKS_TOKEN. At minimum the token
carries tasks.readonly plus the identity scopes
(openid email profile); if the user opted in to write at install
time it also carries the broader tasks scope (read + write).
The Tasks API returns standard JSON; failures surface as
{"error": {"code": 401|403|..., "message": "..."}} — show that
error verbatim. 401 means the token expired (re-install). 403 insufficientPermissions on a write means the user only granted
tasks.readonly — ask them to re-install with the read+write box
checked.
Always start with users/@me/lists to discover which task lists
the account has — the user's default plus any extras they created on
calendar.google.com or in the Tasks app.
Before bulk creates / completions / deletes echo the exact titles back to the user and ask them to confirm. Don't trash a task by guessing an id.
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq '.items[] | {id, title, updated}'
The default list is usually titled "我的任务" / "My Tasks" but the
id (a long opaque string like MTAxMjM0NTY3OA) is what every
subsequent lists/{id}/tasks call needs.
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq -r '.items[] | "\(.id)\t\(.title)"' | while IFS=$'\t' read LIST_ID LIST_TITLE; do
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode 'showCompleted=false' \
--data-urlencode 'maxResults=100' \
| jq --arg list "$LIST_TITLE" '.items[]? | {list: $list, title, due, status, notes}'
done | jq -s '. | sort_by(.due // "9999")'
showCompleted=false filters out done items at the API level. The
default showCompleted=true&showHidden=false returns done tasks too.
LIST_ID='MTAxMjM0NTY3OA'
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode 'showCompleted=false' \
--data-urlencode 'maxResults=100' \
| jq '.items // [] | sort_by(.due // "9999") | .[] | {title, due, notes, status, position}'
position is the user's drag-to-reorder rank inside the list — useful
when the user says "what's at the top of my tasks". Tasks without a
due field are open-ended.
TODAY=$(date -u +%Y-%m-%d)
TOMORROW=$(date -u -d "+1 day" +%Y-%m-%d 2>/dev/null \
|| date -u -v+1d +%Y-%m-%d)
TODAY_START="${TODAY}T00:00:00.000Z"
TOMORROW_START="${TOMORROW}T00:00:00.000Z"
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq -r '.items[] | "\(.id)\t\(.title)"' | while IFS=$'\t' read LIST_ID LIST_TITLE; do
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode "dueMin=$TODAY_START" \
--data-urlencode "dueMax=$TOMORROW_START" \
--data-urlencode 'showCompleted=false' \
| jq --arg list "$LIST_TITLE" '.items[]? | {list: $list, title, due, notes}'
done | jq -s
dueMin / dueMax are RFC 3339 timestamps. The Tasks API stores
due at midnight UTC, so the local-day window is approximate around
the date boundary — that's fine for "due today" semantics, mention
the caveat only if the user pushes back.
NOW=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq -r '.items[] | "\(.id)\t\(.title)"' | while IFS=$'\t' read LIST_ID LIST_TITLE; do
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode "dueMax=$NOW" \
--data-urlencode 'showCompleted=false' \
| jq --arg list "$LIST_TITLE" '.items[]? | {list: $list, title, due, daysOverdue: (((now * 1000) - (.due | sub("Z"; "+00:00") | fromdateiso8601 * 1000)) / 86400000 | floor)}'
done | jq -s
ONE_WEEK_AGO=$(date -u -d "-7 days" +%Y-%m-%dT%H:%M:%S.000Z 2>/dev/null \
|| date -u -v-7d +%Y-%m-%dT%H:%M:%S.000Z)
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq -r '.items[] | "\(.id)\t\(.title)"' | while IFS=$'\t' read LIST_ID LIST_TITLE; do
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode 'showCompleted=true' \
--data-urlencode 'showHidden=true' \
--data-urlencode "completedMin=$ONE_WEEK_AGO" \
| jq --arg list "$LIST_TITLE" '.items[]? | select(.status=="completed") | {list: $list, title, completed}'
done | jq -s '. | sort_by(.completed)'
completedMin / completedMax mirror dueMin/Max and only apply
to tasks already moved to the "completed" state. You must pass
showCompleted=true AND showHidden=true to see them — Google hides
completed tasks from the default list.
LIST_ID='MTAxMjM0NTY3OA'
TASK_ID='dGFza0lkRXhhbXBsZQ'
curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks/$TASK_ID" \
| jq '{title, due, status, notes, completed, position, links: .links}'
links exposes the user's manual hyperlinks (e.g. an attached email
or Drive doc) — render them as a list to the user when present.
maxResults caps at 100 per page. Use nextPageToken:
LIST_ID='MTAxMjM0NTY3OA'
PAGE_TOKEN=''
while : ; do
RESP=$(curl -sS -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--get "https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
--data-urlencode 'maxResults=100' \
--data-urlencode 'showCompleted=false' \
${PAGE_TOKEN:+--data-urlencode "pageToken=$PAGE_TOKEN"})
echo "$RESP" | jq -c '.items[]?'
PAGE_TOKEN=$(echo "$RESP" | jq -r '.nextPageToken // empty')
[ -z "$PAGE_TOKEN" ] && break
done
These all need the broader tasks scope. If the user only granted
tasks.readonly you'll get 403 insufficientPermissions — surface
that and ask them to re-install with the read+write box checked.
LIST_ID='MTAxMjM0NTY3OA'
curl -sS -X POST -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"title":"Draft Q2 plan","notes":"Outline + risks + asks.","due":"2026-05-15T00:00:00.000Z"}' \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
| jq '{id, title, due, status}'
Google stores due as midnight UTC of the chosen day — the time of
day is ignored in the UI. To insert at the very top of the list,
add ?previous= (no value) to the URL.
LIST_ID='MTAxMjM0NTY3OA'
DUE='2026-05-12T00:00:00.000Z'
for T in 'Reply to Alice' 'Review PR #404' 'Send meeting recap'; do
curl -sS -X POST -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
-H 'Content-Type: application/json' \
--data "{\"title\":$(jq -nr --arg t "$T" '$t'),\"due\":\"$DUE\"}" \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks" \
| jq -c '{id, title, due}'
done
Always list the titles you're about to create and ask for the user's go-ahead before running this loop — there is no atomic batch endpoint.
LIST_ID='MTAxMjM0NTY3OA'
TASK_ID='dGFza0lkRXhhbXBsZQ'
NOW=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
curl -sS -X PATCH -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
-H 'Content-Type: application/json' \
--data "{\"status\":\"completed\",\"completed\":\"$NOW\"}" \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks/$TASK_ID" \
| jq '{id, title, status, completed}'
Reverse with {"status":"needsAction","completed":null}.
LIST_ID='MTAxMjM0NTY3OA'
TASK_ID='dGFza0lkRXhhbXBsZQ'
curl -sS -X PATCH -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"title":"Draft Q2 plan (rev2)","notes":"Cover risks + asks + budget.","due":"2026-05-20T00:00:00.000Z"}' \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks/$TASK_ID" \
| jq '{id, title, due, notes}'
LIST_ID='MTAxMjM0NTY3OA'
TASK_ID='dGFza0lkRXhhbXBsZQ'
curl -sS -X DELETE -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks/$TASK_ID" \
-o /dev/null -w 'HTTP %{http_code}\n'
204 = success. There is no soft-delete — once gone the task is
gone. Echo the title back before deleting.
LIST_ID='MTAxMjM0NTY3OA'
TASK_ID='dGFza0lkRXhhbXBsZQ'
PREV='dGFza0lkUHJldg' # task id this one should appear AFTER; omit to move to top
curl -sS -X POST -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
--data '' \
"https://tasks.googleapis.com/tasks/v1/lists/$LIST_ID/tasks/$TASK_ID/move?previous=$PREV" \
| jq '{id, title, parent, position}'
Use ?parent=... instead of ?previous=... to nest a task under
another task as a sub-task.
curl -sS -X POST -H "Authorization: Bearer $GOOGLE_TASKS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"title":"Q2 follow-ups"}' \
"https://tasks.googleapis.com/tasks/v1/users/@me/lists" \
| jq '{id, title}'
| HTTP | meaning | what to tell the user |
|---|---|---|
401 UNAUTHENTICATED | token expired / revoked | "Reconnect the Google Tasks connector on the Connections page." |
403 insufficientPermissions | write scope missing | "This action needs the Tasks read+write scope, but only tasks.readonly was granted. Re-install the connector with the read+write box checked." |
404 notFound | wrong list / task id | re-list with users/@me/lists to find the right id. |
429 quotaExceeded | quota / throttling | back off ~5s, then retry once. |
Never log or echo $GOOGLE_TASKS_TOKEN — treat it as a secret.
npx claudepluginhub acedatacloud/skills --plugin acedatacloud-ai-mediaAgent-callable Google Tasks tools — create, list, update, complete, move, and delete tasks and task lists. Use when the user wants to manage Google Tasks or to-dos.
Automates Google Tasks via Rube MCP (Composio) for creating, listing, updating, deleting, moving, and bulk-inserting tasks and task lists.
Manages Todoist tasks and projects via CLI. Lists, adds, completes, updates, and searches tasks with filters for priority, label, project, and due date. Activated by requests about tasks, to-dos, reminders, or productivity.