Gmail, Calendar, Drive, Contacts, Sheets, and Docs integration via Python. Uses OAuth2 with automatic token refresh. No external binaries needed — runs entirely with Google's Python client libraries in the Gauss venv.
Gmail, Calendar, Drive, Contacts, Sheets, and Docs — all through Python scripts in this skill. No external binaries to install.
references/gmail-search-syntax.md — Gmail search operators (is:unread, from:, newer_than:, etc.)scripts/setup.py — OAuth2 setup (run once to authorize)scripts/google_api.py — API wrapper CLI (agent uses this for all operations)The setup is fully non-interactive — you drive it step by step so it works on CLI, Telegram, Discord, or any platform.
Define a shorthand first:
GSETUP="python ~/.gauss/skills/productivity/google-workspace/scripts/setup.py"
$GSETUP --check
If it prints AUTHENTICATED, skip to Usage — setup is already done.
Before starting OAuth setup, ask the user TWO questions:
Question 1: "What Google services do you need? Just email, or also Calendar/Drive/Sheets/Docs?"
Email only → They don't need this skill at all. Use the himalaya skill
instead — it works with a Gmail App Password (Settings → Security → App
Passwords) and takes 2 minutes to set up. No Google Cloud project needed.
Load the himalaya skill and follow its setup instructions.
Calendar, Drive, Sheets, Docs (or email + these) → Continue with this skill's OAuth setup below.
Question 2: "Does your Google account use Advanced Protection (hardware security keys required to sign in)? If you're not sure, you probably don't — it's something you would have explicitly enrolled in."
Tell the user:
You need a Google Cloud OAuth client. This is a one-time setup:
- Go to https://console.cloud.google.com/apis/credentials
- Create a project (or use an existing one)
- Click "Enable APIs" and enable: Gmail API, Google Calendar API, Google Drive API, Google Sheets API, Google Docs API, People API
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Application type: "Desktop app" → Create
- Click "Download JSON" and tell me the file path
Once they provide the path:
$GSETUP --client-secret /path/to/client_secret.json
$GSETUP --auth-url
This prints a URL. Send the URL to the user and tell them:
Open this link in your browser, sign in with your Google account, and authorize access. After authorizing, you'll be redirected to a page that may show an error — that's expected. Copy the ENTIRE URL from your browser's address bar and paste it back to me.
The user will paste back either a URL like http://localhost:1/?code=4/0A...&scope=...
or just the code string. Either works. The --auth-url step stores a temporary
pending OAuth session locally so --auth-code can complete the PKCE exchange
later, even on headless systems:
$GSETUP --auth-code "THE_URL_OR_CODE_THE_USER_PASTED"
$GSETUP --check
Should print AUTHENTICATED. Setup is complete — token refreshes automatically from now on.
~/.gauss/google_token.json and auto-refreshes.~/.gauss/google_oauth_pending.json until exchange completes.$GSETUP --revokeAll commands go through the API script. Set GAPI as a shorthand:
GAPI="python ~/.gauss/skills/productivity/google-workspace/scripts/google_api.py"
# Search (returns JSON array with id, from, subject, date, snippet)
$GAPI gmail search "is:unread" --max 10
$GAPI gmail search "from:[email protected] newer_than:1d"
$GAPI gmail search "has:attachment filename:pdf newer_than:7d"
# Read full message (returns JSON with body text)
$GAPI gmail get MESSAGE_ID
# Send
$GAPI gmail send --to [email protected] --subject "Hello" --body "Message text"
$GAPI gmail send --to [email protected] --subject "Report" --body "<h1>Q4</h1><p>Details...</p>" --html
# Reply (automatically threads and sets In-Reply-To)
$GAPI gmail reply MESSAGE_ID --body "Thanks, that works for me."
# Labels
$GAPI gmail labels
$GAPI gmail modify MESSAGE_ID --add-labels LABEL_ID
$GAPI gmail modify MESSAGE_ID --remove-labels UNREAD
# List events (defaults to next 7 days)
$GAPI calendar list
$GAPI calendar list --start 2026-03-01T00:00:00Z --end 2026-03-07T23:59:59Z
# Create event (ISO 8601 with timezone required)
$GAPI calendar create --summary "Team Standup" --start 2026-03-01T10:00:00-06:00 --end 2026-03-01T10:30:00-06:00
$GAPI calendar create --summary "Lunch" --start 2026-03-01T12:00:00Z --end 2026-03-01T13:00:00Z --location "Cafe"
$GAPI calendar create --summary "Review" --start 2026-03-01T14:00:00Z --end 2026-03-01T15:00:00Z --attendees "[email protected],[email protected]"
# Delete event
$GAPI calendar delete EVENT_ID
$GAPI drive search "quarterly report" --max 10
$GAPI drive search "mimeType='application/pdf'" --raw-query --max 5
$GAPI contacts list --max 20
# Read
$GAPI sheets get SHEET_ID "Sheet1!A1:D10"
# Write
$GAPI sheets update SHEET_ID "Sheet1!A1:B2" --values '[["Name","Score"],["Alice","95"]]'
# Append rows
$GAPI sheets append SHEET_ID "Sheet1!A:C" --values '[["new","row","data"]]'
$GAPI docs get DOC_ID
All commands return JSON. Parse with jq or read directly. Key fields:
[{id, threadId, from, to, subject, date, snippet, labels}]{id, threadId, from, to, subject, date, labels, body}{status: "sent", id, threadId}[{id, summary, start, end, location, description, htmlLink}]{status: "created", id, summary, htmlLink}[{id, name, mimeType, modifiedTime, webViewLink}][{name, emails: [...], phones: [...]}][[cell, cell, ...], ...]setup.py --check. If it fails, guide the user through setup.skill_view("google-workspace", file_path="references/gmail-search-syntax.md").2026-03-01T10:00:00-06:00) or UTC (Z).| Problem | Fix |
|---|---|
NOT_AUTHENTICATED | Run setup Steps 2-5 above |
REFRESH_FAILED | Token revoked or expired — redo Steps 3-5 |
HttpError 403: Insufficient Permission | Missing API scope — $GSETUP --revoke then redo Steps 3-5 |
HttpError 403: Access Not Configured | API not enabled — user needs to enable it in Google Cloud Console |
ModuleNotFoundError | Run $GSETUP --install-deps |
| Advanced Protection blocks auth | Workspace admin must allowlist the OAuth client ID |
$GSETUP --revoke