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.
- 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 --trackwith 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 -
--readonlyand--drive-scopeto 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)
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/gogVerify the installed binary:
gog --version
gog --helpUpstream 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.
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 skillsAgents: 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 --helpshows 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 schemaemits one deterministic, versioned JSON document describing visible commands, aliases, arguments, flags, global flags, exit-code classes, and effective automation/policy state. gog schemais read-only and remains available under--enable-commandsrestrictions; 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(ormake gog -- gmail --help). make gog-helpshows CLI help (note:make gog --helpis Make’s own help; use--).
Before adding an account, create OAuth2 credentials from Google Cloud Console:
- Open the Google Cloud Console credentials page: https://console.cloud.google.com/apis/credentials
- 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 Chat API: https://console.cloud.google.com/apis/api/chat.googleapis.com
- Google Drive API: https://console.cloud.google.com/apis/api/drive.googleapis.com
- Google Classroom API: https://console.cloud.google.com/apis/api/classroom.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
- Cloud Identity API (Groups): https://console.cloud.google.com/apis/api/cloudidentity.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)
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 setupNon-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.jsonSee docs/auth-clients.md for flags, acknowledgments, and exit codes. Advanced users can still run the manual steps below.
gog auth credentials ~/Downloads/client_secret_....jsonFor multiple OAuth clients/projects:
gog --client work auth credentials ~/Downloads/work-client.json
gog auth credentials listgog 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 listgog 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 listVerify tokens are usable (helps spot revoked/expired tokens):
gog auth list --checkAccounts 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 statusRun a read-only auth health check (config, keyring, credentials, accounts, token usability):
gog auth doctor
gog --json auth doctorUse --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.comOptional domain mapping for auto-selection:
gog --client work auth credentials ~/Downloads/work.json --domain example.comHow it works:
- Default client is
default(stored incredentials.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):
--client/GOG_CLIENTaccount_clientsconfig (email -> client)client_domainsconfig (domain -> client)- Credentials file named after the email domain (
credentials-example.com.json) default
Config example (JSON5):
{
account_clients: { "you@company.com": "work" },
client_domains: { "example.com": "work" },
}List stored credentials:
gog auth credentials listSee docs/auth-clients.md for the full client selection and mapping rules.
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 autoShow current backend + source (env/config/default) and config path:
gog auth keyringNon-interactive runs (CI/ssh): file backend requires GOG_KEYRING_PASSWORD.
export GOG_KEYRING_PASSWORD='...'
gog --no-input auth statusForce backend via env (overrides config):
export GOG_KEYRING_BACKEND=filePrecedence: GOG_KEYRING_BACKEND env var overrides config.json.
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 autoList 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).--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 asid,nameorsender.email; dotted paths preserve nested shape and missing fields are omitted.- When combined,
--results-onlyruns 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--plainor 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
--jsonand--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.
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,calendarTo request read-only scopes for a new account:
gog auth add you@gmail.com --services drive,calendar --readonlyTo 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 fileNotes:
--drive-scope readonlyis enough for listing/downloading/exporting via Drive (write operations will 403).--drive-scope fileis 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,
--readonlyretains them; add--replace-scopesto 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-consentTo 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-scopesTo 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.modifyhttps://www.googleapis.com/auth/gmail.settings.basichttps://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.spaceshttps://www.googleapis.com/auth/chat.messageshttps://www.googleapis.com/auth/chat.membershipshttps://www.googleapis.com/auth/chat.users.readstate.readonly |
|
| classroom | yes | Classroom API | https://www.googleapis.com/auth/classroom.courseshttps://www.googleapis.com/auth/classroom.rostershttps://www.googleapis.com/auth/classroom.coursework.studentshttps://www.googleapis.com/auth/classroom.coursework.mehttps://www.googleapis.com/auth/classroom.courseworkmaterialshttps://www.googleapis.com/auth/classroom.announcementshttps://www.googleapis.com/auth/classroom.topicshttps://www.googleapis.com/auth/classroom.guardianlinks.studentshttps://www.googleapis.com/auth/classroom.profile.emailshttps://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/drivehttps://www.googleapis.com/auth/documents |
Export/copy/create via Drive |
| contacts | yes | People API | https://www.googleapis.com/auth/contactshttps://www.googleapis.com/auth/contacts.other.readonlyhttps://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/drivehttps://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/bigqueryhttps://www.googleapis.com/auth/bigquery.readonly |
|
| analytics | yes | Analytics Data API, Analytics Admin API | https://www.googleapis.com/auth/analytics.readonlyhttps://www.googleapis.com/auth/analytics.edithttps://www.googleapis.com/auth/analytics.manage.users.readonlyhttps://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.readonlyhttps://www.googleapis.com/auth/webmasters |
|
| tagmanager | yes | Tag Manager API v2 | https://www.googleapis.com/auth/tagmanager.readonlyhttps://www.googleapis.com/auth/tagmanager.edit.containershttps://www.googleapis.com/auth/tagmanager.edit.containerversionshttps://www.googleapis.com/auth/tagmanager.manage.accountshttps://www.googleapis.com/auth/tagmanager.manage.usershttps://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.
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).
- Create (or pick) a Google Cloud project.
- Enable the APIs you’ll use (e.g. Gmail, Calendar, Drive, Sheets, Docs, People, Tasks, Cloud Identity).
- Go to IAM & Admin → Service Accounts and create a service account.
- In the service account details, enable Domain-wide delegation.
- Create a key (Keys → Add key → Create new key → JSON) and download the JSON key file.
Domain-wide delegation is enforced by Workspace admin settings.
- Open Admin console → Security → API controls → Domain-wide delegation.
- 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 servicesand/or yourgog 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).
Store the key for the user you want to impersonate:
gog auth service-account set you@yourdomain.com --key ~/Downloads/service-account.jsonVerify gog is preferring the service account for that account:
gog --account you@yourdomain.com auth status
gog auth listKeep 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.comGOG_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 outputGOG_PLAIN- Default plain outputGOG_COLOR- Color mode:auto(default),always, orneverGOG_TIMEZONE- Default output timezone for Calendar/Gmail (IANA name,UTC, orlocal)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)
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",
},
}gog config path
gog config list
gog config keys
gog config get default_timezone
gog config set default_timezone UTC
gog config unset default_timezonegog auth alias set work work@company.com
gog auth alias list
gog auth alias unset workAliases work anywhere you pass --account or GOG_ACCOUNT (reserved: auto, default).
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 threaddoes not allowgmail 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
policyrules 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'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.
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
gogbinary 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).
- To avoid password prompts too (CI/non-interactive): set
- 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>
Flag aliases:
--outalso accepts--output.--out-diralso accepts--output-dir(Gmail thread attachment downloads).
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 tokensgog 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# 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:NAMEismessage_countandVALUEis the count;MESSAGE_IDis empty.header:NAMEisFrom,To,Subject, orDate;VALUEis the header value.body:VALUEis the selected body, using the same HTML cleanup and preview truncation as human output.attachment:NAMEis the filename,VALUEis the MIME type,PATHis the Gmail attachment ID, andBYTESis the declared attachment size.download:NAMEis the filename,PATHis the committed on-disk path,BYTESis the exact committed byte count, andCACHEDistrueorfalse.
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.
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 statusDocs: 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.
# 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 conflictsgog time now
gog time now --timezone UTC# 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
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'# 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 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.# 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.
# 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# 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).
# List groups you belong to
gog groups list
# List members of a group
gog groups members engineering@company.comNote: 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# 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.
# 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-08Message-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-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": [...]
},
...
]
}$ 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/endDayOfWeekon event payloads (derived from start/end).
# 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# Archive and star a thread
gog gmail thread modify <threadId> --remove INBOX --add STARRED# 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 --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 IMPORTANTEnable verbose logging for troubleshooting:
gog --verbose gmail search 'newer_than:7d'
# Shows API requests and responsesAll 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, 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 tools:
make toolsPinned 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.
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).
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.comScript toggles:
--auth all,groupsto re-auth before running--client <name>to select OAuth client credentials--strictto fail on optional features (groups/keep/enterprise)--allow-nontestto override the test-account guardrail
Go test wrapper (opt-in):
GOG_LIVE=1 go test -tags=integration ./internal/integration -run LiveOptional env:
GOG_LIVE_FAST=1GOG_LIVE_SKIP=groups,keepGOG_LIVE_AUTH=all,groupsGOG_LIVE_ALLOW_NONTEST=1GOG_LIVE_EMAIL_TEST=test-account@example.com(required for Gmail send and Drive sharing tests)GOG_LIVE_GROUP_EMAIL=group@domainGOG_LIVE_CLASSROOM_COURSE=<courseId>GOG_LIVE_CLASSROOM_CREATE=1GOG_LIVE_CLASSROOM_ALLOW_STATE=1GOG_LIVE_TRACK=1GOG_LIVE_GMAIL_BATCH_DELETE=1GOG_LIVE_GMAIL_FILTERS=1GOG_LIVE_GMAIL_WATCH_TOPIC=projects/.../topics/...GOG_LIVE_CALENDAR_RESPOND=1GOG_LIVE_CALENDAR_RECURRENCE=1GOG_KEEP_SERVICE_ACCOUNT=/path/to/service-account.jsonGOG_KEEP_IMPERSONATE=user@workspace-domain
Build and run:
make gog auth add you@gmail.comFor clean stdout when scripting:
- Use
--when the first arg is a flag:make gog -- --json gmail search "from:me" | jq .
MIT
- Robben Media fork
- Original project by Peter Steinberger
- Gmail API Documentation
- Google Calendar API Documentation
- Google Drive API Documentation
- Google People API Documentation
- Google Tasks API Documentation
- Google Sheets API Documentation
- Cloud Identity API Documentation
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: