---
name: google-workspace
description: Unified Google Workspace skill — Gmail, Calendar, Contacts, Drive, Docs, Sheets, and Photos.
---
# Google Workspace Skill
Unified Google Workspace management for AI agents. One skill, one auth, seven services.
> **Replaces**: `gmail`, `google-calendar`, `google-contacts`, `google-drive`, `google-photos`
> Run `scripts/upgrade.sh` to migrate from the old per-service skills.
## Services
| Service | Script | Capabilities |
| ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Gmail** | `scripts/gmail.py` | Search, read, thread, draft, send, reply, reply-all, forward, trash, filters, empty-trash/spam |
| **Calendar** | `scripts/google_calendar.py` | List, get, search, create (RRULE), update, delete, quick-add, secondary calendars, Drive attachments |
| **Contacts** | `scripts/contacts.py` | Search, list, get, create, update, delete contacts |
| **Drive** | `scripts/google_drive.py` | List, search, upload, download, export, mkdir, move, copy, rename, trash, delete, empty-trash, share, revisions, comments |
| **Docs** | `scripts/google_docs.py` | Read text, create, append, replace, insert-heading, format-text, insert-image, comments |
| **Sheets** | `scripts/google_sheets.py` | Read, create, append, update, clear, tabs, format-range, freeze-panes, auto-resize |
| **Photos** | `scripts/google_photos.py` | List, search, download, upload media, manage albums |
## Prerequisites
1. **Google Cloud Project** with these APIs enabled:
- Gmail API
- Google Calendar API
- Google People API
- Google Drive API
- Google Docs API
- Google Sheets API
- Photos Library API
2. **OAuth 2.0 Credentials** — Desktop app client (`credentials.json`).
## Setup
### One-Time Setup (all services at once)
```bash
uv run scripts/setup_workspace.py
```
This authenticates once with all scopes and stores a unified token at `~/.google_workspace/`.
### Manual Setup (gcloud ADC)
```bash
gcloud auth application-default login \
--scopes https://mail.google.com/,\
https://www.googleapis.com/auth/calendar,\
https://www.googleapis.com/auth/contacts,\
https://www.googleapis.com/auth/drive,\
https://www.googleapis.com/auth/documents,\
https://www.googleapis.com/auth/spreadsheets,\
https://www.googleapis.com/auth/photoslibrary,\
https://www.googleapis.com/auth/photoslibrary.sharing,\
https://www.googleapis.com/auth/cloud-platform
```
### Verify
```bash
uv run scripts/gmail.py verify
uv run scripts/google_calendar.py verify
uv run scripts/contacts.py verify
uv run scripts/google_drive.py verify
uv run scripts/google_docs.py verify
uv run scripts/google_sheets.py verify
uv run scripts/google_photos.py verify
```
## Credential Lookup Order
Every script checks credentials in this order:
1. **Service-specific env var** (e.g., `GMAIL_CREDENTIALS_DIR`) — for overrides.
2. **Unified directory** `~/.google_workspace/` — primary location.
3. **Legacy per-service directory** (e.g., `~/.gmail_credentials/`) — backward compat.
No migration required. If you already have legacy credentials, they still work.
---
## 🛑 Notice: No More SQLite Cache
The local SQLite caching system (`scripts/cache.py`) has been **removed** in favor of live API queries.
**Do not** attempt to use `cache.py`, `sync`, or `search` against a local database. Always use the live API commands provided by the individual service scripts (e.g., `gmail.py search --query "..."`).
---
## Gmail
Full CRUD Gmail management. Search, read, compose, reply, forward, and manage messages.
### Search for Emails
```bash
# Unread emails from a sender
uv run scripts/gmail.py search --query "from:obiwan@jedi.org is:unread"
# Emails with attachments
uv run scripts/gmail.py search --query "has:attachment subject:plans" --limit 5
```
### Read a Message / Thread
```bash
uv run scripts/gmail.py read --id "18e..."
uv run scripts/gmail.py thread --id "18e..."
# Prefer HTML body
uv run scripts/gmail.py read --id "18e..." --html
```
### Create a Draft
**Safest option** — creates a draft for the user to review before sending.
```bash
uv run scripts/gmail.py draft \
--to "yoda@dagobah.net" \
--subject "Training Schedule" \
--body "Master, when shall we begin the next session?" \
--cc "mace@jedi.org"
# Create HTML draft
uv run scripts/gmail.py draft --to "yoda@dagobah.net" --subject "HTML Test" --body "Bold" --html
```
### Send an Email
```bash
uv run scripts/gmail.py send \
--to "yoda@dagobah.net" \
--subject "Urgent: Sith Sighting" \
--body "Master, I sense a disturbance in the Force."
# Send HTML
uv run scripts/gmail.py send --to "yoda@dagobah.net" --subject "HTML" --body "
Alert
" --html
```
### Reply / Reply All / Forward
```bash
# Reply (draft by default, --send for immediate)
uv run scripts/gmail.py reply --id "18e..." --body "Acknowledged." --send
# Reply with HTML
uv run scripts/gmail.py reply --id "18e..." --body "Agreed." --send --html
# Reply all
uv run scripts/gmail.py reply-all --id "18e..." --body "Council noted." --send
# Forward
uv run scripts/gmail.py forward --id "18e..." --to "luke@tatooine.net" --body "FYI"
uv run scripts/gmail.py forward --id "18e..." --to "luke@tatooine.net" --send
```
### Trash / Labels / Attachments / Filters
```bash
uv run scripts/gmail.py trash --id "18e..."
uv run scripts/gmail.py untrash --id "18e..."
# Empty Trash or Spam (permanent — no recovery)
uv run scripts/gmail.py empty-trash
uv run scripts/gmail.py empty-spam
uv run scripts/gmail.py labels
uv run scripts/gmail.py modify-labels --id "18e..." --add STARRED --remove UNREAD
uv run scripts/gmail.py attachments --id "18e..." --output-dir ./downloads
# Filters — auto-route or label incoming mail
uv run scripts/gmail.py list-filters
uv run scripts/gmail.py create-filter \
--from "noreply@galactic-senate.gov" --archive --mark-read
uv run scripts/gmail.py create-filter \
--subject "URGENT" --add-label "IMPORTANT"
uv run scripts/gmail.py delete-filter --filter-id "ANe1BmhV..."
```
### Safety Guidelines
1. **Prefer `draft` over `send`** for new compositions — let the user review first.
2. **Reply/Forward defaults to draft** — use `--send` only when explicitly requested.
3. **Trash is reversible** — `empty-trash` is permanent, so confirm intent.
---
## Token Maintenance & Persistence
### 7-Day Expiry Fix (Important)
If you are using a personal Gmail account with a "Testing" GCP project, your refresh token will expire every 7 days.
To fix this, follow the guide at `references/GCP_SETUP.md` to set up a proper app or use an Internal app (Workspace users).
### Background Refresh
To keep your 1-hour access token fresh and avoid CLI latency:
```bash
# Install the maintenance service
cp scripts/workspace-token-maintainer.service ~/.config/systemd/user/
cp scripts/workspace-token-maintainer.timer ~/.config/systemd/user/
systemctl --user enable --now workspace-token-maintainer.timer
```
This runs `scripts/maintain_token.py` every 45 minutes to refresh the token on disk.
---
## Calendar
Full CRUD Calendar management. List, create, update, delete, and search events.
### List / Search Events
```bash
# Next 5 events
uv run scripts/google_calendar.py list --limit 5
# Events in a date range
uv run scripts/google_calendar.py list \
--after "2026-02-16T00:00:00Z" --before "2026-02-22T23:59:59Z"
# Search by text
uv run scripts/google_calendar.py search --query "Training" --limit 5
```
### Create / Update / Delete Events
```bash
# Timed event
uv run scripts/google_calendar.py create \
--summary "Jedi Council Meeting" \
--start "2026-05-04T10:00:00" --end "2026-05-04T11:00:00" \
--location "Council Chamber, Coruscant" \
--attendees yoda@dagobah.net mace@jedi.org
# All-day event
uv run scripts/google_calendar.py create \
--summary "May the 4th" --start "2026-05-04" --end "2026-05-05" --all-day
# Recurring event (RRULE — RFC 5545)
uv run scripts/google_calendar.py create \
--summary "Weekly Stand-up" \
--start "2026-03-03T09:00:00" --end "2026-03-03T09:30:00" \
--rrule "RRULE:FREQ=WEEKLY;BYDAY=MO"
uv run scripts/google_calendar.py create \
--summary "Monthly Report" \
--start "2026-03-01T14:00:00" --end "2026-03-01T15:00:00" \
--rrule "RRULE:FREQ=MONTHLY;BYMONTHDAY=1;COUNT=12"
# Event with Drive file attachment
uv run scripts/google_calendar.py create \
--summary "Design Review" \
--start "2026-03-10T14:00:00" --end "2026-03-10T15:00:00" \
--drive-files "FILE_ID_1" "FILE_ID_2"
# Update (patch semantics — only provided fields change)
uv run scripts/google_calendar.py update --id "abc123" --summary "Updated Meeting"
# Delete
uv run scripts/google_calendar.py delete --id "abc123"
```
### Quick Add / Calendar Management
```bash
uv run scripts/google_calendar.py quick --text "Lunch with Padme tomorrow at noon"
# List all calendars
uv run scripts/google_calendar.py calendars
# Subscribe to a secondary calendar (e.g. public holiday calendar)
uv run scripts/google_calendar.py add-calendar \
--calendar-id "en.usa#holiday@group.v.calendar.google.com"
# Unsubscribe
uv run scripts/google_calendar.py remove-calendar \
--calendar-id "en.usa#holiday@group.v.calendar.google.com"
```
---
## Contacts
Full CRUD Contacts management via the People API.
### Search / List / Get
```bash
uv run scripts/contacts.py search --query "Han Solo"
uv run scripts/contacts.py list --limit 50
uv run scripts/contacts.py get --id "people/c12345"
```
### Create / Update / Delete
```bash
uv run scripts/contacts.py create \
--first "Lando" --last "Calrissian" \
--email "lando@cloudcity.com" --phone "555-0123" \
--org "Cloud City Administration" --title "Baron Administrator"
# Update (patch semantics, etag-based conflict detection)
uv run scripts/contacts.py update --id "people/c12345" --phone "555-9999" --title "General"
uv run scripts/contacts.py delete --id "people/c12345"
```
---
## Drive
Full CRUD Drive management. List, search, upload, download, export, organize, and share files.
### List / Search / Get
```bash
uv run scripts/google_drive.py list
uv run scripts/google_drive.py list --folder "FOLDER_ID" --limit 20
uv run scripts/google_drive.py search --query "Death Star plans"
uv run scripts/google_drive.py search --query "budget" --mime-type "application/vnd.google-apps.spreadsheet"
uv run scripts/google_drive.py get --id "FILE_ID"
```
### Upload / Download / Export
```bash
uv run scripts/google_drive.py upload --file "./blueprints.pdf" --folder "FOLDER_ID"
uv run scripts/google_drive.py download --id "FILE_ID" --output "./local_copy.pdf"
# Export Google Workspace docs
uv run scripts/google_drive.py export --id "DOC_ID" --output "./report.docx" --format docx
uv run scripts/google_drive.py export --id "SHEET_ID" --output "./data.csv" --format csv
```
**Export Formats**: Google Docs (pdf, docx, txt, html, md), Sheets (pdf, xlsx, csv), Slides (pdf, pptx), Drawings (pdf, png, svg).
### Organize (mkdir, move, copy, rename)
```bash
uv run scripts/google_drive.py mkdir --name "Project Stardust" --parent "PARENT_ID"
uv run scripts/google_drive.py move --id "FILE_ID" --to "DEST_FOLDER_ID"
uv run scripts/google_drive.py copy --id "FILE_ID" --name "Copy of Plans"
uv run scripts/google_drive.py rename --id "FILE_ID" --name "Updated Plans v2"
```
### Trash / Delete / Share / Revisions / Comments
```bash
# Soft delete (reversible)
uv run scripts/google_drive.py trash --id "FILE_ID"
uv run scripts/google_drive.py untrash --id "FILE_ID"
# Empty entire trash (permanent, no recovery)
uv run scripts/google_drive.py empty-trash
# Permanent delete of a specific file
uv run scripts/google_drive.py delete --id "FILE_ID"
# Share
uv run scripts/google_drive.py share --id "FILE_ID" --email "luke@tatooine.net" --role writer
uv run scripts/google_drive.py share --id "FILE_ID" --type anyone --role reader
uv run scripts/google_drive.py permissions --id "FILE_ID"
uv run scripts/google_drive.py unshare --id "FILE_ID" --permission-id "PERM_ID"
# Revision history
uv run scripts/google_drive.py list-revisions --id "FILE_ID"
uv run scripts/google_drive.py restore-revision --id "FILE_ID" --revision-id "REV_ID"
# Comments
uv run scripts/google_drive.py list-comments --id "FILE_ID"
uv run scripts/google_drive.py add-comment --id "FILE_ID" --content "LGTM, approved."
```
---
## Docs
Google Docs content manipulation. Read text, create documents, and modify text.
### Read / Create
```bash
# Read text from a document
uv run scripts/google_docs.py read --id "DOC_ID"
# Create a new document
uv run scripts/google_docs.py create --title "Project Requirements"
```
### Edit Text
```bash
# Append text to the end of the document
uv run scripts/google_docs.py append --id "DOC_ID" --text "Additional requirements:\n1. Must be fast."
# Replace text
uv run scripts/google_docs.py replace --id "DOC_ID" --old "[COMPANY_NAME]" --new "Acme Corp"
# Insert a heading
uv run scripts/google_docs.py insert-heading --id "DOC_ID" --text "Project Overview" --level 1
# Format a text range (index-based)
uv run scripts/google_docs.py format-text --id "DOC_ID" --start 0 --end 20 --bold
uv run scripts/google_docs.py format-text --id "DOC_ID" --start 0 --end 20 --italic --underline
# Insert a public image
uv run scripts/google_docs.py insert-image --id "DOC_ID" --uri "https://example.com/banner.png"
```
### Comments
```bash
uv run scripts/google_docs.py list-comments --id "DOC_ID"
uv run scripts/google_docs.py add-comment --id "DOC_ID" --content "Please review this section."
```
---
## Sheets
Google Sheets manipulation. Read, append, update, and clear ranges.
### Read / Create
```bash
# Read values from a specific range
uv run scripts/google_sheets.py read --id "SHEET_ID" --range "Sheet1!A1:D10"
# Create a new spreadsheet
uv run scripts/google_sheets.py create --title "Q3 Budget"
```
### Update / Append / Clear / Format
```bash
# Append a row (expects a 2D JSON array)
uv run scripts/google_sheets.py append --id "SHEET_ID" --range "Sheet1!A:A" --values '[["2026-03-01", "Rent", 1200]]'
# Update a specific range
uv run scripts/google_sheets.py update --id "SHEET_ID" --range "Sheet1!A2:C2" --values '[["2026-03-02", "Utilities", 150]]'
# Clear a range
uv run scripts/google_sheets.py clear --id "SHEET_ID" --range "Sheet1!A2:D10"
# Worksheet tab management
uv run scripts/google_sheets.py list-sheets --id "SHEET_ID"
uv run scripts/google_sheets.py add-sheet --id "SHEET_ID" --title "February"
uv run scripts/google_sheets.py rename-sheet --id "SHEET_ID" --title "January" --new-title "Jan 2026"
uv run scripts/google_sheets.py delete-sheet --id "SHEET_ID" --title "February"
# Format a range (bold header, background color)
uv run scripts/google_sheets.py format-range \
--id "SHEET_ID" --range "Sheet1!A1:D1" --bold --background-color "#4A90D9"
# Freeze the first row and first column
uv run scripts/google_sheets.py freeze-panes --id "SHEET_ID" --rows 1 --cols 1
# Auto-resize columns to fit content
uv run scripts/google_sheets.py auto-resize --id "SHEET_ID" --range "Sheet1!A:D"
```
---
## Photos
Google Photos management. Browse, search, download, upload, and organize albums.
> **API Limitation**: The Photos Library API only allows modifying media items uploaded by this application.
### List / Search / Get / Download
```bash
uv run scripts/google_photos.py list
uv run scripts/google_photos.py search --date-start "2026-01-01" --date-end "2026-02-16"
uv run scripts/google_photos.py search --categories LANDSCAPES FOOD
uv run scripts/google_photos.py get --id "MEDIA_ID"
uv run scripts/google_photos.py download --id "MEDIA_ID" --output "./sunset.jpg"
```
**Search Categories**: ANIMALS, ARTS, BIRTHDAYS, CITYSCAPES, CRAFTS, DOCUMENTS, FASHION, FLOWERS, FOOD, GARDENS, HOLIDAYS, HOUSES, LANDMARKS, LANDSCAPES, NIGHT, PEOPLE, PERFORMANCES, PETS, RECEIPTS, SCREENSHOTS, SELFIES, SPORT, TRAVEL, UTILITY, WEDDINGS, WHITEBOARDS.
### Upload
```bash
uv run scripts/google_photos.py upload \
--file "./hologram.jpg" --description "Leia's holographic message" --album "ALBUM_ID"
```
### Albums
```bash
uv run scripts/google_photos.py albums
uv run scripts/google_photos.py album-get --id "ALBUM_ID"
uv run scripts/google_photos.py album-create --title "Tatooine Sunsets"
uv run scripts/google_photos.py album-add --album "ALBUM_ID" --items "ITEM_1" "ITEM_2"
uv run scripts/google_photos.py album-remove --album "ALBUM_ID" --items "ITEM_1"
```
---
## Upgrading from v1 (per-service skills)
If you previously installed the separate `gmail`, `google-calendar`, `google-contacts`, `google-drive`, and/or `google-photos` skills:
```bash
# Dry run — shows what will change without modifying anything
bash scripts/upgrade.sh --dry-run
# Run the migration
bash scripts/upgrade.sh
```
The upgrade script:
1. **Consolidates credentials** — copies `token.json` and `credentials.json` from any legacy dir (`~/.gmail_credentials/`, etc.) into `~/.google_workspace/`.
2. **Removes old skill installations** — deletes old per-service skill directories from `.agent/skills/` if present.
3. **Preserves legacy dirs** — does not delete `~/.gmail_credentials/` etc., so existing tools that depend on them still work.
4. **Verifies auth** — confirms the unified token works for all services.
---
## JSON Output
All commands produce JSON for easy parsing. See the individual service sections above for output schemas.