Skip to content
 
 

Repository files navigation

🧭 gogcli — Google in your terminal.

GitHub Repo Banner

Fast, script-friendly CLI for Gmail, Calendar, Chat, Classroom, Drive, Docs, Slides, Sheets, Contacts, Tasks, People, Groups (Workspace), and Keep (Workspace-only). JSON-first output, multiple accounts, and least-privilege auth built in.

Features

  • Gmail - search threads and messages, send emails, view attachments, manage labels/drafts/filters/delegation/vacation settings, history, and watch (Pub/Sub push)
  • Email tracking - track opens for gog gmail send --track with a small Cloudflare Worker backend
  • Calendar - list/create/update events, detect conflicts, manage invitations, check free/busy status, team calendars, propose new times, focus/OOO/working-location events, recurrence + reminders
  • Classroom - manage courses, roster, coursework/materials, submissions, announcements, topics, invitations, guardians, profiles
  • Chat - list/find/create spaces, list messages/threads (filter by thread/unread), send messages and DMs (Workspace-only)
  • Drive - list/search/upload/download files, manage permissions/comments, organize folders, list shared drives
  • Contacts - search/create/update contacts, access Workspace directory/other contacts
  • Tasks - manage tasklists and tasks: get/create/add/update/done/undo/delete/clear, repeat schedules
  • Sheets - read/write/update spreadsheets, format cells, 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
  • Keep (Workspace only) - list/get/search notes and download attachments (service account + domain-wide delegation)
  • Groups - list groups you belong to, view group members (Google Workspace)
  • Local time - quick local/UTC time display for scripts and agents
  • Multiple accounts - manage multiple Google accounts simultaneously (with aliases)
  • Command allowlist - restrict top-level services and/or exact command paths for sandboxed/agent runs
  • Secure credential storage using OS keyring or encrypted on-disk keyring (configurable)
  • Auto-refreshing tokens - authenticate once, use indefinitely
  • Least-privilege auth - --readonly and --drive-scope to request fewer scopes
  • Workspace service accounts - domain-wide delegation auth (preferred when configured)
  • Parseable output - JSON mode for scripting and automation (Calendar adds day-of-week fields)

Installation

Robben Media maintains this fork independently. Build and install it from the Robben Media repository:

git clone https://github.com/Robben-Media/gogcli.git
cd gogcli
make build
install -m 755 bin/gog ~/.local/bin/gog

Verify the installed binary:

gog --version
gog --help

Upstream Homebrew taps and go install ...@main are not supported installation methods for this fork. The retained Go module namespace is an implementation compatibility detail, not an install target.

Updates (binary + companion skills)

This fork can pull newer binaries from GitHub Releases and refresh only the Google companion skills that ship with gog (not unrelated agent skills):

# Notice on use (stderr) when a newer release exists, or:
gog update --check

# Upgrade binary + refresh installed pack skills (skips local skill edits)
gog update

# Skills only
gog skills status
gog skills update
gog skills install                 # ensure pack skills under ~/.agents/skills
gog skills update --overwrite-local  # human: replace dirty pack skills

Agents: if output says skills skipped (local edits), tell the user — do not force-overwrite unless asked.

Disable background update checks: GOG_SKIP_UPDATE_CHECK=1.

Help:

  • gog --help shows top-level command groups.
  • Drill down with gog <group> --help (and deeper subcommands).
  • For the full expanded command list: GOG_HELP=full gog --help.
  • For machine-readable discovery: gog schema emits one deterministic, versioned JSON document describing visible commands, aliases, arguments, flags, global flags, exit-code classes, and effective automation/policy state.
  • gog schema is read-only and remains available under --enable-commands restrictions; it does not authenticate, call Google APIs, prompt, check for updates, write configuration, or expose stored credentials and secret environment values.
  • Make shortcut: make gog -- --help (or make gog -- gmail --help).
  • make gog-help shows CLI help (note: make gog --help is Make’s own help; use --).

Quick Start

1. Get OAuth2 Credentials

Before adding an account, create OAuth2 credentials from Google Cloud Console:

  1. Open the Google Cloud Console credentials page: https://console.cloud.google.com/apis/credentials
  2. Create a project: https://console.cloud.google.com/projectcreate
  3. Enable the APIs you need:
  4. Configure OAuth consent screen: https://console.cloud.google.com/auth/branding
  5. If your app is in "Testing", add test users: https://console.cloud.google.com/auth/audience
  6. Create OAuth client:

2. Guided setup (recommended)

For a re-runnable, agent-friendly flow that discovers or creates a Cloud project, enables APIs, guides Console-only OAuth client steps, installs credentials, and can authorize the first account:

gog auth setup

Non-interactive discovery / resume:

gog --json --no-input auth setup --discover
gog --no-input --force auth setup --project my-proj --enable-apis --credentials ~/Downloads/client_secret.json

See docs/auth-clients.md for flags, acknowledgments, and exit codes. Advanced users can still run the manual steps below.

3. Store Credentials (manual)

gog auth credentials ~/Downloads/client_secret_....json

For multiple OAuth clients/projects:

gog --client work auth credentials ~/Downloads/work-client.json
gog auth credentials list

4. Authorize Your Account

gog auth add you@gmail.com

This will open a browser window for OAuth authorization. The refresh token is stored securely in your system keychain.

5. Test Authentication

export GOG_ACCOUNT=you@gmail.com
gog gmail labels list

Authentication & Secrets

Accounts and tokens

gog stores your OAuth refresh tokens in a “keyring” backend. Default is auto (best available backend for your OS/environment).

Before you can run gog auth add, you must store OAuth client credentials once via gog auth credentials <credentials.json> (download a Desktop app OAuth client JSON from the Cloud Console). For multiple clients, use gog --client <name> auth credentials ...; tokens are isolated per client.

List accounts:

gog auth list

Verify tokens are usable (helps spot revoked/expired tokens):

gog auth list --check

Accounts can be authorized either via OAuth refresh tokens or Workspace service accounts (domain-wide delegation). If a service account key is configured for an account, it takes precedence over OAuth refresh tokens (see gog auth list).

Show current auth state/services for the active account:

gog auth status

Run a read-only auth health check (config, keyring, credentials, accounts, token usability):

gog auth doctor
gog --json auth doctor

Multiple OAuth clients

Use --client (or GOG_CLIENT) to select a named OAuth client:

gog --client work auth credentials ~/Downloads/work.json
gog --client work auth add you@company.com

Optional domain mapping for auto-selection:

gog --client work auth credentials ~/Downloads/work.json --domain example.com

How it works:

  • Default client is default (stored in credentials.json).
  • Named clients are stored as credentials-<client>.json.
  • Tokens are isolated per client (token:<client>:<email>); defaults are per client too.

Client selection order (when --client is not set):

  1. --client / GOG_CLIENT
  2. account_clients config (email -> client)
  3. client_domains config (domain -> client)
  4. Credentials file named after the email domain (credentials-example.com.json)
  5. default

Config example (JSON5):

{
  account_clients: { "you@company.com": "work" },
  client_domains: { "example.com": "work" },
}

List stored credentials:

gog auth credentials list

See docs/auth-clients.md for the full client selection and mapping rules.

Keyring backend: Keychain vs encrypted file

Backends:

  • auto (default): picks the best backend for the platform.
  • keychain: macOS Keychain (recommended on macOS; avoids password management).
  • file: encrypted on-disk keyring (requires a password).

Set backend via command (writes keyring_backend into config.json):

gog auth keyring file
gog auth keyring keychain
gog auth keyring auto

Show current backend + source (env/config/default) and config path:

gog auth keyring

Non-interactive runs (CI/ssh): file backend requires GOG_KEYRING_PASSWORD.

export GOG_KEYRING_PASSWORD='...'
gog --no-input auth status

Force backend via env (overrides config):

export GOG_KEYRING_BACKEND=file

Precedence: GOG_KEYRING_BACKEND env var overrides config.json.

Configuration

Account Selection

Specify the account using either a flag or environment variable:

# Via flag
gog gmail search 'newer_than:7d' --account you@gmail.com

# Via alias
gog auth alias set work work@company.com
gog gmail search 'newer_than:7d' --account work

# Via environment
export GOG_ACCOUNT=you@gmail.com
gog gmail search 'newer_than:7d'

# Auto-select (default account or the single stored token)
gog gmail labels list --account auto

List configured accounts:

gog auth list

Output

  • 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).
  • --results-only: with --json, emit only the command's declared primary result instead of its response envelope.
  • --select <paths>: with --json, project comma-separated fields such as id,name or sender.email; dotted paths preserve nested shape and missing fields are omitted.
  • When combined, --results-only runs before --select.
  • --wrap-untrusted / GOG_WRAP_UNTRUSTED: when combined with JSON mode, free-text fields from Workspace (mail bodies/subjects, doc/sheet text, names, summaries, etc.) are wrapped in machine-readable untrusted-content fences so agents can treat them as data, not instructions. Default off. No effect on --plain or human table output; no-op without JSON mode.
  • Human-facing hints/progress go to stderr.
  • Colors are enabled only in rich TTY output and are disabled automatically for --json and --plain.

Agent tip: prefer gog --json --wrap-untrusted … (or GOG_JSON=1 GOG_WRAP_UNTRUSTED=1) when reading Gmail/Docs/Sheets/Drive/Calendar text into a model context.

Service Scopes

By default, gog auth add requests access to the user services (see gog auth services for the current list and scopes).

To request fewer scopes:

gog auth add you@gmail.com --services drive,calendar

To request read-only scopes for a new account:

gog auth add you@gmail.com --services drive,calendar --readonly

To control Drive’s scope (default: full):

gog auth add you@gmail.com --services drive --drive-scope full
gog auth add you@gmail.com --services drive --drive-scope readonly
gog auth add you@gmail.com --services drive --drive-scope file

Notes:

  • --drive-scope readonly is enough for listing/downloading/exporting via Drive (write operations will 403).
  • --drive-scope file is write-capable (limited to files created/opened by this app) and can’t be combined with --readonly.
  • Reauthorization is additive by default. If the account already has write scopes, --readonly retains them; add --replace-scopes to intentionally downgrade the grant.

To add services later, re-run auth add with the additional services. Existing stored scopes are retained. If Google doesn't return a refresh token, add --force-consent:

gog auth add you@gmail.com --services sheets --force-consent

To intentionally replace the existing grant with exactly the selected services, use --replace-scopes (which implies --force-consent):

gog auth add you@gmail.com --services sheets --replace-scopes

To recover after replacing scopes accidentally, reauthorize with every service the account should retain. For the default user-service set:

gog auth add you@gmail.com --services user --force-consent

--services all is accepted as an alias for user for backwards compatibility.

Docs commands are implemented via the Drive API, and docs requests both Drive and Docs API scopes.

Service scope matrix (auto-generated; run go run scripts/gen-auth-services-md.go):

Service User APIs Scopes Notes
gmail yes Gmail API https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.settings.basic
https://www.googleapis.com/auth/gmail.settings.sharing
calendar yes Calendar API https://www.googleapis.com/auth/calendar
chat yes Chat API https://www.googleapis.com/auth/chat.spaces
https://www.googleapis.com/auth/chat.messages
https://www.googleapis.com/auth/chat.memberships
https://www.googleapis.com/auth/chat.users.readstate.readonly
classroom yes Classroom API https://www.googleapis.com/auth/classroom.courses
https://www.googleapis.com/auth/classroom.rosters
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.coursework.me
https://www.googleapis.com/auth/classroom.courseworkmaterials
https://www.googleapis.com/auth/classroom.announcements
https://www.googleapis.com/auth/classroom.topics
https://www.googleapis.com/auth/classroom.guardianlinks.students
https://www.googleapis.com/auth/classroom.profile.emails
https://www.googleapis.com/auth/classroom.profile.photos
drive yes Drive API https://www.googleapis.com/auth/drive
docs yes Docs API, Drive API https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/documents
Export/copy/create via Drive
contacts yes People API https://www.googleapis.com/auth/contacts
https://www.googleapis.com/auth/contacts.other.readonly
https://www.googleapis.com/auth/directory.readonly
Contacts + other contacts + directory
tasks yes Tasks API https://www.googleapis.com/auth/tasks
sheets yes Sheets API, Drive API https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/spreadsheets
Export via Drive
people yes People API profile OIDC profile scope
groups no Cloud Identity API https://www.googleapis.com/auth/cloud-identity.groups.readonly Workspace only
keep no Keep API https://www.googleapis.com/auth/keep.readonly Workspace only; service account (domain-wide delegation)
youtube yes YouTube Data API v3 https://www.googleapis.com/auth/youtube.readonly
bigquery yes BigQuery API https://www.googleapis.com/auth/bigquery
https://www.googleapis.com/auth/bigquery.readonly
analytics yes Analytics Data API, Analytics Admin API https://www.googleapis.com/auth/analytics.readonly
https://www.googleapis.com/auth/analytics.edit
https://www.googleapis.com/auth/analytics.manage.users.readonly
https://www.googleapis.com/auth/analytics.manage.users
Includes manage.users for accessBindings / invite users
searchconsole yes Search Console API https://www.googleapis.com/auth/webmasters.readonly
https://www.googleapis.com/auth/webmasters
tagmanager yes Tag Manager API v2 https://www.googleapis.com/auth/tagmanager.readonly
https://www.googleapis.com/auth/tagmanager.edit.containers
https://www.googleapis.com/auth/tagmanager.edit.containerversions
https://www.googleapis.com/auth/tagmanager.manage.accounts
https://www.googleapis.com/auth/tagmanager.manage.users
https://www.googleapis.com/auth/tagmanager.publish
Includes manage.users + edit/publish (not delete.containers)
businessprofile yes Business Information API, Business Account Management API https://www.googleapis.com/auth/business.manage

GA4 access bindings require an email backed by a Google account. The Analytics Admin API cannot grant access to a Google Workspace alias or group address; use an individual Google account or the GA4 web interface instead.

Service Accounts (Workspace only)

A service account is a non-human Google identity that belongs to a Google Cloud project. In Google Workspace, a service account can impersonate a user via domain-wide delegation (admin-controlled) and access APIs like Gmail/Calendar/Drive as that user.

In gog, service accounts are an optional auth method that can be configured per account email. If a service account key is configured for an account, it takes precedence over OAuth refresh tokens (see gog auth list).

1) Create a Service Account (Google Cloud)

  1. Create (or pick) a Google Cloud project.
  2. Enable the APIs you’ll use (e.g. Gmail, Calendar, Drive, Sheets, Docs, People, Tasks, Cloud Identity).
  3. Go to IAM & Admin → Service Accounts and create a service account.
  4. In the service account details, enable Domain-wide delegation.
  5. Create a key (Keys → Add key → Create new key → JSON) and download the JSON key file.

2) Allowlist scopes (Google Workspace Admin Console)

Domain-wide delegation is enforced by Workspace admin settings.

  1. Open Admin console → Security → API controls → Domain-wide delegation.
  2. Add a new API client:
    • Client ID: use the service account’s “Client ID” from Google Cloud.
    • OAuth scopes: comma-separated list of scopes you want to allow (copy from gog auth services and/or your gog auth add --services ... usage).

If a scope is missing from the allowlist, service-account token minting can fail (or API calls will 403 with insufficient permissions).

3) Configure gog to use the service account

Store the key for the user you want to impersonate:

gog auth service-account set you@yourdomain.com --key ~/Downloads/service-account.json

Verify gog is preferring the service account for that account:

gog --account you@yourdomain.com auth status
gog auth list

Google Keep (Workspace only)

Keep requires Workspace + domain-wide delegation. You can configure it via the generic service-account command above (recommended), or the legacy Keep helper:

gog auth service-account set you@yourdomain.com --key ~/Downloads/service-account.json
gog keep list --account you@yourdomain.com
gog keep get <noteId> --account you@yourdomain.com

Environment Variables

  • GOG_ACCOUNT - Default account email or alias to use (avoids repeating --account; otherwise uses keyring default or a single stored token)
  • GOG_CLIENT - OAuth client name (selects stored credentials + token bucket)
  • GOG_JSON - Default JSON output
  • GOG_PLAIN - Default plain output
  • GOG_COLOR - Color mode: auto (default), always, or never
  • GOG_TIMEZONE - Default output timezone for Calendar/Gmail (IANA name, UTC, or local)
  • GOG_ENABLE_COMMANDS - Comma-separated allowlist of top-level commands (e.g., calendar,tasks)
  • GOG_ENABLE_COMMAND_PATHS - Comma-separated allowlist of exact command paths (e.g., gmail search,calendar events)

Config File (JSON5)

Find the actual config path in gog --help or gog auth keyring.

Typical paths:

  • macOS: ~/Library/Application Support/gogcli/config.json
  • Linux: ~/.config/gogcli/config.json (or $XDG_CONFIG_HOME/gogcli/config.json)
  • Windows: %AppData%\\gogcli\\config.json

Example (JSON5 supports comments and trailing commas):

{
  // Avoid macOS Keychain prompts
  keyring_backend: "file",
  // Default output timezone for Calendar/Gmail (IANA, UTC, or local)
  default_timezone: "UTC",
  // Optional account aliases
  account_aliases: {
    work: "work@company.com",
    personal: "me@gmail.com",
  },
  // Optional per-account OAuth client selection
  account_clients: {
    "work@company.com": "work",
  },
  // Optional domain -> client mapping
  client_domains: {
    "example.com": "work",
  },
}

Config Commands

gog config path
gog config list
gog config keys
gog config get default_timezone
gog config set default_timezone UTC
gog config unset default_timezone

Account Aliases

gog auth alias set work work@company.com
gog auth alias list
gog auth alias unset work

Aliases work anywhere you pass --account or GOG_ACCOUNT (reserved: auto, default).

Command Allowlist (Sandboxing)

Two complementary invocation allowlists restrict which commands may run:

  • --enable-commands / GOG_ENABLE_COMMANDS: top-level services only (e.g. gmail, calendar)
  • --enable-command-paths / GOG_ENABLE_COMMAND_PATHS: exact parser-resolved command paths (e.g. gmail search, gmail thread get)

Matching rules for exact paths:

  • Identity is the Kong-resolved command path: command segments only (flags and positional values are excluded)
  • Documented aliases resolve via the parser model (mail search == gmail search; gmail read == gmail thread get); parent paths written by primary name do not implicitly allow default child leaves
  • Parent paths do not allow children (gmail thread does not allow gmail thread get)
  • When both lists are set, a match in either list permits the command (OR)
  • When neither list is set, enablement is unrestricted
  • Persisted policy rules remain a separate subsequent gate (AND with enablement)
# Only allow calendar + tasks commands for an agent (top-level)
gog --enable-commands calendar,tasks calendar events --today

# Same via env
export GOG_ENABLE_COMMANDS=calendar,tasks
gog tasks list <tasklistId>

# Exact paths: allow Gmail search without other Gmail commands
gog --enable-command-paths "gmail search" gmail search 'is:unread'
export GOG_ENABLE_COMMAND_PATHS='gmail search,calendar events'

# Compose: top-level calendar OR exact gmail search
gog --enable-commands calendar --enable-command-paths "gmail search" gmail search 'is:unread'

Security

Credential Storage

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.

Keychain Prompts (macOS)

macOS Keychain may prompt more than you’d expect when the “app identity” keeps changing (different binary path, go run temp builds, rebuilding to new ./bin/gog, multiple copies). Keychain treats those as different apps, so it asks again.

Options:

  • Default (recommended): keep using Keychain (secure) and run a stable gog binary path to reduce repeat prompts.
  • Force Keychain: GOG_KEYRING_BACKEND=keychain (disables any file-backend fallback).
  • Avoid Keychain prompts entirely: GOG_KEYRING_BACKEND=file (stores encrypted entries on disk under your config dir).
    • To avoid password prompts too (CI/non-interactive): set GOG_KEYRING_PASSWORD=... (tradeoff: secret in env).

Best Practices

  • 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-consent if you suspect token compromise
  • Remove unused accounts with gog auth remove <email>

Commands

Flag aliases:

  • --out also accepts --output.
  • --out-dir also accepts --output-dir (Gmail thread attachment downloads).

Authentication

gog auth setup                        # Guided Cloud project + OAuth client setup
gog auth credentials <path>           # Store OAuth client credentials
gog auth credentials list             # List stored OAuth client credentials
gog --client work auth credentials <path>  # Store named OAuth client credentials
gog auth add <email>                  # Authorize and store refresh token
gog auth service-account set <email> --key <path>  # Configure service account impersonation (Workspace only)
gog auth service-account status <email>            # Show service account status
gog auth service-account unset <email>             # Remove service account
gog auth keep <email> --key <path>                 # Legacy alias (Keep)
gog auth keyring [backend]            # Show/set keyring backend (auto|keychain|file)
gog auth status                       # Show current auth state/services
gog auth doctor                       # Read-only auth/keyring/token health check
gog auth services                     # List available services and OAuth scopes
gog auth list                         # List stored accounts
gog auth list --check                 # Validate stored refresh tokens
gog auth remove <email>               # Remove a stored refresh token
gog auth manage                       # Open accounts manager in browser
gog auth tokens                       # Manage stored refresh tokens

Keep (Workspace only)

gog keep list --account you@yourdomain.com
gog keep get <noteId> --account you@yourdomain.com
gog keep search <query> --account you@yourdomain.com
gog keep attachment <attachmentName> --account you@yourdomain.com --out ./attachment.bin

Gmail

# Search and read
gog gmail search 'newer_than:7d' --max 10
gog gmail thread get <threadId>
gog gmail thread get <threadId> --download              # Download attachments to current dir
gog gmail thread get <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
gog gmail thread modify <threadId> --add STARRED --remove INBOX

# 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-file ./message.txt
gog gmail send --to a@b.com --subject "Hi" --body-file -   # Read body from stdin
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 --subject "Draft" --body "Body"
gog gmail drafts create --to a@b.com --subject "Draft" --body "Body"
gog gmail drafts update <draftId> --subject "Draft" --body "Body"
gog gmail drafts update <draftId> --to a@b.com --subject "Draft" --body "Body"
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 modify <threadId> --add STARRED --remove INBOX

# Batch operations
gog gmail batch delete <messageId> <messageId>
gog gmail batch modify <messageId> <messageId> --add STARRED --remove INBOX

# Filters
gog gmail filters list
gog gmail filters create --from 'noreply@example.com' --add-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 http://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>

gog gmail get <messageId> --plain uses the same five-column TSV schema for full, metadata, and raw fetch formats:

RECORD_TYPE	MESSAGE_ID	THREAD_ID	NAME	VALUE

RECORD_TYPE is metadata, header, attachment, body, or raw. NAME identifies the metadata, header, or attachment field and is empty for body and raw records; VALUE contains its value. Every row includes the message and thread IDs. Tabs, newlines, and carriage returns in free-form fields are replaced with spaces so each record occupies one physical TSV row.

gog gmail thread get <threadId> --plain uses an eight-column TSV schema:

RECORD_TYPE	THREAD_ID	MESSAGE_ID	NAME	VALUE	PATH	BYTES	CACHED

Record meanings:

  • metadata: NAME is message_count and VALUE is the count; MESSAGE_ID is empty.
  • header: NAME is From, To, Subject, or Date; VALUE is the header value.
  • body: VALUE is the selected body, using the same HTML cleanup and preview truncation as human output.
  • attachment: NAME is the filename, VALUE is the MIME type, PATH is the Gmail attachment ID, and BYTES is the declared attachment size.
  • download: NAME is the filename, PATH is the committed on-disk path, BYTES is the exact committed byte count, and CACHED is true or false.

Every message-specific record includes both IDs. Free-form fields are kept to one physical row. Download PATH values use reversible URL path-segment percent encoding (decode with any URL percent-decoder), so tabs, newlines, and other path bytes remain lossless without creating extra TSV rows or columns. An empty thread emits only the header.

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.

Email Tracking

Track when recipients open your emails:

# Set up local tracking config (per-account; generates keys; follow printed deploy steps)
gog gmail track setup --worker-url https://gog-email-tracker.<acct>.workers.dev

# Send with tracking
gog gmail send --to recipient@example.com --subject "Hello" --body-html "<p>Hi!</p>" --track

# Check opens
gog gmail track opens <tracking_id>
gog gmail track opens --to recipient@example.com

# View status
gog gmail track status

Docs: docs/email-tracking.md (setup/deploy) + docs/email-tracking-worker.md (internals).

Notes: --track requires exactly 1 recipient (no cc/bcc) and an HTML body (--body-html). Use --track-split to send per-recipient messages with individual tracking ids. The tracking worker stores IP/user-agent + coarse geo by default.

Calendar

# 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
gog calendar users                    # List workspace users (use email as calendar ID)

# Events (with timezone-aware time flags)
gog calendar events <calendarId> --today                    # Today's events
gog calendar events <calendarId> --tomorrow                 # Tomorrow's events
gog calendar events <calendarId> --week                     # This week (Mon-Sun by default; use --week-start)
gog calendar events <calendarId> --days 3                   # Next 3 days
gog calendar events <calendarId> --from today --to friday   # Relative dates
gog calendar events <calendarId> --from today --to friday --weekday   # Include weekday columns
gog calendar events <calendarId> --from 2025-01-01T00:00:00Z --to 2025-01-08T00:00:00Z
gog calendar events --all             # Fetch events from all calendars
gog calendar events --calendars 1,3   # Fetch events from calendar indices (see gog calendar calendars)
gog calendar events --cal Work --cal Personal  # Fetch events from calendars by name/ID
# Multi-calendar --plain rows use: TYPE CALENDAR ID START END SUMMARY ERROR
# With --weekday: TYPE CALENDAR ID START START_DOW END END_DOW SUMMARY ERROR
# TYPE is "event" or "calendar_error"; errors occupy CALENDAR and ERROR.
# Multi-calendar --json returns events, per-calendar errors, and a complete boolean.
gog calendar event <calendarId> <eventId>
gog calendar get <calendarId> <eventId>                     # Alias for event
gog calendar search "meeting" --today
gog calendar search "meeting" --tomorrow
gog calendar search "meeting" --days 365
gog calendar search "meeting" --from 2025-01-01T00:00:00Z --to 2025-01-31T00:00:00Z --max 50

# Search defaults to 30 days ago through 90 days ahead unless you set --from/--to/--today/--week/--days.
# Tip: set GOG_CALENDAR_WEEKDAY=1 to default --weekday for calendar events output.

# JSON event output includes timezone and localized times (useful for agents).
gog calendar get <calendarId> <eventId> --json
# {
#   "event": {
#     "id": "...",
#     "summary": "...",
#     "startDayOfWeek": "Friday",
#     "endDayOfWeek": "Friday",
#     "timezone": "America/Los_Angeles",
#     "eventTimezone": "America/New_York",
#     "startLocal": "2026-01-23T20:45:00-08:00",
#     "endLocal": "2026-01-23T22:45:00-08:00",
#     "start": { "dateTime": "2026-01-23T23:45:00-05:00" },
#     "end": { "dateTime": "2026-01-24T01:45:00-05:00" }
#   }
# }

# Team calendars (requires Cloud Identity API for Google Workspace)
gog calendar team <group-email> --today           # Show team's events for today
gog calendar team <group-email> --week            # Show team's events for the week (use --week-start)
gog calendar team <group-email> --freebusy        # Show only busy/free blocks (faster)
gog calendar team <group-email> --query "standup" # Filter by event title

# In event mode, --json includes complete and errors fields. If any member
# calendar fails, successful events are still rendered with complete=false and
# one {calendarId,error} entry per failure, then the command exits nonzero.
# In --plain mode, incomplete results use this six-column TSV schema:
# TYPE  WHO  START  END  SUMMARY  ERROR
# Records are typed as event or calendar_error. Complete results keep the
# existing WHO/START/END/SUMMARY schema; --freebusy behavior is unchanged.

# 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

# Send notifications when creating/updating
gog calendar create <calendarId> \
  --summary "Team Sync" \
  --from 2025-01-15T14:00:00Z \
  --to 2025-01-15T15:00:00Z \
  --send-updates all

gog calendar update <calendarId> <eventId> \
  --send-updates externalOnly

# Recurrence + reminders
gog calendar create <calendarId> \
  --summary "Payment" \
  --from 2025-02-11T09:00:00-03:00 \
  --to 2025-02-11T09:15:00-03:00 \
  --rrule "RRULE:FREQ=MONTHLY;BYMONTHDAY=11" \
  --reminder "email:3d" \
  --reminder "popup:30m"

# Special event types via --event-type (focus-time/out-of-office/working-location)
gog calendar create primary \
  --event-type focus-time \
  --from 2025-01-15T13:00:00Z \
  --to 2025-01-15T14:00:00Z

gog calendar create primary \
  --event-type out-of-office \
  --from 2025-01-20 \
  --to 2025-01-21 \
  --all-day

gog calendar create primary \
  --event-type working-location \
  --working-location-type office \
  --working-office-label "HQ" \
  --from 2025-01-22 \
  --to 2025-01-23

# Dedicated shortcuts (same event types, more opinionated defaults)
gog calendar focus-time --from 2025-01-15T13:00:00Z --to 2025-01-15T14:00:00Z
gog calendar out-of-office --from 2025-01-20 --to 2025-01-21 --all-day
gog calendar working-location --type office --office-label "HQ" --from 2025-01-22 --to 2025-01-23
# Add attendees without replacing existing attendees/RSVP state
gog calendar update <calendarId> <eventId> \
  --add-attendee "alice@example.com,bob@example.com"

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
gog calendar respond <calendarId> <eventId> --status declined --send-updates externalOnly

# Propose a new time (browser-only flow; API limitation)
gog calendar propose-time <calendarId> <eventId>
gog calendar propose-time <calendarId> <eventId> --open
gog calendar propose-time <calendarId> <eventId> --decline --comment "Can we do 5pm?"

# 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" \
  --today                             # Today's conflicts

Time

gog time now
gog time now --timezone UTC

Drive

# 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 upload ./path/to/report.docx --convert
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>

# Shared drives (Team Drives)
gog drive drives --max 100

Docs / Slides / Sheets

# Docs
gog docs info <docId>
gog docs info <docId> --tab <tabId>
gog docs cat <docId> --max-bytes 10000
gog docs cat <docId> --tab <tabId>
gog docs create "My Doc"
gog docs copy <docId> "My Doc Copy"
gog docs export <docId> --format pdf --out ./doc.pdf
gog docs insert <docId> --text "Hello" --index 1
gog docs replace <docId> --match "foo" --replace "bar"
gog docs tabs list <docId>
gog docs tabs add <docId> "New Tab"
gog docs tabs delete <docId> <tabId>
gog docs update <docId> --requests-json '[{"insertText":{"text":"Hi","location":{"index":1}}}]'

# 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
gog sheets format <spreadsheetId> 'Sheet1!A1:B2' --format-json '{"textFormat":{"bold":true}}' --format-fields 'userEnteredFormat.textFormat.bold'

Contacts

# 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

Tasks

# Task lists
gog tasks lists --max 50
gog tasks lists create <title>

# Tasks in a list
gog tasks list <tasklistId> --max 50
gog tasks get <tasklistId> <taskId>
gog tasks add <tasklistId> --title "Task title"
gog tasks add <tasklistId> --title "Weekly sync" --due 2025-02-01 --repeat weekly --repeat-count 4
gog tasks add <tasklistId> --title "Daily standup" --due 2025-02-01 --repeat daily --repeat-until 2025-02-05
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>

# Note: Google Tasks treats due dates as date-only; time components may be ignored.

Sheets

# 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 update <spreadsheetId> 'Sheet1!A1:C1' 'new|row|data' --copy-validation-from 'Sheet1!A2:C2'
gog sheets append <spreadsheetId> 'Sheet1!A:C' 'new|row|data'
gog sheets append <spreadsheetId> 'Sheet1!A:C' 'new|row|data' --copy-validation-from 'Sheet1!A2:C2'
gog sheets clear <spreadsheetId> 'Sheet1!A1:B10'

# Format
gog sheets format <spreadsheetId> 'Sheet1!A1:B2' --format-json '{"textFormat":{"bold":true}}' --format-fields 'userEnteredFormat.textFormat.bold'

# Create
gog sheets create "My New Spreadsheet" --sheets "Sheet1,Sheet2"

gog sheets metadata <spreadsheetId> --plain emits headerless TSV with columns SPREADSHEET_ID, SPREADSHEET_TITLE, LOCALE, TIMEZONE, URL, SHEET_ID, SHEET_TITLE, ROWS, and COLUMNS, in that order. It emits one row per sheet; a spreadsheet with no sheets emits one row with the four sheet fields empty.

People

# Profile
gog people me
gog people get people/<userId>

# Search the Workspace directory
gog people search "Ada Lovelace" --max 5

# Relations (defaults to people/me)
gog people relations
gog people relations people/<userId> --type manager

Chat

# Spaces
gog chat spaces list
gog chat spaces find "Engineering"
gog chat spaces create "Engineering" --member alice@company.com --member bob@company.com

# Messages
gog chat messages list spaces/<spaceId> --max 5
gog chat messages list spaces/<spaceId> --thread <threadId>
gog chat messages list spaces/<spaceId> --unread
gog chat messages send spaces/<spaceId> --text "Build complete!" --thread spaces/<spaceId>/threads/<threadId>

# Threads
gog chat threads list spaces/<spaceId>

# Direct messages
gog chat dm space user@company.com
gog chat dm send user@company.com --text "ping"

Note: Chat commands require a Google Workspace account (consumer @gmail.com accounts are not supported).

Groups (Google Workspace)

# List groups you belong to
gog groups list

# List members of a group
gog groups members engineering@company.com

Note: Groups commands require the Cloud Identity API and the cloud-identity.groups.readonly scope. If you get a permissions error, re-authenticate:

gog auth add your@email.com --services groups --force-consent

Classroom (Google Workspace for Education)

# Courses
gog classroom courses list
gog classroom courses list --role teacher
gog classroom courses get <courseId>
gog classroom courses create --name "Math 101"
gog classroom courses update <courseId> --name "Math 102"
gog classroom courses archive <courseId>
gog classroom courses unarchive <courseId>
gog classroom courses url <courseId>

# Roster
gog classroom roster <courseId>
gog classroom roster <courseId> --students
gog classroom students add <courseId> <userId>
gog classroom teachers add <courseId> <userId>

# Coursework
gog classroom coursework list <courseId>
gog classroom coursework get <courseId> <courseworkId>
gog classroom coursework create <courseId> --title "Homework 1" --type ASSIGNMENT --state PUBLISHED
gog classroom coursework update <courseId> <courseworkId> --title "Updated"
gog classroom coursework assignees <courseId> <courseworkId> --mode INDIVIDUAL_STUDENTS --add-student <studentId>

# Materials
gog classroom materials list <courseId>
gog classroom materials create <courseId> --title "Syllabus" --state PUBLISHED

# Submissions
gog classroom submissions list <courseId> <courseworkId>
gog classroom submissions get <courseId> <courseworkId> <submissionId>
gog classroom submissions grade <courseId> <courseworkId> <submissionId> --grade 85
gog classroom submissions return <courseId> <courseworkId> <submissionId>
gog classroom submissions turn-in <courseId> <courseworkId> <submissionId>
gog classroom submissions reclaim <courseId> <courseworkId> <submissionId>

# Announcements
gog classroom announcements list <courseId>
gog classroom announcements create <courseId> --text "Welcome!"
gog classroom announcements update <courseId> <announcementId> --text "Updated"
gog classroom announcements assignees <courseId> <announcementId> --mode INDIVIDUAL_STUDENTS --add-student <studentId>

# Topics
gog classroom topics list <courseId>
gog classroom topics create <courseId> --name "Unit 1"
gog classroom topics update <courseId> <topicId> --name "Unit 2"

# Invitations
gog classroom invitations list
gog classroom invitations create <courseId> <userId> --role student
gog classroom invitations accept <invitationId>

# Guardians
gog classroom guardians list <studentId>
gog classroom guardians get <studentId> <guardianId>
gog classroom guardians delete <studentId> <guardianId>

# Guardian invitations
gog classroom guardian-invitations list <studentId>
gog classroom guardian-invitations create <studentId> --email parent@example.com

# Profiles
gog classroom profile get
gog classroom profile get <userId>

Note: Classroom commands require a Google Workspace for Education account. Personal Google accounts have limited Classroom functionality.

Docs

# 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

Slides

# Export (via Drive)
gog slides export <presentationId> --format pptx --out ./deck.pptx
gog slides export <presentationId> --format pdf --out ./deck.pdf

Output Formats

Text

Human-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-08

Message-level search (one row per email; add --include-body to fetch/decode bodies):

$ gog gmail messages search 'newer_than:7d' --max 3
ID                  THREAD             SUBJECT                           FROM                  DATE
18f1a2b3c4d5e6f7    9e8d7c6b5a4f3e2d    Meeting notes                     alice@example.com     2025-01-10
17e1d2c3b4a5f6e7    9e8d7c6b5a4f3e2d    Invoice #12345                    billing@vendor.com    2025-01-09
16d1c2b3a4e5f6d7    7f6e5d4c3b2a1908    Project update                    bob@example.com       2025-01-08

JSON

Machine-readable output for scripting and automation:

$ gog gmail search 'newer_than:7d' --max 3 --json
{
  "threads": [
    {
      "id": "18f1a2b3c4d5e6f7",
      "snippet": "Meeting notes from today...",
      "messages": [...]
    },
    ...
  ]
}
$ gog gmail messages search 'newer_than:7d' --max 3 --json
{
  "messages": [
    {
      "id": "18f1a2b3c4d5e6f7",
      "threadId": "9e8d7c6b5a4f3e2d",
      "subject": "Meeting notes",
      "from": "alice@example.com",
      "date": "2025-01-10"
    },
    ...
  ]
}
$ gog gmail messages search 'newer_than:7d' --max 1 --include-body --json
{
  "messages": [
    {
      "id": "18f1a2b3c4d5e6f7",
      "threadId": "9e8d7c6b5a4f3e2d",
      "subject": "Meeting notes",
      "from": "alice@example.com",
      "date": "2025-01-10",
      "body": "Hi team — meeting notes..."
    }
  ]
}

Data goes to stdout, errors and progress to stderr for clean piping. Built-in projection can replace common envelope-scraping jq usage:

# Emit the file array without nextPageToken, then retain only selected fields.
gog --json --results-only --select id,name,mimeType drive ls --max 5

# Filtering expressions remain a jq use case.
gog --json --results-only drive ls --max 5 | jq '.[] | select(.mimeType=="application/pdf")'

--select projects objects or each object in an array. It is separate from command-specific options such as Calendar's --fields: --fields controls the Google API partial response, while --select shapes the JSON printed by gog; they can be combined.

Calendar JSON convenience fields:

  • startDayOfWeek / endDayOfWeek on event payloads (derived from start/end).

Examples

Search recent emails and download attachments

# 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 get <threadId> --download

Modify labels on a thread

# Archive and star a thread
gog gmail thread modify <threadId> --remove INBOX --add STARRED

Create a calendar event with attendees

# 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"

Find and download files from Drive

# 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

Manage multiple accounts

# 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'

Update a Google Sheet from a CSV

# Convert CSV to pipe-delimited format and update sheet
cat data.csv | tr ',' '|' | \
  gog sheets update <spreadsheetId> 'Sheet1!A1'

Export Sheets / Docs / Slides

# Sheets
gog sheets export <spreadsheetId> --format pdf

# Docs
gog docs export <docId> --format docx

# Slides
gog slides export <presentationId> --format pptx

Batch process Gmail threads

# Mark all emails from a sender as read
gog --json gmail search 'from:noreply@example.com' --max 200 | \
  jq -r '.threads[].id' | \
  xargs -n 50 gog gmail labels modify --remove UNREAD

# Archive old emails
gog --json gmail search 'older_than:1y' --max 200 | \
  jq -r '.threads[].id' | \
  xargs -n 50 gog gmail labels modify --remove INBOX

# Label important emails
gog --json gmail search 'from:boss@example.com' --max 200 | \
  jq -r '.threads[].id' | \
  xargs -n 50 gog gmail labels modify --add IMPORTANT

Advanced Features

Verbose Mode

Enable verbose logging for troubleshooting:

gog --verbose gmail search 'newer_than:7d'
# Shows API requests and responses

Global Flags

All commands support these flags:

  • --account <email|alias|auto> - Account to use (overrides GOG_ACCOUNT)
  • --enable-commands <csv> - Allowlist top-level commands (e.g., calendar,tasks)
  • --enable-command-paths <csv> - Allowlist exact command paths (e.g., gmail search,calendar events)
  • --json - Output JSON to stdout (best for scripting)
  • --results-only - Output the command's declared primary result (requires --json)
  • --select <paths> - Project comma-separated dotted paths from JSON output (requires --json)
  • --plain - Output stable, parseable text to stdout (TSV; no colors)
  • --color <mode> - Color mode: auto, always, or never (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

Shell Completions

Generate shell completions for your preferred shell:

Bash

# 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)

Zsh

# 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" >> ~/.zshrc

Fish

gog completion fish > ~/.config/fish/completions/gog.fish

PowerShell

# Load for current session
gog completion powershell | Out-String | Invoke-Expression

# Or add to profile for all sessions
gog completion powershell >> $PROFILE

After installing completions, start a new shell session for changes to take effect.

Development

After cloning, install tools:

make tools

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.

Integration Tests (Live Google APIs)

Opt-in tests that hit real Google APIs using your stored gog credentials/tokens.

# Optional: override which account to use
export GOG_IT_ACCOUNT=you@gmail.com
export GOG_CLIENT=work
go test -tags=integration ./...

Tip: if you want to avoid macOS Keychain prompts during these runs, set GOG_KEYRING_BACKEND=file and GOG_KEYRING_PASSWORD=... (uses encrypted on-disk keyring).

Live Test Script (CLI)

Fast end-to-end smoke checks against live APIs:

scripts/live-test.sh --fast
scripts/live-test.sh --account you@gmail.com --skip groups,keep,calendar-enterprise
scripts/live-test.sh --client work --account you@company.com

Script toggles:

  • --auth all,groups to re-auth before running
  • --client <name> to select OAuth client credentials
  • --strict to fail on optional features (groups/keep/enterprise)
  • --allow-nontest to override the test-account guardrail

Go test wrapper (opt-in):

GOG_LIVE=1 go test -tags=integration ./internal/integration -run Live

Optional env:

  • GOG_LIVE_FAST=1
  • GOG_LIVE_SKIP=groups,keep
  • GOG_LIVE_AUTH=all,groups
  • GOG_LIVE_ALLOW_NONTEST=1
  • GOG_LIVE_EMAIL_TEST=test-account@example.com (required for Gmail send and Drive sharing tests)
  • GOG_LIVE_GROUP_EMAIL=group@domain
  • GOG_LIVE_CLASSROOM_COURSE=<courseId>
  • GOG_LIVE_CLASSROOM_CREATE=1
  • GOG_LIVE_CLASSROOM_ALLOW_STATE=1
  • GOG_LIVE_TRACK=1
  • GOG_LIVE_GMAIL_BATCH_DELETE=1
  • GOG_LIVE_GMAIL_FILTERS=1
  • GOG_LIVE_GMAIL_WATCH_TOPIC=projects/.../topics/...
  • GOG_LIVE_CALENDAR_RESPOND=1
  • GOG_LIVE_CALENDAR_RECURRENCE=1
  • GOG_KEEP_SERVICE_ACCOUNT=/path/to/service-account.json
  • GOG_KEEP_IMPERSONATE=user@workspace-domain

Make Shortcut

Build and run:

make gog auth add you@gmail.com

For clean stdout when scripting:

  • Use -- when the first arg is a flag: make gog -- --json gmail search "from:me" | jq .

License

MIT

Links

Credits

This Robben Media fork is based on Peter Steinberger's original gogcli. We are grateful for the foundation he created and retain attribution under the MIT license while maintaining this fork independently going forward.

The original project was inspired by Mario Zechner's CLIs:

About

Google Suite CLI: Gmail, GCal, GDrive, GContacts.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages