Skip to main content

Google CLI Tools

When does a Google Workspace operation belong in a CLI — and when does it belong in the UI?

Rule of thumb: if an agent workflow produces structured data that needs to land in Sheets, Drive, or Gmail — use the CLI. If a human is making one-off decisions in a document — use the UI.

What It Can Do

gws is a single CLI for all Google Workspace services. Pattern: gws <service> <resource> <method> [flags]

Supported services:

  • sheets — Read/write/append spreadsheets and ranges
  • drive — List, upload, download, share files
  • gmail — Send, read, search, label messages
  • calendar — List events, create meetings, check availability
  • docs — Get document content, create docs
  • chat — Send messages to Spaces

Primary use case in agent workflows: Sheets — structured data in, structured data out. The other services support delivery (Drive upload, Gmail send) rather than data exchange.

When to Use CLI vs UI

Agent pipeline writes ROI model output to Sheets — use CLI (gws sheets values update)

Human reviews and adjusts numbers in a sheet — use UI

Agent uploads a PDF deliverable to a shared Drive folder — use CLI (gws drive files create)

Human moves files between folders — use UI

Agent sends a structured report email — use CLI (gws gmail send) or transactional email service

Human replies to a client email — use UI

Auth Setup (one-time)

gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/spreadsheets,\
https://www.googleapis.com/auth/drive,\
https://www.googleapis.com/auth/gmail.send

# Verify:
gws auth status
gws drive files list --params '{"pageSize": 3}'

Credentials are stored locally by gcloud — never committed to source control.

Core Operations

Sheets — Read

gws sheets spreadsheets values get \
--params '{"spreadsheetId": "SHEET_ID", "range": "Sheet1!A1:Z50"}' \
--format csv

Sheets — Write

gws sheets spreadsheets values update \
--params '{"spreadsheetId": "SHEET_ID", "range": "Sheet1!A1", "valueInputOption": "USER_ENTERED"}' \
--json '{"values": [["Label","Value"],["ROI","3.2x"]]}'

Sheets — Append Rows

gws sheets spreadsheets values append \
--params '{"spreadsheetId": "SHEET_ID", "range": "Sheet1", "valueInputOption": "USER_ENTERED"}' \
--json '{"values": [["new row","data"]]}'

Drive — Upload File

gws drive files create \
--params '{"uploadType": "multipart"}' \
--upload ./report.pdf \
--json '{"name": "AI Transformation Report", "parents": ["FOLDER_ID"]}'

Drive — Share File

gws drive permissions create \
--params '{"fileId": "FILE_ID", "sendNotificationEmail": true}' \
--json '{"role": "reader", "type": "user", "emailAddress": "client@example.com"}'

Adopting a Vendor's Skill Library

A CLI that ships SKILL.md files (gws generate-skills, future others) is a vendor skill library. Adopting one wholesale floods agent discovery with unused verbs. Cherry-pick instead. Two matrices below are universal — any vendor library reuses the same shape.

Matrix A — Vendoring Tiers (Value × Effort)

Tier 1 — core agent ops — vendor immediately. Service atoms + workflow digests the agent calls in active sessions today.

  • sheets, gmail, calendar, drive (service atoms)
  • workflow-weekly-digest, workflow-meeting-prep (composed workflows)

Tier 2 — adapt on use — catalog only. Promote when a real session demands the verb.

  • doc-from-template, generate-report-from-sheet (recipes)
  • exec-assistant, researcher, sales-ops (personas)
  • docs, slides, tasks (lower-traffic service atoms)

Tier 3 — defer — skip unless explicit demand signal arrives. No catalog row.

  • classroom, keep, script, modelarmor, events, admin-reports
  • Recipes and personas not in Tier 2

Matrix B — Implementation Steps (what / where / reversibility)

Step 0 — Install vendor CLI + verify auth

  • Writes: $PATH, ~/.config/{vendor}/
  • Reverse: npm rm -g @{vendor}/cli (or vendor's uninstall)

Step 1 — Create vendor namespace root

  • Writes: .agents/skills/_vendor/{vendor-name}/
  • Reverse: rm -rf the folder

Step 2 — Pull Tier-1 SKILL.md files

  • Writes: .agents/skills/_vendor/{vendor-name}/{skill}/SKILL.md
  • Reverse: git revert

Step 3 — Symlink to agent-readable surface

  • Writes: .claude/skills/{vendor-name}-{skill}.agents/skills/_vendor/{vendor-name}/{skill}
  • Reverse: unlink

Step 4 — Lock refresh script + manifest

  • Writes: scripts/sync-{vendor-name}-skills.sh + .agents/skills/_vendor/{vendor-name}/.vendor-manifest.json
  • Reverse: delete script + manifest

Step 5 — Promote on signal

  • After 3+ sessions actively call a vendor skill, copy → adapt frontmatter → add gates → reference upstream
  • Reverse: git history

The namespace prefix {vendor-name}-{skill} prevents flat-name collision with native skills. The vendor folder is read-only — never edit upstream content; promote instead.

Agent Delivery Pipeline Pattern

For workflows that produce a model, render a document, and deliver to a client:

1. Agent writes ROI model → Google Sheets (gws sheets values update)
2. Agent reads headline numbers → injects into report template
3. Report renders to PDF
4. gws drive files create → upload to shared folder
5. gws drive permissions create → share with client
OR
gws gmail send → email PDF directly

Schema Exploration

# Discover all parameters for any method:
gws schema sheets.spreadsheets.values.update
gws schema drive.files.create
gws schema gmail.users.messages.send

Anti-Patterns

Passing full spreadsheet URL as ID — strip to bare ID: everything between /d/ and /edit

Using RAW for cells with formulas — use USER_ENTERED; formulas need evaluation

One API call per cell for bulk writes — use batchUpdate for 5+ ranges

Storing credentials in source control — credentials live in ~/.config/gcloud/; host-owned

Using gws for interactive human decisions — CLI is for agent pipelines, not human editing sessions

Context

Questions

When does putting structured agent output into Google Sheets create more friction than it removes?

  • At what data volume does a direct Sheets write become a bottleneck — and what replaces it?
  • Which gws operation is most likely to fail silently in an agent pipeline — and how do you detect it?
  • How does this pattern change when the consumer of the Sheet is another agent rather than a human?