
Gws
- 204 installs
- 339 repo stars
- Updated August 4, 2026
- glebis/claude-skills
Automate Google Workspace tasks such as reading mail, calendar events, or Drive files when a feature needs external productivity data or outbound notifications.
About
The gws skill guides Claude Code through Google Workspace integration patterns so agents can query or act on Gmail, Calendar, Drive, and related services while building features that depend on real user productivity data instead of static mocks.
- Connects agent workflows to Google Workspace APIs
- Supports email, calendar, and document automation patterns
- Reduces manual context switching during implementation
- Fits SaaS products that depend on user productivity suites
Gws by the numbers
- 204 all-time installs (skills.sh)
- Ranked #588 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/glebis/claude-skills --skill gwsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 204 |
|---|---|
| repo stars | ★ 339 |
| Last updated | August 4, 2026 |
| Repository | glebis/claude-skills ↗ |
What it does
Automate Google Workspace tasks such as reading mail, calendar events, or Drive files when a feature needs external productivity data or outbound notifications.
Files
Google Workspace CLI (gws)
CLI for Gmail, Calendar, Drive, Sheets, Docs, Slides, Tasks, People, Chat, Meet, Forms, Keep, Admin, and cross-service workflows.
Binary: /opt/homebrew/bin/gws
Command Pattern
gws <service> <resource> [sub-resource] <method> [flags]Every command accepts:
--params <JSON>— URL/query parameters--json <JSON>— request body (POST/PATCH/PUT)--upload <PATH>— file to upload as media content--output <PATH>— path for binary responses (downloads)--format json|table|yaml|csv— output format (default: json)--page-all/--page-limit N— auto-paginate--dry-run— validate locally without sending
Quick Reference — Helper Commands (prefer these)
| Command | Purpose | R/W |
|---|---|---|
gws gmail +triage [--max N] [--query Q] | Unread inbox summary | R |
gws gmail +send --to EMAIL --subject S --body T | Send plaintext email | W |
gws gmail +watch --project GCP | Stream new emails (Pub/Sub) | R |
| `gws calendar +agenda [--today\ | --tomorrow\ | --week\ |
gws calendar +insert --summary T --start ISO --end ISO | Create event | W |
gws drive +upload FILE [--parent ID] [--name N] | Upload file | W |
gws sheets +read --spreadsheet ID --range R | Read range (e.g. Sheet1!A1:D10) | R |
gws sheets +append --spreadsheet ID --values "a,b,c" | Append row (or --json-values) | W |
gws docs +write --document ID --text T | Append text to doc | W |
gws chat +send --space spaces/ID --text T | Post to Chat space | W |
gws workflow +standup-report | Today's meetings + open tasks | R |
gws workflow +meeting-prep [--calendar ID] | Next meeting details | R |
gws workflow +email-to-task --message-id ID | Email → Task | W |
gws workflow +weekly-digest | Week's meetings + unread | R |
gws workflow +file-announce --file-id ID --space SPACE | Announce file in Chat | W |
Common Patterns
Gmail
# Triage unread (table for humans)
gws gmail +triage --max 10 --format table
# Search
gws gmail users messages list --params '{"userId":"me","q":"from:amazon newer_than:7d","maxResults":5}'
# Read full message
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"full"}'
# Read headers only (faster)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"metadata","metadataHeaders":["Subject","From","Date"]}'
# Archive (remove INBOX)
gws gmail users messages modify --params '{"userId":"me","id":"MSG_ID"}' --json '{"removeLabelIds":["INBOX"]}'
# Trash
gws gmail users messages trash --params '{"userId":"me","id":"MSG_ID"}'
# Bulk label
gws gmail users messages batchModify --params '{"userId":"me"}' --json '{"ids":["ID1","ID2"],"addLabelIds":["Label_123"]}'Calendar
# Today (Europe/Berlin default works with RFC3339 +02:00/+01:00)
gws calendar +agenda --today --format table
# Create simple event
gws calendar +insert \
--summary 'AGENCY Meetup' \
--start '2026-04-14T18:00:00+02:00' \
--end '2026-04-14T19:00:00+02:00' \
--location 'https://us02web.zoom.us/j/8991032224' \
--description 'Zoom: https://us02web.zoom.us/j/8991032224'
# Event WITH Google Meet link (helper doesn't support — use raw)
gws calendar events insert \
--params '{"calendarId":"primary","conferenceDataVersion":1}' \
--json '{
"summary":"Sync",
"start":{"dateTime":"2026-04-15T14:00:00+02:00"},
"end":{"dateTime":"2026-04-15T15:00:00+02:00"},
"conferenceData":{"createRequest":{"requestId":"req-'$(date +%s)'","conferenceSolutionKey":{"type":"hangoutsMeet"}}}
}'
# Update event
gws calendar events patch --params '{"calendarId":"primary","eventId":"EID"}' --json '{"summary":"New title"}'
# Delete
gws calendar events delete --params '{"calendarId":"primary","eventId":"EID"}'
# List all calendars
gws calendar calendarList list --format tableDrive
# Upload to root
gws drive +upload ./report.pdf
# Upload to folder
gws drive +upload ./data.csv --parent FOLDER_ID --name 'Sales Data.csv'
# Search files
gws drive files list --params '{"q":"name contains \"report\" and mimeType=\"application/pdf\"","pageSize":10}'
# Download
gws drive files get --params '{"fileId":"FID","alt":"media"}' --output ./local.pdf
# Create folder
gws drive files create --json '{"name":"MyFolder","mimeType":"application/vnd.google-apps.folder"}'
# Share with user
gws drive permissions create --params '{"fileId":"FID"}' --json '{"role":"reader","type":"user","emailAddress":"user@example.com"}'Sheets
# Read
gws sheets +read --spreadsheet SID --range 'Sheet1!A1:D10' --format table
# Append single row (simple values)
gws sheets +append --spreadsheet SID --values 'Alice,100,true'
# Append multiple rows
gws sheets +append --spreadsheet SID --json-values '[["a","b"],["c","d"]]'Tasks
gws tasks tasklists list
gws tasks tasks list --params '{"tasklist":"@default"}'
gws tasks tasks insert --params '{"tasklist":"@default"}' --json '{"title":"My task","notes":"Details","due":"2026-04-20T00:00:00Z"}'
gws tasks tasks patch --params '{"tasklist":"@default","task":"TID"}' --json '{"status":"completed"}'Chat
# Find space
gws chat spaces list --format table
# Post message
gws chat +send --space spaces/AAAAxxxx --text 'Hello team!'People / Contacts
gws people people connections list --params '{"resourceName":"people/me","personFields":"names,emailAddresses","pageSize":100}'
gws people people searchContacts --params '{"query":"John","readMask":"names,emailAddresses"}'Critical Notes
- userId: Every Gmail raw call needs
"userId":"me"in params. - RFC3339 times: Calendar uses full ISO with offset (
2026-04-14T18:00:00+02:00). "Z" for UTC. - Meet links:
+insertdoes NOT add conferencing — use rawevents.insertwithconferenceDataVersion=1andconferenceData.createRequest. - Pagination:
--page-allemits NDJSON (one JSON object per page).--page-limit Ncaps pages. - Schema discovery:
gws schema <service>.<resource>.<method>— e.g.gws schema gmail.users.messages.list. - Filters:
gmail.settings.basicscope required — special manual OAuth flow (seereferences/api_reference.md). - Write confirmation: Always confirm with user before
+send,+insert,+email-to-task,+file-announce,drive files delete,events delete,messages trash. - Format choice:
--format tablefor human-readable summaries; defaultjsonfor scripting/piping tojq.
OAuth Setup
- GCP project:
n8n-automations-454016 - Credentials:
~/.config/gws/credentials.json - Configured scopes:
gmail.modify,gmail.settings.basic,drive,spreadsheets,tasks,calendar,documents,chat.messages,contacts.readonly gmail.settings.basicscope needs manual OAuth (Python localhost listener on port 8085) —gws auth login --scopescannot request it directly.
Full API Reference
For full command inventory, all raw API calls, pagination, labels, drafts, filters, and admin APIs, see references/api_reference.md.
{
"name": "gws",
"description": "This skill should be used when interacting with Google Workspace services via the gws CLI \u2014 Gmail (search, triage, send,",
"author": {
"name": "Gleb Kalinin"
},
"repository": "https://github.com/glebis/claude-skills",
"license": "MIT"
}GWS CLI — Full API Reference
Global Flags (all commands)
--params <JSON> URL/Query parameters as JSON
--json <JSON> Request body as JSON (POST/PATCH/PUT)
--upload <PATH> Local file to upload as media content (multipart)
--output <PATH> Output file path for binary responses
--format <FMT> Output format: json (default), table, yaml, csv
--api-version <VER> Override the API version
--page-all Auto-paginate, one JSON line per page (NDJSON)
--page-limit <N> Max pages to fetch with --page-all (default: 10)
--page-delay <MS> Delay between pages in ms (default: 100)
--sanitize <TEMPLATE> Sanitize via Model Armor template
--dry-run Validate locally without sendingGmail
Helper Commands
gws gmail +triage
Show unread inbox summary (sender, subject, date). Read-only.
--max <N> Maximum messages (default: 20)
--query <QUERY> Gmail search query (default: is:unread)
--labels Include label names in output
--format <FORMAT> Output format (defaults to table)Examples:
gws gmail +triage
gws gmail +triage --max 5 --query 'from:boss'
gws gmail +triage --format json | jq '.[].subject'
gws gmail +triage --labelsgws gmail +send
Send an email. Handles RFC 2822 formatting and base64 encoding automatically.
--to <EMAIL> Recipient email address (required)
--subject <SUBJECT> Email subject (required)
--body <TEXT> Email body plain text (required)Examples:
gws gmail +send --to alice@example.com --subject 'Hello' --body 'Hi Alice!'For HTML bodies, attachments, or CC/BCC, use the raw API: gws gmail users messages send --json '...'
gws gmail +watch
Watch for new emails and stream them as NDJSON. Requires GCP project with Pub/Sub.
--project <PROJECT> GCP project ID for Pub/Sub
--subscription <NAME> Existing Pub/Sub subscription (skip setup)
--topic <TOPIC> Existing Pub/Sub topic
--label-ids <LABELS> Comma-separated Gmail label IDs to filter
--max-messages <N> Max messages per pull batch (default: 10)
--poll-interval <SECS> Seconds between pulls (default: 5)
--msg-format <FORMAT> full, metadata, minimal, raw (default: full)
--once Pull once and exit
--cleanup Delete created Pub/Sub resources on exit
--output-dir <DIR> Write each message to a separate JSON fileRaw API
All raw API calls require userId in params (use "me" for authenticated user).
Messages
- List:
gws gmail users messages list --params '{"userId": "me", "q": "search query", "maxResults": 10}' - Get:
gws gmail users messages get --params '{"userId": "me", "id": "MSG_ID", "format": "full"}' - format options:
full,metadata,minimal,raw - For metadata only: add
"metadataHeaders": ["Subject", "From", "Date"] - Send:
gws gmail users messages send --json '{"raw": "base64_encoded_message"}' - Trash:
gws gmail users messages trash --params '{"userId": "me", "id": "MSG_ID"}' - Modify labels:
gws gmail users messages modify --params '{"userId": "me", "id": "MSG_ID"}' --json '{"addLabelIds": ["LABEL_ID"], "removeLabelIds": ["INBOX"]}' - Batch modify:
gws gmail users messages batchModify --params '{"userId": "me"}' --json '{"ids": ["MSG1", "MSG2"], "addLabelIds": ["LABEL"]}'
Labels
- List:
gws gmail users labels list --params '{"userId": "me"}' - Create:
gws gmail users labels create --params '{"userId": "me"}' --json '{"name": "MyLabel", "labelListVisibility": "labelShow", "messageListVisibility": "show"}'
Threads
- List:
gws gmail users threads list --params '{"userId": "me", "q": "search query"}' - Get:
gws gmail users threads get --params '{"userId": "me", "id": "THREAD_ID"}'
Drafts
- List:
gws gmail users drafts list --params '{"userId": "me"}' - Create:
gws gmail users drafts create --params '{"userId": "me"}' --json '{"message": {"raw": "base64"}}'
Settings / Filters
- List filters:
gws gmail users settings filters list --params '{"userId": "me"}' - Create filter:
gws gmail users settings filters create --params '{"userId": "me"}' --json '{"criteria": {"from": "sender@example.com"}, "action": {"addLabelIds": ["LABEL_ID"], "removeLabelIds": ["INBOX"]}}' - Note: Requires
gmail.settings.basicscope
Profile
- Get:
gws gmail users getProfile --params '{"userId": "me"}'
Calendar
Helper Commands
gws calendar +agenda
Show upcoming events across all calendars. Read-only.
--today Show today's events
--tomorrow Show tomorrow's events
--week Show this week's events
--days <N> Number of days ahead
--calendar <NAME> Filter to specific calendar name or ID
--format <FORMAT> Output format (defaults to table for readability)Examples:
gws calendar +agenda --today
gws calendar +agenda --week --format table
gws calendar +agenda --days 3 --calendar 'Work'gws calendar +insert
Create a new event.
--summary <TEXT> Event title (required)
--start <TIME> Start time ISO 8601 / RFC3339 (required)
--end <TIME> End time ISO 8601 / RFC3339 (required)
--calendar <ID> Calendar ID (default: primary)
--location <TEXT> Event location
--description <TEXT> Event description
--attendee <EMAIL> Attendee (repeatable)Examples:
gws calendar +insert --summary 'Standup' --start '2026-06-17T09:00:00+02:00' --end '2026-06-17T09:30:00+02:00'
gws calendar +insert --summary 'Review' --start ... --end ... --attendee alice@example.comFor recurring events or conference links, use the raw API.
Raw API
- List events:
gws calendar events list --params '{"calendarId": "primary", "timeMin": "2026-04-10T00:00:00Z", "maxResults": 10, "singleEvents": true, "orderBy": "startTime"}' - Get event:
gws calendar events get --params '{"calendarId": "primary", "eventId": "EVENT_ID"}' - Insert event:
gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "...", "start": {"dateTime": "..."}, "end": {"dateTime": "..."}}' - Insert event with Google Meet link (helper doesn't support this):
gws calendar events insert \
--params '{"calendarId":"primary","conferenceDataVersion":1}' \
--json '{"summary":"Sync","start":{"dateTime":"2026-04-15T14:00:00+02:00"},"end":{"dateTime":"2026-04-15T15:00:00+02:00"},"conferenceData":{"createRequest":{"requestId":"unique-id-123","conferenceSolutionKey":{"type":"hangoutsMeet"}}}}'- Recurring event: add
"recurrence":["RRULE:FREQ=WEEKLY;BYDAY=MO;COUNT=10"]to event body - Add attendees and send invites:
--params '{"calendarId":"primary","sendUpdates":"all"}'with"attendees":[{"email":"a@b.com"}]in body - Update event:
gws calendar events patch --params '{"calendarId": "primary", "eventId": "EVENT_ID"}' --json '{"summary": "Updated"}' - Delete event:
gws calendar events delete --params '{"calendarId": "primary", "eventId": "EVENT_ID"}' - List calendars:
gws calendar calendarList list - Free/busy lookup:
gws calendar freebusy query --json '{"timeMin":"...","timeMax":"...","items":[{"id":"primary"}]}'
Drive
Helper Commands
gws drive +upload
Upload a file with automatic metadata. MIME type auto-detected.
<file> Path to file (required, positional)
--parent <ID> Parent folder ID
--name <NAME> Target filename (defaults to source filename)Examples:
gws drive +upload ./report.pdf
gws drive +upload ./report.pdf --parent FOLDER_ID
gws drive +upload ./data.csv --name 'Sales Data.csv'Raw API
- List files:
gws drive files list --params '{"q": "name contains \"report\"", "pageSize": 10}' - Get file metadata:
gws drive files get --params '{"fileId": "FILE_ID"}' - Download file:
gws drive files get --params '{"fileId": "FILE_ID", "alt": "media"}' --output ./downloaded_file.pdf - Create folder:
gws drive files create --json '{"name": "MyFolder", "mimeType": "application/vnd.google-apps.folder"}' - Delete file:
gws drive files delete --params '{"fileId": "FILE_ID"}' - Share file:
gws drive permissions create --params '{"fileId": "FILE_ID"}' --json '{"role": "reader", "type": "user", "emailAddress": "user@example.com"}'
Sheets
Helper Commands
gws sheets +read
Read values from a range. Read-only.
--spreadsheet <ID> Spreadsheet ID (required)
--range <RANGE> A1 notation (e.g. 'Sheet1!A1:D10')Examples:
gws sheets +read --spreadsheet SID --range 'Sheet1!A1:D10' --format table
gws sheets +read --spreadsheet SID --range Sheet1gws sheets +append
Append row(s). Simple strings via --values or structured via --json-values.
--spreadsheet <ID> Spreadsheet ID (required)
--values <CSV> Comma-separated single row
--json-values <JSON> 2D array of rowsExamples:
gws sheets +append --spreadsheet SID --values 'Alice,100,true'
gws sheets +append --spreadsheet SID --json-values '[["a","b"],["c","d"]]'Raw API
- Get spreadsheet metadata:
gws sheets spreadsheets get --params '{"spreadsheetId":"SID"}' - Create spreadsheet:
gws sheets spreadsheets create --json '{"properties":{"title":"My Sheet"}}' - Read values:
gws sheets spreadsheets values get --params '{"spreadsheetId":"SID","range":"Sheet1!A1:D10"}' - Write values (overwrite):
gws sheets spreadsheets values update --params '{"spreadsheetId":"SID","range":"Sheet1!A1","valueInputOption":"USER_ENTERED"}' --json '{"values":[["a","b"]]}' - Clear range:
gws sheets spreadsheets values clear --params '{"spreadsheetId":"SID","range":"Sheet1!A1:Z1000"}' - Batch update (formatting, formulas):
gws sheets spreadsheets batchUpdate --params '{"spreadsheetId":"SID"}' --json '{"requests":[...]}'
Chat
Helper Commands
gws chat +send
Send plaintext message to a Chat space.
--space <NAME> e.g. spaces/AAAAxxxx
--text <TEXT> Message bodyRaw API
- List spaces:
gws chat spaces list - Get space:
gws chat spaces get --params '{"name":"spaces/AAAA"}' - Send card / threaded reply:
gws chat spaces messages create --params '{"parent":"spaces/AAAA"}' --json '{"text":"hi","thread":{"threadKey":"mykey"}}' - List messages:
gws chat spaces messages list --params '{"parent":"spaces/AAAA"}'
Meet
- List conferences:
gws meet spaces get --params '{"name":"spaces/SID"}' - Create meeting:
gws meet spaces create --json '{}'(returns a new Meet space with join URL)
Tasks
- List task lists:
gws tasks tasklists list - List tasks:
gws tasks tasks list --params '{"tasklist": "@default"}' - Create task:
gws tasks tasks insert --params '{"tasklist": "@default"}' --json '{"title": "My task", "notes": "Details"}' - Complete task:
gws tasks tasks patch --params '{"tasklist": "@default", "task": "TASK_ID"}' --json '{"status": "completed"}'
Docs
Helper Commands
gws docs +write
Append text to a document.
Raw API
- Get doc:
gws docs documents get --params '{"documentId": "DOC_ID"}' - Batch update:
gws docs documents batchUpdate --params '{"documentId": "DOC_ID"}' --json '{"requests": [...]}'
People (Contacts)
- List contacts:
gws people people connections list --params '{"resourceName": "people/me", "personFields": "names,emailAddresses"}' - Search:
gws people people searchContacts --params '{"query": "John", "readMask": "names,emailAddresses"}'
Workflow (Cross-Service Helpers)
gws workflow +standup-report
Today's meetings + open tasks as a standup summary. Read-only.
gws workflow +meeting-prep
Prepare for next meeting: agenda, attendees, linked docs. Read-only.
--calendar <ID> Calendar ID (default: primary)gws workflow +email-to-task
Convert a Gmail message into a Google Tasks entry. Write command — confirm before executing.
--message-id <ID> Gmail message ID to convert (required)
--tasklist <ID> Task list ID (default: @default)gws workflow +weekly-digest
Weekly summary: this week's meetings + unread email count. Read-only.
gws workflow +file-announce
Announce a Drive file in a Chat space. Write command.
--file-id <ID> Drive file ID (required)
--space <SPACE> Chat space name (required)
--message <TEXT> Custom announcement messageSchema Introspection
Discover API parameters and request body schemas:
gws schema gmail.users.messages.list
gws schema drive.files.list --resolve-refs
gws schema calendar.events.insertFormat: service.resource.method or service.Resource.method
All Available Services
gmail, calendar, drive, sheets, docs, slides, tasks, people, chat, vault, admin (directory), admin-reports (reports), groupssettings, reseller, licensing, apps-script (script), classroom, cloudidentity, alertcenter, forms, keep, meet, events, modelarmor, workflow (wf)