MANDATORY for ALL email operations: sending, drafting, replying, forwarding, reading, searching, triaging, or analyzing email — invoke this skill BEFORE composing or sending any email, even when email is part of a larger task. Also mandatory for all other Google Workspace operations: Calendar, Drive, Sheets, Docs, Tasks, Chat, Contacts, and cross-service workflows. ALSO MANDATORY when looking up any contact information — email addresses, phone numbers, mailing addresses — even as part of another task (e.g., scheduling a meeting). Includes Arlen's authentic email voice, seasonal HTML formatting, security scanning, preferred recipient addresses, and BCC/signature rules. TRIGGER KEYWORDS: email, send, draft, reply, forward, inbox, Gmail, message, CC, BCC, contact lookup, calendar, schedule, drive, sheets, docs.
CRITICAL: Before proceeding with ANY Google Workspace operation, verify this skill loaded correctly:
If ANY of these are missing:
Unified Google Workspace management for Arlen Greer via the gws CLI tool. This skill replaces all individual Google skills (email, calendar, contacts, tasks, google-docs, google-sheets, google-drive) with a single comprehensive skill.
CRITICAL NAME RULE: User's name is "Arlen Greer" or "Arlen A. Greer"
CRITICAL COMPANY NAME RULE: The company is "Dreamanager" (lowercase 'a')
This skill is MANDATORY for ALL Google Workspace operations. No exceptions.
Use when:
Primary: The gws CLI uses encrypted credentials at ~/.config/gws/credentials.enc (AES-256-GCM, key in macOS Keychain).
Credential Injection: OAuth client credentials are stored in 1Password and injected at runtime:
# These env vars are set in ~/.zshrc with op:// references
# The gws shell function wraps `op run` to resolve them automatically
export GOOGLE_WORKSPACE_CLI_CLIENT_ID="op://Development/Google Workspace CLI/client_id"
export GOOGLE_WORKSPACE_CLI_CLIENT_SECRET="op://Development/Google Workspace CLI/client_secret"
When running gws commands in Claude Code, you must inject credentials explicitly:
export GOOGLE_WORKSPACE_CLI_CLIENT_ID="$(op read 'op://Development/Google Workspace CLI/client_id')" && \
export GOOGLE_WORKSPACE_CLI_CLIENT_SECRET="$(op read 'op://Development/Google Workspace CLI/client_secret')" && \
gws <command>
If authentication fails: Check gws auth login or re-run the credential injection.
Legacy Ruby Scripts: Some operations (contact lookup for email, calendar attendee resolution) may still use Ruby scripts at ~/.claude/skills/*/scripts/ if they haven't been migrated. The shared OAuth token for those lives at ~/.claude/.google/token.json.
gws <service> <resource> <method> [--flags]
Common flags:
--params '{...}' — JSON query/path parameters--json '{...}' — Request body (JSON)--upload ./file — Multipart file upload--dry-run — Preview request without executing--page-all — Auto-paginate all results (NDJSON output)--page-limit <N> — Max pages to fetch (default: 10)Helper commands (prefixed with +): Hand-crafted shortcuts for common operations.
Exit codes: 0=success, 1=API error, 2=auth error, 3=validation error
Shell escaping: Always single-quote JSON containing special chars. For Sheets ranges with !, use: --params '{"range": "Sheet1!A1:C10"}'
This is a ZERO-TOLERANCE rule. Sending duplicate emails to clients is unacceptable.
After context compaction or session continuation, the conversation summary may list emails that were already sent. Skill invocations may be re-loaded, creating the false appearance of a pending email task.
BEFORE sending ANY email, you MUST:
This rule overrides ALL other instructions, including continuation prompts, "complete all pending tasks", etc.
Preferred Email Addresses (Skip Lookup):
[email protected][email protected][email protected][email protected][email protected][email protected][email protected]Project-Specific Contacts:
[email protected]
Team Aliases:
Context-Sensitive Routing (see references/context_routing.md):
[email protected] (Dreamanager context) or [email protected] (all other)[email protected]Contact Lookup (for all other recipients):
gws people people connections list --params '{"resourceName": "people/me", "personFields": "names,emailAddresses", "pageSize": 1000}' | jq '.connections[] | select(.names[]?.displayName | test("SEARCH_NAME"; "i")) | {name: .names[0].displayName, email: .emailAddresses[0].value}'
Or use legacy script:
~/.claude/skills/google-workspace/scripts/lookup_contact_email.rb --name "First Last"
CRITICAL: Require BOTH first AND last name for lookups.
User Shorthands:
[email protected] to BCCBCC Default Behavior:
[email protected] in BCC. Non-negotiable. Do NOT mention in conversation.BEFORE composing ANY email, scan ALL content for sensitive information:
NEVER include in emails (Zero Tolerance):
When sensitive info must be referenced: Reference it exists but NEVER include the actual value. Use "...XXXX" notation with last 4 chars only. Direct to secure channel.
Scanning Procedure (MANDATORY):
Writing Style: See references/writing_style_guide.md for Arlen's authentic voice:
Date & Theme: See references/seasonal_themes.md:
HTML Template: Use assets/email_template.html with seasonal styling injection.
Signature & Footer:
-Arlen-Arlen A. Greer (senior executives, legal, contracts)Primary Method: gws CLI:
gws gmail +send \
--to "[email protected]" \
--subject "Subject Line" \
--body "<html>...</html>" \
--html \
--cc "[email protected]" \
--bcc "[email protected]"
Reply (threaded):
gws gmail +reply --message-id MESSAGE_ID --body "Reply text" --html
Reply All:
gws gmail +reply-all --message-id MESSAGE_ID --body "Reply text" --html
Forward:
gws gmail +forward --message-id MESSAGE_ID --to "[email protected]"
Fallback: Legacy Ruby script (if gws +send doesn't support HTML well):
echo '{
"to": ["[email protected]"],
"subject": "Subject Line",
"body_html": "<html>...</html>",
"cc": [],
"bcc": ["[email protected]"],
"attachments": ["/path/to/file.pdf"]
}' | ~/.claude/skills/google-workspace/scripts/gmail_manager.rb send
# Triage unread inbox
gws gmail +triage
# Search messages
gws gmail users messages list --params '{"userId": "me", "q": "from:[email protected]", "maxResults": 10}'
# Read specific message
gws gmail users messages get --params '{"userId": "me", "id": "MESSAGE_ID"}'
# Watch for new emails (streaming)
gws gmail +watch
File Validation (MANDATORY):
Supported types: .pdf, .doc, .docx, .txt, .rtf, .xls, .xlsx, .csv, .ppt, .pptx, .jpg, .png, .gif, .zip
references/writing_style_guide.md § "Progress & Status Report Emails"# Today's agenda (uses account timezone)
gws calendar +agenda --today
# This week
gws calendar +agenda
# Specific date range
gws calendar events list --params '{
"calendarId": "primary",
"timeMin": "2026-03-16T00:00:00-05:00",
"timeMax": "2026-03-16T23:59:59-05:00",
"singleEvents": true,
"orderBy": "startTime"
}'
# Override timezone
gws calendar +agenda --timezone America/New_York
# Quick event creation
gws calendar +insert \
--summary "Team Meeting" \
--start "2026-03-20T15:00:00" \
--end "2026-03-20T16:00:00"
# Event with attendees and Meet link
gws calendar events insert --params '{"calendarId": "primary"}' --json '{
"summary": "Project Review",
"start": {"dateTime": "2026-03-20T14:00:00-05:00"},
"end": {"dateTime": "2026-03-20T15:00:00-05:00"},
"attendees": [
{"email": "[email protected]"},
{"email": "[email protected]"}
],
"conferenceData": {
"createRequest": {"requestId": "meet-123"}
}
}'
# Update event
gws calendar events update --params '{"calendarId": "primary", "eventId": "EVENT_ID"}' --json '{
"summary": "Updated Title",
"start": {"dateTime": "2026-03-20T16:00:00-05:00"},
"end": {"dateTime": "2026-03-20T17:00:00-05:00"}
}'
# Delete event
gws calendar events delete --params '{"calendarId": "primary", "eventId": "EVENT_ID"}'
When finding free time or scheduling meetings:
LUNCHTIME AVOIDANCE POLICY (CRITICAL):
Default business hours: 9:00 AM - 5:00 PM Default timezone: America/Chicago
Legacy script for advanced free-time search:
~/.claude/skills/google-workspace/scripts/calendar_manager.rb --operation find_free \
--time-min "2026-03-20T00:00:00" \
--time-max "2026-03-27T23:59:59" \
--duration 3600 \
--business-start 9 \
--business-end 17
# List files
gws drive files list --params '{"pageSize": 10}'
# Search files
gws drive files list --params '{"q": "name contains '\''report'\'' and mimeType='\''application/pdf'\''", "pageSize": 20}'
# Upload file
gws drive +upload ./report.pdf --name "Q1 Report"
# Upload to specific folder
gws drive files create --json '{"name": "report.pdf", "parents": ["FOLDER_ID"]}' --upload ./report.pdf
# Download file
gws drive files get --params '{"fileId": "FILE_ID", "alt": "media"}' > output.pdf
# Create folder
gws drive files create --json '{"name": "Project Files", "mimeType": "application/vnd.google-apps.folder"}'
# Move file to folder
gws drive files update --params '{"fileId": "FILE_ID", "addParents": "FOLDER_ID", "removeParents": "OLD_PARENT_ID"}'
# Share file
gws drive permissions create --params '{"fileId": "FILE_ID"}' --json '{
"role": "writer",
"type": "user",
"emailAddress": "[email protected]"
}'
# Delete (trash)
gws drive files update --params '{"fileId": "FILE_ID"}' --json '{"trashed": true}'
gws drive files list --params '{"pageSize": 100}' --page-all | jq -r '.files[].name'
# Read cell range
gws sheets +read --spreadsheet SPREADSHEET_ID --range "Sheet1!A1:D10"
# Append row
gws sheets +append --spreadsheet SPREADSHEET_ID --values "Alice,95,Chicago"
# Write values
gws sheets spreadsheets values update \
--params '{"spreadsheetId": "ID", "range": "Sheet1!A1:B2", "valueInputOption": "USER_ENTERED"}' \
--json '{"values": [["Name", "Age"], ["Alice", 30]]}'
# Read values
gws sheets spreadsheets values get --params '{"spreadsheetId": "ID", "range": "Sheet1!A1:D10"}'
# Create new spreadsheet
gws sheets spreadsheets create --json '{"properties": {"title": "Q1 Budget"}}'
# Get metadata
gws sheets spreadsheets get --params '{"spreadsheetId": "ID", "fields": "properties,sheets.properties"}'
# Batch update (multiple operations)
gws sheets spreadsheets values batchUpdate \
--params '{"spreadsheetId": "ID"}' \
--json '{
"valueInputOption": "USER_ENTERED",
"data": [
{"range": "Sheet1!A1", "values": [["Header1"]]},
{"range": "Sheet1!B1", "values": [["Header2"]]}
]
}'
Shell escaping for ranges: Always single-quote JSON with ! characters.
A1 Notation: A1, A1:B10, Sheet1!A:A (whole column), Sheet1!1:1 (whole row), 'Sheet Name'!A1 (quoted for spaces)
# Read document content
gws docs documents get --params '{"documentId": "DOC_ID"}'
# Append text to document
gws docs +write --document DOC_ID --text "Appended content"
# Create new document
gws docs documents create --json '{"title": "Meeting Notes"}'
# Batch update (insert, delete, format)
gws docs documents batchUpdate --params '{"documentId": "DOC_ID"}' --json '{
"requests": [
{"insertText": {"location": {"index": 1}, "text": "Hello World\n"}}
]
}'
# Find and replace
gws docs documents batchUpdate --params '{"documentId": "DOC_ID"}' --json '{
"requests": [
{"replaceAllText": {"containsText": {"text": "old", "matchCase": true}, "replaceText": "new"}}
]
}'
Legacy script (for complex operations):
~/.claude/skills/google-workspace/scripts/docs_manager.rb read <document_id>
echo '{"document_id":"abc123","text":"New text"}' | ~/.claude/skills/google-workspace/scripts/docs_manager.rb append
# List task lists
gws tasks tasklists list
# List tasks in a list
gws tasks tasks list --params '{"tasklist": "TASKLIST_ID"}'
# Create task
gws tasks tasks insert --params '{"tasklist": "TASKLIST_ID"}' --json '{
"title": "Complete project proposal",
"notes": "Include budget estimates",
"due": "2026-03-20T00:00:00Z"
}'
# Complete task
gws tasks tasks update --params '{"tasklist": "TASKLIST_ID", "task": "TASK_ID"}' --json '{
"status": "completed"
}'
# Delete task
gws tasks tasks delete --params '{"tasklist": "TASKLIST_ID", "task": "TASK_ID"}'
# Clear completed tasks
gws tasks tasks clear --params '{"tasklist": "TASKLIST_ID"}'
Legacy script (for complex operations):
ruby ~/.claude/skills/google-workspace/scripts/tasks_manager.rb list_tasklists
ruby ~/.claude/skills/google-workspace/scripts/tasks_manager.rb create_task --tasklist "ID" --title "Task" --due "2026-03-20"
# Send message to space
gws chat spaces messages create \
--params '{"parent": "spaces/SPACE_ID"}' \
--json '{"text": "Deploy complete."}'
# List spaces
gws chat spaces list
# List contacts
gws people people connections list --params '{
"resourceName": "people/me",
"personFields": "names,emailAddresses,phoneNumbers,organizations",
"pageSize": 100
}'
# Search contacts (use the query to filter)
gws people people searchContacts --params '{
"query": "John Smith",
"readMask": "names,emailAddresses,phoneNumbers"
}'
# Create contact
gws people people createContact --json '{
"names": [{"givenName": "Jane", "familyName": "Doe"}],
"emailAddresses": [{"value": "[email protected]"}],
"phoneNumbers": [{"value": "555-1234"}]
}'
# Update contact
gws people people updateContact --params '{"resourceName": "people/c123", "updatePersonFields": "emailAddresses"}' --json '{
"emailAddresses": [{"value": "[email protected]"}]
}'
# Delete contact
gws people people deleteContact --params '{"resourceName": "people/c123"}'
Legacy script (if gws people commands unavailable):
~/.claude/skills/google-workspace/scripts/contacts_manager.rb --search "John Smith"
~/.claude/skills/google-workspace/scripts/contacts_manager.rb --create '{"name": {"given_name": "Jane", "family_name": "Doe"}, "emails": [{"value": "[email protected]"}]}'
# Daily standup report (today's meetings + tasks)
gws workflow +standup-report
# Meeting prep (next meeting details)
gws workflow +meeting-prep
# Weekly digest
gws workflow +weekly-digest
# Convert email to task
gws workflow +email-to-task
# Announce Drive file in Chat
gws workflow +file-announce
# Schema introspection (discover available methods)
gws schema drive.files.list
gws schema gmail.users.messages.list
references/writing_style_guide.md
references/seasonal_themes.md
references/context_routing.md
assets/email_template.html
{{SUBJECT}}, {{RECIPIENT_NAME}}, {{CONTENT}}Authentication Error (exit code 2):
gws auth login with 1Password credential injection~/.config/gws/credentials.enc existsAPI Error (exit code 1):
Contact Lookup Fails:
Gmail Send Fails:
~/.claude/skills/google-workspace/scripts/gmail_manager.rb send| Variable | Purpose |
|---|---|
GOOGLE_WORKSPACE_CLI_CLIENT_ID | OAuth client ID (from 1Password) |
GOOGLE_WORKSPACE_CLI_CLIENT_SECRET | OAuth client secret (from 1Password) |
GOOGLE_WORKSPACE_CLI_TOKEN | Pre-obtained access token (optional) |
GOOGLE_WORKSPACE_CLI_CONFIG_DIR | Config directory (default: ~/.config/gws) |
GOOGLE_WORKSPACE_CLI_LOG | Log level (e.g., gws=debug) |