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.
Scanned 9/4/2026
Install to Claude Code
npx -y skills add NeverSight/skills_feed --skill google-tasks --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Google Tasks?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/neversight-google-tasks)More formats (shields.io, HTML) on the badges page.
---
name: google-tasks
description: 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.
when_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.
connections: [google/tasks]
allowed_tools: [Bash]
license: Apache-2.0
metadata:
author: acedatacloud
version: "1.1"
---
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)
```sh
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
```sh
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
```sh
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
```sh
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)
```sh
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)
```sh
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
```sh
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`:
```sh
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
```sh
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
```sh
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
```sh
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
```sh
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
```sh
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
```sh
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
```sh
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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!