Google tasks
Read and manage Google Tasks task lists and individual tasks via the Tasks v1 REST API. Use when the user mentions Google Tasks, todo / pending / overdue tasks, weekly task recap, grouping todos by list, adding or completing a task, or moving / deleting tasks.From its SKILL.md
npx -y skills add AceDataCloud/Skills --skill google-tasksAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
11.3 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it
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.
Recipes
Verify auth + list all task lists (always run first)
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.
List all unfinished tasks across every list
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.
Pending tasks in one specific list, sorted by due date
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.
Tasks due today
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.
Overdue tasks (everything still pending with a due date in the past)
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
Recently completed tasks (this week, for a recap)
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.
Get one task's details
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.
Pagination
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
Write recipes
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.
Add a new task
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.
Bulk add three tasks under user confirmation
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.
Mark a task complete
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}.
Edit a task's title / notes / due date
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}'
Delete a task
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.
Re-order: move a task to a position
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.
Create a brand-new task list
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}'
Common error codes
| 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.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.