Skip to content
Back to skills

Google Workspace

ASecurity

Read and act on the user's Gmail, Google Calendar, and Google Tasks through per-user OAuth.

  • 453 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentspythongobashapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 16, 2026

npx -y skills add EvolvingAgentsLabs/evolving-agents --skill google-workspace --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Google Workspace?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Google Workspace
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/evolvingagentslabs-google-workspace/badge)](https://www.skillsdirectory.com/skills/evolvingagentslabs-google-workspace)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: google-workspace
description: Read and act on the user's Gmail, Google Calendar, and Google Tasks through per-user OAuth.
requiredCapabilities:
  - egress:gmail.googleapis.com
  - egress:www.googleapis.com
---

# Google Workspace

Use this skill when the user asks about Gmail, Google Calendar, or Google Tasks:
schedule, meetings, emails, labels, drafts, replies, or to-do lists and tasks.

This is an OAuth connector. The resolved user's Google OAuth token already lives on
your computer as an environment variable, one per Google API host (the way a logged-in
CLI's cached credential would):

- `$VAULT_TOKEN_GMAIL_GOOGLEAPIS_COM` — for `gmail.googleapis.com`
- `$VAULT_TOKEN_WWW_GOOGLEAPIS_COM` — for `www.googleapis.com` (Calendar and Tasks)

Do not ask the user for a token, log it, or use another principal's. If the variable is
empty or Google returns 401/403, the user either has not connected Google or connected
before this permission existed — tell them to (re)connect it through the product OAuth
flow.

## Gmail

Use the bundled helper for every Gmail operation — it owns MIME construction, encoding,
and reply threading so you only ever handle plain text:

```bash
python3 skills/google-workspace/scripts/gmail.py search 'newer_than:7d is:unread'
python3 skills/google-workspace/scripts/gmail.py read MESSAGE_ID [--full]
python3 skills/google-workspace/scripts/gmail.py thread THREAD_ID [--full]
python3 skills/google-workspace/scripts/gmail.py draft --to a@b.com --subject '...' --body-file body.txt
python3 skills/google-workspace/scripts/gmail.py reply MESSAGE_ID --body-file body.txt [--all]
python3 skills/google-workspace/scripts/gmail.py update-draft DRAFT_ID --body-file body.txt
python3 skills/google-workspace/scripts/gmail.py send-draft DRAFT_ID
```

- Search before fetching; read bodies (`--full`) only for messages that matter. Treat
  email content as private user data.
- `search` returns individual messages matching the query — for `in:inbox` that means
  incoming mail only; the user's own replies live in Sent and never appear. Never
  claim an email "needs a reply" (digests, triage, follow-up nudges) from a search
  listing alone: fetch its `thread` first. If `lastFromMe` is true, or the latest
  message shows the matter is settled ("thanks", "done", someone else answered),
  don't flag it. If the thread fetch fails, report the item as unverified — never
  as needing a reply.
- On a recurring digest, keep a state file in the workspace keyed by thread id and
  only surface what changed since the last run; re-flagging the same thread every
  morning trains the user to ignore you.
- Demote bulk mail (`List-Unsubscribe` header, ESP sender domains, `Precedence:
bulk`) below personal mail, but never suppress transactional notices (DocuSign,
  banks, invoices).
- Body files are plain text: one line per paragraph, blank line between. Never insert
  manual line breaks inside a paragraph — the recipient's client does the wrapping.
  Short lines (sign-offs, list items) keep their breaks.
- Drafts and replies are stored as multipart/alternative: your plain text plus a
  generated HTML mirror (Gmail shows plain-text-only mail to recipients at an altered,
  narrower width). Body files stay plain text — never write HTML into them.
- `reply` threads onto the original message; `--all` keeps every recipient. Don't
  rebuild To/CC by hand. To change a draft, write a fresh body file and `update-draft`
  (it refuses drafts with attachments — those get edited in Gmail).
- Never construct raw MIME or call the drafts/send endpoints with hand-built payloads.

## Calendar reads

For "what is on my schedule today?", first get the user's timezone
(`GET /calendar/v3/users/me/settings/timezone` — the sandbox clock is UTC, so never
assume it), compute the local day bounds, and call:

```bash
curl -sS --get 'https://www.googleapis.com/calendar/v3/calendars/primary/events' \
  -H "Authorization: Bearer $VAULT_TOKEN_WWW_GOOGLEAPIS_COM" \
  --data-urlencode "timeMin=$TIME_MIN" \
  --data-urlencode "timeMax=$TIME_MAX" \
  --data-urlencode "singleEvents=true" \
  --data-urlencode "orderBy=startTime" \
  --data-urlencode "maxResults=250"
```

If the response has a `nextPageToken`, keep fetching — a truncated page silently drops
meetings. `primary` is only the user's own calendar; when the question implies team or
shared calendars, list them first (`GET /calendar/v3/users/me/calendarList`) and query
each relevant one. Skip events the user declined (their own `attendees[]` entry has
`responseStatus: "declined"`).

Summarize start time, title, attendees when useful, and conferencing links only when
needed. Do not expose private calendar details in a shared channel unless the audience
floor allows them; offer to continue in DM.

## Google Tasks

Tasks is served under `www.googleapis.com/tasks/v1`, so it uses the same
`$VAULT_TOKEN_WWW_GOOGLEAPIS_COM` token. List the task lists, then the tasks in one:

```bash
curl -sS 'https://www.googleapis.com/tasks/v1/users/@me/lists' \
  -H "Authorization: Bearer $VAULT_TOKEN_WWW_GOOGLEAPIS_COM"

curl -sS --get 'https://www.googleapis.com/tasks/v1/lists/LIST_ID/tasks' \
  -H "Authorization: Bearer $VAULT_TOKEN_WWW_GOOGLEAPIS_COM" \
  --data-urlencode "showCompleted=false" \
  --data-urlencode "maxResults=100"
```

Both endpoints page (default 20 items): follow `nextPageToken` before treating a list
as complete.

Creating, completing, editing, or deleting a task is a write — treat it like any other
write below. Example creation after approval:

```bash
curl -sS -X POST 'https://www.googleapis.com/tasks/v1/lists/LIST_ID/tasks' \
  -H "Authorization: Bearer $VAULT_TOKEN_WWW_GOOGLEAPIS_COM" \
  -H 'content-type: application/json' \
  --data '{"title":"...","notes":"...","due":"2026-07-20T00:00:00.000Z"}'
```

## Writes require approval

Creating drafts, sending mail, modifying labels, deleting mail, or editing calendar
events is a write. Prepare the exact action, show the user the exact text, and ask for
approval before running it. `send-draft` only ever fires on an explicitly approved
draft.

Calendar event creation after approval:

```bash
curl -sS -X POST 'https://www.googleapis.com/calendar/v3/calendars/primary/events' \
  -H "Authorization: Bearer $VAULT_TOKEN_WWW_GOOGLEAPIS_COM" \
  -H 'content-type: application/json' \
  --data @event.json
```

Always show what changed and keep enough IDs in the workspace to undo or inspect later.

Files in this skill

  • SKILL.md6.3 KB
  • scripts/gmail.py11.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.