Google in your terminal - CLI for Gmail, Calendar, Drive, Contacts, Tasks, and Sheets.
- Gmail - search threads, send emails, manage labels, drafts, filters, delegation, vacation settings, and watch (Pub/Sub push)
- Calendar - list/create/update events, detect conflicts, manage invitations, check free/busy status
- Drive - list/search/upload/download files, manage permissions, organize folders
- Contacts - search/create/update contacts, access Workspace directory
- Tasks - manage tasklists and tasks: create/add/update/done/undo/delete/clear
- Sheets - read/write/update spreadsheets, create new sheets (and export via Drive)
- Docs/Slides - export to PDF/DOCX/PPTX via Drive (plus create/copy, docs-to-text)
- People - access profile information
- Multiple account support - manage multiple Google accounts simultaneously
- Secure credential storage using OS keyring (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows)
- Auto-refreshing tokens - authenticate once, use indefinitely
- Parseable output - JSON mode for scripting and automation
brew install steipete/tap/gogcligit clone https://github.com/steipete/gogcli.git
cd gogcli
makeRun:
./bin/gog --helpBefore adding an account, create OAuth2 credentials from Google Cloud Console:
- Create a project: https://console.cloud.google.com/projectcreate
- Enable the APIs you need:
- Gmail API: https://console.cloud.google.com/apis/api/gmail.googleapis.com
- Google Calendar API: https://console.cloud.google.com/apis/api/calendar-json.googleapis.com
- Google Drive API: https://console.cloud.google.com/apis/api/drive.googleapis.com
- People API (Contacts): https://console.cloud.google.com/apis/api/people.googleapis.com
- Google Tasks API: https://console.cloud.google.com/apis/api/tasks.googleapis.com
- Google Sheets API: https://console.cloud.google.com/apis/api/sheets.googleapis.com
- Configure OAuth consent screen: https://console.cloud.google.com/auth/branding
- If your app is in "Testing", add test users: https://console.cloud.google.com/auth/audience
- Create OAuth client:
- Go to https://console.cloud.google.com/auth/clients
- Click "Create Client"
- Application type: "Desktop app"
- Download the JSON file (usually named
client_secret_....apps.googleusercontent.com.json)
gog auth credentials ~/Downloads/client_secret_....jsongog auth add you@gmail.comThis will open a browser window for OAuth authorization. The refresh token is stored securely in your system keychain.
export GOG_ACCOUNT=you@gmail.com
gog gmail labels listSpecify the account using either a flag or environment variable:
# Via flag
gog gmail search 'newer_than:7d' --account you@gmail.com
# Via environment
export GOG_ACCOUNT=you@gmail.com
gog gmail search 'newer_than:7d'List configured accounts:
gog auth list- Default: human-friendly tables on stdout.
--plain: stable TSV on stdout (tabs preserved; best for piping to tools that expect\t).--json: JSON on stdout (best for scripting).- Human-facing hints/progress go to stderr.
- Colors are enabled only in rich TTY output and are disabled automatically for
--jsonand--plain.
By default, gog auth add requests access to all services (gmail, calendar, drive, contacts, tasks, sheets, people). To request fewer scopes:
gog auth add you@gmail.com --services drive,calendarIf you need to add services later and Google doesn't return a refresh token, re-run with --force-consent:
gog auth add you@gmail.com --services all --force-consent
# Or add just Sheets
gog auth add you@gmail.com --services sheets --force-consentGOG_ACCOUNT- Default account email to use (avoids repeating--accountflag)GOG_JSON- Default JSON outputGOG_PLAIN- Default plain outputGOG_COLOR- Color mode:auto(default),always, orneverGOG_KEYRING_PASSWORD- Password for encrypted on-disk keyring (Linux/WSL/container environments without OS keychain)
OAuth credentials are stored securely in your system's keychain:
- macOS: Keychain Access
- Linux: Secret Service (GNOME Keyring, KWallet)
- Windows: Credential Manager
The CLI uses github.com/99designs/keyring for secure storage.
If no OS keychain backend is available (e.g., Linux/WSL/container), keyring can fall back to an encrypted on-disk store and may prompt for a password; for non-interactive runs set GOG_KEYRING_PASSWORD.
- Never commit OAuth client credentials to version control
- Store client credentials outside your project directory
- Use different OAuth clients for development and production
- Re-authorize with
--force-consentif you suspect token compromise - Remove unused accounts with
gog auth remove <email>
gog auth credentials <path> # Store OAuth client credentials
gog auth add <email> # Authorize and store refresh token
gog auth list # List stored accounts
gog auth remove <email> # Remove a stored refresh token
gog auth manage # Open accounts manager in browser
gog auth tokens # Manage stored refresh tokens# Search and read
gog gmail search 'newer_than:7d' --max 10
gog gmail thread <threadId>
gog gmail thread <threadId> --download # Download attachments to current dir
gog gmail thread <threadId> --download --out-dir ./attachments
gog gmail get <messageId>
gog gmail get <messageId> --format metadata
gog gmail attachment <messageId> <attachmentId>
gog gmail attachment <messageId> <attachmentId> --out ./attachment.bin
gog gmail url <threadId> # Print Gmail web URL
# Send and compose
gog gmail send --to a@b.com --subject "Hi" --body "Plain fallback"
gog gmail send --to a@b.com --subject "Hi" --body "Plain fallback" --body-html "<p>Hello</p>"
gog gmail drafts list
gog gmail drafts create --to a@b.com --subject "Draft"
gog gmail drafts send <draftId>
# Labels
gog gmail labels list
gog gmail labels get INBOX --json # Includes message counts
gog gmail labels create "My Label"
gog gmail labels update <labelId> --name "New Name"
gog gmail labels delete <labelId>
# Batch operations
gog gmail batch mark-read --query 'older_than:30d'
gog gmail batch delete --query 'from:spam@example.com'
gog gmail batch label --query 'from:boss@example.com' --add-labels IMPORTANT
# Filters
gog gmail filters list
gog gmail filters create --from 'noreply@example.com' --label 'Notifications'
gog gmail filters delete <filterId>
# Settings
gog gmail autoforward get
gog gmail autoforward enable --email forward@example.com
gog gmail autoforward disable
gog gmail forwarding list
gog gmail forwarding add --email forward@example.com
gog gmail sendas list
gog gmail sendas create --email alias@example.com
gog gmail vacation get
gog gmail vacation enable --subject "Out of office" --message "..."
gog gmail vacation disable
# Delegation (G Suite/Workspace)
gog gmail delegates list
gog gmail delegates add --email delegate@example.com
gog gmail delegates remove --email delegate@example.com
# Watch (Pub/Sub push)
gog gmail watch start --topic projects/<p>/topics/<t> --label INBOX
gog gmail watch serve --bind 127.0.0.1 --token <shared> --hook-url https://127.0.0.1:18789/hooks/agent
gog gmail watch serve --bind 0.0.0.0 --verify-oidc --oidc-email <svc@...> --hook-url <url>
gog gmail history --since <historyId>Gmail watch (Pub/Sub push):
- Create Pub/Sub topic + push subscription (OIDC preferred; shared token ok for dev).
- Full flow + payload details:
docs/watch.md.
# Calendars
gog calendar calendars
gog calendar acl <calendarId> # List access control rules
gog calendar colors # List available event/calendar colors
gog calendar time --timezone America/New_York
# Events
gog calendar events <calendarId> --from 2025-01-01T00:00:00Z --to 2025-01-08T00:00:00Z --max 50
gog calendar events --all # Fetch events from all calendars
gog calendar event <calendarId> <eventId>
gog calendar search "meeting" --from 2025-01-01T00:00:00Z --to 2025-01-31T00:00:00Z --max 50
# Create and update
gog calendar create <calendarId> \
--summary "Meeting" \
--from 2025-01-15T10:00:00Z \
--to 2025-01-15T11:00:00Z
gog calendar create <calendarId> \
--summary "Team Sync" \
--from 2025-01-15T14:00:00Z \
--to 2025-01-15T15:00:00Z \
--attendees "alice@example.com,bob@example.com" \
--location "Zoom"
gog calendar update <calendarId> <eventId> \
--summary "Updated Meeting" \
--from 2025-01-15T11:00:00Z \
--to 2025-01-15T12:00:00Z
gog calendar delete <calendarId> <eventId>
# Invitations
gog calendar respond <calendarId> <eventId> --status accepted
gog calendar respond <calendarId> <eventId> --status declined
gog calendar respond <calendarId> <eventId> --status tentative
# Availability
gog calendar freebusy --calendars "primary,work@example.com" \
--from 2025-01-15T00:00:00Z \
--to 2025-01-16T00:00:00Z
gog calendar conflicts --calendars "primary,work@example.com" \
--from 2025-01-15T00:00:00Z \
--to 2025-01-22T00:00:00Z# List and search
gog drive ls --max 20
gog drive ls --parent <folderId> --max 20
gog drive search "invoice" --max 20
gog drive get <fileId> # Get file metadata
gog drive url <fileId> # Print Drive web URL
gog drive copy <fileId> "Copy Name"
# Upload and download
gog drive upload ./path/to/file --parent <folderId>
gog drive download <fileId> --out ./downloaded.bin
gog drive download <fileId> --format pdf --out ./exported.pdf
gog drive download <fileId> --format docx --out ./doc.docx
gog drive download <fileId> --format pptx --out ./slides.pptx
# Organize
gog drive mkdir "New Folder"
gog drive mkdir "New Folder" --parent <parentFolderId>
gog drive rename <fileId> "New Name"
gog drive move <fileId> --parent <destinationFolderId>
gog drive delete <fileId> # Move to trash
# Permissions
gog drive permissions <fileId>
gog drive share <fileId> --email user@example.com --role reader
gog drive share <fileId> --email user@example.com --role writer
gog drive unshare <fileId> --permission-id <permissionId># Docs
gog docs info <docId>
gog docs cat <docId> --max-bytes 10000
gog docs create "My Doc"
gog docs copy <docId> "My Doc Copy"
gog docs export <docId> --format pdf --out ./doc.pdf
# Slides
gog slides info <presentationId>
gog slides create "My Deck"
gog slides copy <presentationId> "My Deck Copy"
gog slides export <presentationId> --format pdf --out ./deck.pdf
# Sheets
gog sheets copy <spreadsheetId> "My Sheet Copy"
gog sheets export <spreadsheetId> --format pdf --out ./sheet.pdf# Personal contacts
gog contacts list --max 50
gog contacts search "Ada" --max 50
gog contacts get people/<resourceName>
gog contacts get user@example.com # Get by email
# Other contacts (people you've interacted with)
gog contacts other list --max 50
gog contacts other search "John" --max 50
# Create and update
gog contacts create \
--given-name "John" \
--family-name "Doe" \
--email "john@example.com" \
--phone "+1234567890"
gog contacts update people/<resourceName> \
--given-name "Jane" \
--email "jane@example.com"
gog contacts delete people/<resourceName>
# Workspace directory (requires Google Workspace)
gog contacts directory list --max 50
gog contacts directory search "Jane" --max 50# Task lists
gog tasks lists --max 50
gog tasks lists create <title>
# Tasks in a list
gog tasks list <tasklistId> --max 50
gog tasks add <tasklistId> --title "Task title"
gog tasks update <tasklistId> <taskId> --title "New title"
gog tasks done <tasklistId> <taskId>
gog tasks undo <tasklistId> <taskId>
gog tasks delete <tasklistId> <taskId>
gog tasks clear <tasklistId># Read
gog sheets metadata <spreadsheetId>
gog sheets get <spreadsheetId> 'Sheet1!A1:B10'
# Export (via Drive)
gog sheets export <spreadsheetId> --format pdf --out ./sheet.pdf
gog sheets export <spreadsheetId> --format xlsx --out ./sheet.xlsx
# Write
gog sheets update <spreadsheetId> 'A1' 'val1|val2,val3|val4'
gog sheets update <spreadsheetId> 'A1' --values-json '[["a","b"],["c","d"]]'
gog sheets append <spreadsheetId> 'Sheet1!A:C' 'new|row|data'
gog sheets clear <spreadsheetId> 'Sheet1!A1:B10'
# Create
gog sheets create "My New Spreadsheet" --sheets "Sheet1,Sheet2"# Profile
gog people me# Export (via Drive)
gog docs export <docId> --format pdf --out ./doc.pdf
gog docs export <docId> --format docx --out ./doc.docx
gog docs export <docId> --format txt --out ./doc.txt# Export (via Drive)
gog slides export <presentationId> --format pptx --out ./deck.pptx
gog slides export <presentationId> --format pdf --out ./deck.pdfHuman-readable output with colors (default):
$ gog gmail search 'newer_than:7d' --max 3
THREAD_ID SUBJECT FROM DATE
18f1a2b3c4d5e6f7 Meeting notes alice@example.com 2025-01-10
17e1d2c3b4a5f6e7 Invoice #12345 billing@vendor.com 2025-01-09
16d1c2b3a4e5f6d7 Project update bob@example.com 2025-01-08Machine-readable output for scripting and automation:
$ gog gmail search 'newer_than:7d' --max 3 --json
{
"threads": [
{
"id": "18f1a2b3c4d5e6f7",
"snippet": "Meeting notes from today...",
"messages": [...]
},
...
]
}Data goes to stdout, errors and progress to stderr for clean piping:
gog --json drive ls --max 5 | jq '.files[] | select(.mimeType=="application/pdf")'Useful pattern:
gog --json ... | jq .
If you use pnpm, see the shortcut section for pnpm -s (silent) to keep stdout clean.
# Search for emails from the last week
gog gmail search 'newer_than:7d has:attachment' --max 10
# Get thread details and download attachments
gog gmail thread <threadId> --download# Find a free time slot
gog calendar freebusy --calendars "primary" \
--from 2025-01-15T00:00:00Z \
--to 2025-01-16T00:00:00Z
# Create the meeting
gog calendar create primary \
--summary "Team Standup" \
--from 2025-01-15T10:00:00Z \
--to 2025-01-15T10:30:00Z \
--attendees "alice@example.com,bob@example.com"# Search for PDFs
gog drive search "invoice filetype:pdf" --max 20 --json | \
jq -r '.files[] | .id' | \
while read fileId; do
gog drive download "$fileId"
done# Check personal Gmail
gog gmail search 'is:unread' --account personal@gmail.com
# Check work Gmail
gog gmail search 'is:unread' --account work@company.com
# Or set default
export GOG_ACCOUNT=work@company.com
gog gmail search 'is:unread'# Convert CSV to pipe-delimited format and update sheet
cat data.csv | tr ',' '|' | \
gog sheets update <spreadsheetId> 'Sheet1!A1'# Sheets
gog sheets export <spreadsheetId> --format pdf
# Docs
gog docs export <docId> --format docx
# Slides
gog slides export <presentationId> --format pptx# Mark all emails from a sender as read
gog gmail batch mark-read --query 'from:noreply@example.com'
# Archive old emails
gog gmail batch archive --query 'older_than:1y'
# Label important emails
gog gmail batch label --query 'from:boss@example.com' --add-labels IMPORTANTEnable verbose logging for troubleshooting:
gog --verbose gmail search 'newer_than:7d'
# Shows API requests and responsesAll commands support these flags:
--account <email>- Account to use (overrides GOG_ACCOUNT)--json- Output JSON to stdout (best for scripting)--plain- Output stable, parseable text to stdout (TSV; no colors)--color <mode>- Color mode:auto,always, ornever(default: auto)--force- Skip confirmations for destructive commands--no-input- Never prompt; fail instead (useful for CI)--verbose- Enable verbose logging--help- Show help for any command
Generate shell completions for your preferred shell:
# macOS (with Homebrew)
gog completion bash > $(brew --prefix)/etc/bash_completion.d/gog
# Linux
gog completion bash > /etc/bash_completion.d/gog
# Or load directly in your current session
source <(gog completion bash)# Generate completion file
gog completion zsh > "${fpath[1]}/_gog"
# Or add to .zshrc for automatic loading
echo 'eval "$(gog completion zsh)"' >> ~/.zshrc
# Enable completions if not already enabled
echo "autoload -U compinit; compinit" >> ~/.zshrcgog completion fish > ~/.config/fish/completions/gog.fish# Load for current session
gog completion powershell | Out-String | Invoke-Expression
# Or add to profile for all sessions
gog completion powershell >> $PROFILEAfter installing completions, start a new shell session for changes to take effect.
After cloning, install git hooks:
make setupThis installs lefthook pre-commit and pre-push hooks for linting and testing.
Pinned tools (installed into .tools/):
- Format:
make fmt(goimports + gofumpt) - Lint:
make lint(golangci-lint) - Test:
make test
CI runs format checks, tests, and lint on push/PR.
Build and run in one step:
pnpm gog auth add you@gmail.comFor clean stdout when scripting:
pnpm -s gog --json gmail search "from:me" | jq .
MIT
- GitHub Repository
- Gmail API Documentation
- Google Calendar API Documentation
- Google Drive API Documentation
- Google People API Documentation
- Google Tasks API Documentation
- Google Sheets API Documentation
This project is inspired by Mario Zechner's original CLIs: