An open API service indexing awesome lists of open source software.

https://github.com/steipete/gogcli

Google Suite CLI: Gmail, GCal, GDrive, GContacts.
https://github.com/steipete/gogcli

gcal gcontacts gdrive gmail google

Last synced: 1 day ago
JSON representation

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

Awesome Lists containing this project

README

          

# 🧭 gogcli — Google in your terminal.

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, 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 commands 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

### Homebrew

```bash
brew install steipete/tap/gogcli
```

### Build from Source

```bash
git clone https://github.com/steipete/gogcli.git
cd gogcli
make
```

Run:

```bash
./bin/gog --help
```

Help:

- `gog --help` shows top-level command groups.
- Drill down with `gog --help` (and deeper subcommands).
- For the full expanded command list: `GOG_HELP=full gog --help`.
- 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
1. Create a project: https://console.cloud.google.com/projectcreate
2. 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
3. Configure OAuth consent screen: https://console.cloud.google.com/auth/branding
4. If your app is in "Testing", add test users: https://console.cloud.google.com/auth/audience
5. 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`)

### 2. Store Credentials

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

### 3. Authorize Your Account

```bash
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.

### 4. Test Authentication

```bash
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 ` (download a Desktop app OAuth client JSON from the Cloud Console).

List accounts:

```bash
gog auth list
```

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

```bash
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:

```bash
gog auth status
```

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

```bash
gog auth keyring file
gog auth keyring keychain
gog auth keyring auto
```

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

```bash
gog auth keyring
```

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

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

Force backend via env (overrides config):

```bash
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:

```bash
# 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:

```bash
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).
- Human-facing hints/progress go to stderr.
- Colors are enabled only in rich TTY output and are disabled automatically for `--json` and `--plain`.

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

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

To request read-only scopes (write operations will fail with 403 insufficient scopes):

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

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

```bash
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`.

If you need to add services later and Google doesn't return a refresh token, re-run with `--force-consent`:

```bash
gog auth add you@gmail.com --services user --force-consent
# Or add just Sheets
gog auth add you@gmail.com --services sheets --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) |

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

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

Verify `gog` is preferring the service account for that account:

```bash
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:

```bash
gog auth service-account set you@yourdomain.com --key ~/Downloads/service-account.json
gog keep list --account you@yourdomain.com
gog keep get --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_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`)

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

```json5
{
// 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",
},
}
```

### Config Commands

```bash
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

```bash
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)

```bash
# Only allow calendar + tasks commands for an agent
gog --enable-commands calendar,tasks calendar events --today

# Same via env
export GOG_ENABLE_COMMANDS=calendar,tasks
gog tasks list
```

## 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](https://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 `

## Commands

Flag aliases:
- `--out` also accepts `--output`.
- `--out-dir` also accepts `--output-dir` (Gmail thread attachment downloads).

### Authentication

```bash
gog auth credentials # Store OAuth client credentials
gog auth add # Authorize and store refresh token
gog auth service-account set --key # Configure service account impersonation (Workspace only)
gog auth service-account status # Show service account status
gog auth service-account unset # Remove service account
gog auth keep --key # Legacy alias (Keep)
gog auth keyring [backend] # Show/set keyring backend (auto|keychain|file)
gog auth status # Show current auth state/services
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 # Remove a stored refresh token
gog auth manage # Open accounts manager in browser
gog auth tokens # Manage stored refresh tokens
```

### Keep (Workspace only)

```bash
gog keep list --account you@yourdomain.com
gog keep get --account you@yourdomain.com
gog keep search --account you@yourdomain.com
gog keep attachment --account you@yourdomain.com --out ./attachment.bin
```

### Gmail

```bash
# Search and read
gog gmail search 'newer_than:7d' --max 10
gog gmail thread get
gog gmail thread get --download # Download attachments to current dir
gog gmail thread get --download --out-dir ./attachments
gog gmail get
gog gmail get --format metadata
gog gmail attachment
gog gmail attachment --out ./attachment.bin
gog gmail url # Print Gmail web URL
gog gmail thread modify --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 "

Hello

"
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 --subject "Draft" --body "Body"
gog gmail drafts update --to a@b.com --subject "Draft" --body "Body"
gog gmail drafts send

# Labels
gog gmail labels list
gog gmail labels get INBOX --json # Includes message counts
gog gmail labels create "My Label"
gog gmail labels update --name "New Name"
gog gmail labels delete

# Batch operations
gog gmail batch mark-read --query 'older_than:30d'
gog gmail batch delete --query 'from:spam@example.com'
gog gmail batch label --query 'from:boss@example.com' --add-labels IMPORTANT

# Filters
gog gmail filters list
gog gmail filters create --from 'noreply@example.com' --label 'Notifications'
gog gmail filters delete

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

/topics/ --label INBOX
gog gmail watch serve --bind 127.0.0.1 --token --hook-url http://127.0.0.1:18789/hooks/agent
gog gmail watch serve --bind 0.0.0.0 --verify-oidc --oidc-email --hook-url
gog gmail history --since
```

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:

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

# Send with tracking
gog gmail send --to recipient@example.com --subject "Hello" --body-html "

Hi!

" --track

# Check opens
gog gmail track opens
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

```bash
# Calendars
gog calendar calendars
gog calendar acl # 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 --today # Today's events
gog calendar events --tomorrow # Tomorrow's events
gog calendar events --week # This week (Mon-Sun by default; use --week-start)
gog calendar events --days 3 # Next 3 days
gog calendar events --from today --to friday # Relative dates
gog calendar events --from 2025-01-01T00:00:00Z --to 2025-01-08T00:00:00Z
gog calendar events --all # Fetch events from all calendars
gog calendar 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.

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

# Create and update
gog calendar create \
--summary "Meeting" \
--from 2025-01-15T10:00:00Z \
--to 2025-01-15T11:00:00Z

gog calendar create \
--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 \
--summary "Updated Meeting" \
--from 2025-01-15T11:00:00Z \
--to 2025-01-15T12:00:00Z

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

gog calendar update \
--send-updates externalOnly

# Recurrence + reminders
gog calendar create \
--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 \
--add-attendee "alice@example.com,bob@example.com"

gog calendar delete

# Invitations
gog calendar respond --status accepted
gog calendar respond --status declined
gog calendar respond --status tentative
gog calendar respond --status declined --send-updates externalOnly

# Propose a new time (browser-only flow; API limitation)
gog calendar propose-time
gog calendar propose-time --open
gog calendar propose-time --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

```bash
gog time now
gog time now --timezone UTC
```

### Drive

```bash
# List and search
gog drive ls --max 20
gog drive ls --parent --max 20
gog drive search "invoice" --max 20
gog drive get # Get file metadata
gog drive url # Print Drive web URL
gog drive copy "Copy Name"

# Upload and download
gog drive upload ./path/to/file --parent
gog drive download --out ./downloaded.bin
gog drive download --format pdf --out ./exported.pdf
gog drive download --format docx --out ./doc.docx
gog drive download --format pptx --out ./slides.pptx

# Organize
gog drive mkdir "New Folder"
gog drive mkdir "New Folder" --parent
gog drive rename "New Name"
gog drive move --parent
gog drive delete # Move to trash

# Permissions
gog drive permissions
gog drive share --email user@example.com --role reader
gog drive share --email user@example.com --role writer
gog drive unshare --permission-id

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

### Docs / Slides / Sheets

```bash
# Docs
gog docs info
gog docs cat --max-bytes 10000
gog docs create "My Doc"
gog docs copy "My Doc Copy"
gog docs export --format pdf --out ./doc.pdf

# Slides
gog slides info
gog slides create "My Deck"
gog slides copy "My Deck Copy"
gog slides export --format pdf --out ./deck.pdf

# Sheets
gog sheets copy "My Sheet Copy"
gog sheets export --format pdf --out ./sheet.pdf
gog sheets format 'Sheet1!A1:B2' --format-json '{"textFormat":{"bold":true}}' --format-fields 'userEnteredFormat.textFormat.bold'
```

### Contacts

```bash
# Personal contacts
gog contacts list --max 50
gog contacts search "Ada" --max 50
gog contacts get people/
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/ \
--given-name "Jane" \
--email "jane@example.com"

gog contacts delete people/

# Workspace directory (requires Google Workspace)
gog contacts directory list --max 50
gog contacts directory search "Jane" --max 50
```

### Tasks

```bash
# Task lists
gog tasks lists --max 50
gog tasks lists create

# Tasks in a list
gog tasks list --max 50
gog tasks get
gog tasks add --title "Task title"
gog tasks add --title "Weekly sync" --due 2025-02-01 --repeat weekly --repeat-count 4
gog tasks add --title "Daily standup" --due 2025-02-01 --repeat daily --repeat-until 2025-02-05
gog tasks update --title "New title"
gog tasks done
gog tasks undo
gog tasks delete
gog tasks clear

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

### Sheets

```bash
# Read
gog sheets metadata
gog sheets get 'Sheet1!A1:B10'

# Export (via Drive)
gog sheets export --format pdf --out ./sheet.pdf
gog sheets export --format xlsx --out ./sheet.xlsx

# Write
gog sheets update 'A1' 'val1|val2,val3|val4'
gog sheets update 'A1' --values-json '[["a","b"],["c","d"]]'
gog sheets update 'Sheet1!A1:C1' 'new|row|data' --copy-validation-from 'Sheet1!A2:C2'
gog sheets append 'Sheet1!A:C' 'new|row|data'
gog sheets append 'Sheet1!A:C' 'new|row|data' --copy-validation-from 'Sheet1!A2:C2'
gog sheets clear 'Sheet1!A1:B10'

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

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

### People

```bash
# Profile
gog people me
gog people get people/

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

# Relations (defaults to people/me)
gog people relations
gog people relations people/ --type manager
```

### Chat

```bash
# 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/ --max 5
gog chat messages list spaces/ --thread
gog chat messages list spaces/ --unread
gog chat messages send spaces/ --text "Build complete!" --thread spaces//threads/

# Threads
gog chat threads list spaces/

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

```bash
# 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:

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

### Classroom (Google Workspace for Education)

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

# Roster
gog classroom roster
gog classroom roster --students
gog classroom students add
gog classroom teachers add

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

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

# Submissions
gog classroom submissions list
gog classroom submissions get
gog classroom submissions grade --grade 85
gog classroom submissions return
gog classroom submissions turn-in
gog classroom submissions reclaim

# Announcements
gog classroom announcements list
gog classroom announcements create --text "Welcome!"
gog classroom announcements update --text "Updated"
gog classroom announcements assignees --mode INDIVIDUAL_STUDENTS --add-student

# Topics
gog classroom topics list
gog classroom topics create --name "Unit 1"
gog classroom topics update --name "Unit 2"

# Invitations
gog classroom invitations list
gog classroom invitations create --role student
gog classroom invitations accept

# Guardians
gog classroom guardians list
gog classroom guardians get
gog classroom guardians delete

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

# Profiles
gog classroom profile get
gog classroom profile get
```

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

### Docs

```bash
# Export (via Drive)
gog docs export --format pdf --out ./doc.pdf
gog docs export --format docx --out ./doc.docx
gog docs export --format txt --out ./doc.txt
```

### Slides

```bash
# Export (via Drive)
gog slides export --format pptx --out ./deck.pptx
gog slides export --format pdf --out ./deck.pdf
```

## Output Formats

### Text

Human-readable output with colors (default):

```bash
$ 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
```

### JSON

Machine-readable output for scripting and automation:

```bash
$ gog gmail search 'newer_than:7d' --max 3 --json
{
"threads": [
{
"id": "18f1a2b3c4d5e6f7",
"snippet": "Meeting notes from today...",
"messages": [...]
},
...
]
}
```

Data goes to stdout, errors and progress to stderr for clean piping:

```bash
gog --json drive ls --max 5 | jq '.files[] | select(.mimeType=="application/pdf")'
```

Useful pattern:

- `gog --json ... | jq .`

Calendar JSON convenience fields:

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

## Examples

### Search recent emails and download attachments

```bash
# 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 --download
```

### Modify labels on a thread

```bash
# Archive and star a thread
gog gmail thread modify --remove INBOX --add STARRED
```

### Create a calendar event with attendees

```bash
# 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

```bash
# 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

```bash
# 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

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

### Export Sheets / Docs / Slides

```bash
# Sheets
gog sheets export --format pdf

# Docs
gog docs export --format docx

# Slides
gog slides export --format pptx
```

### Batch process Gmail threads

```bash
# Mark all emails from a sender as read
gog gmail batch mark-read --query 'from:noreply@example.com'

# Archive old emails
gog gmail batch archive --query 'older_than:1y'

# Label important emails
gog gmail batch label --query 'from:boss@example.com' --add-labels IMPORTANT
```

## Advanced Features

### Verbose Mode

Enable verbose logging for troubleshooting:

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

## Global Flags

All commands support these flags:

- `--account ` - Account to use (overrides GOG_ACCOUNT)
- `--enable-commands ` - Allowlist top-level commands (e.g., `calendar,tasks`)
- `--json` - Output JSON to stdout (best for scripting)
- `--plain` - Output stable, parseable text to stdout (TSV; no colors)
- `--color ` - 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

```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

```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

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

### PowerShell

```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:

```bash
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.

```bash
# Optional: override which account to use
export GOG_IT_ACCOUNT=you@gmail.com
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:

```bash
scripts/live-test.sh --fast
scripts/live-test.sh --account you@gmail.com --skip groups,keep,calendar-enterprise
```

Script toggles:

- `--auth all,groups` to re-auth before running
- `--strict` to fail on optional features (groups/keep/enterprise)
- `--allow-nontest` to override the test-account guardrail

Go test wrapper (opt-in):

```bash
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=steipete+gogtest@gmail.com`
- `GOG_LIVE_GROUP_EMAIL=group@domain`
- `GOG_LIVE_CLASSROOM_COURSE=`
- `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:

```bash
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

- [GitHub Repository](https://github.com/steipete/gogcli)
- [Gmail API Documentation](https://developers.google.com/gmail/api)
- [Google Calendar API Documentation](https://developers.google.com/calendar)
- [Google Drive API Documentation](https://developers.google.com/drive)
- [Google People API Documentation](https://developers.google.com/people)
- [Google Tasks API Documentation](https://developers.google.com/tasks)
- [Google Sheets API Documentation](https://developers.google.com/sheets)
- [Cloud Identity API Documentation](https://cloud.google.com/identity/docs/reference/rest)

## Credits

This project is inspired by Mario Zechner's original CLIs:

- [gmcli](https://github.com/badlogic/gmcli)
- [gccli](https://github.com/badlogic/gccli)
- [gdcli](https://github.com/badlogic/gdcli)