| name | gog |
| description | gog: sandboxed Google Workspace CLI for SwiftBash — JSON-first reads and host-gated writes across Drive, Gmail, Calendar, Tasks, Sheets, Contacts and more, with host-managed auth. |
gog
gog is a Google Workspace CLI that runs inside SwiftBash's sandbox. Use it
to read and write Google Drive, Gmail, Calendar, Tasks, Sheets, Contacts and
more from shell automation that needs stable JSON. Writes are gated by a
host-set capability tier (read-only by default). It pipes like any other command:
gog drive ls --max 20 --json | jq '.files[].name'
How it runs (sandbox model)
- Auth is host-managed. The app injects a Google access token for the active
account;
gog never performs OAuth, stores credentials, or reads tokens from
the environment. There is no gog auth add / login here. On an expired token
gog asks the host to refresh and retries once; if it still fails it exits 7
("re-auth required") for the host to handle.
- Files stay in the sandbox. Reads and writes go through the mounted
workspace (e.g.
/gog). Paths outside the mounts are rejected, so download
and upload targets must be sandbox paths.
- Network is allow-listed. Only Google API hosts are reachable; with no
network configured, networked commands fail closed (exit 7).
- JSON for agents. Pass
--json for machine-readable output. Data goes to
stdout; hints, progress, and errors go to stderr.
Safety rules
- Never print tokens or secrets.
gog does not emit them, they are not in
the environment, and you should not try to extract or echo credentials.
- Data writes need a host-granted tier. Every create / edit / delete across
Drive, Gmail (labels · trash · drafts), Calendar, Tasks, Sheets, and Contacts
is gated by a write tier the host sets — read-only by default, so writes
refuse with exit 3 until the host grants
edit (additive / in-place /
reversible: create, rename, update, append, mkdir, cp, untrash, label edits)
or full (also destructive or exposing: delete, trash, move, share, unshare,
clear, adding the TRASH/SPAM labels, and copying or uploading into a folder).
You cannot raise this from the command line — it is host-only. If a write
exits 3 with "needs write tier …", it wasn't granted; don't try to bypass it.
- Sending and directory writes have separate switches.
gog gmail send and
gog chat send refuse (exit 3) when the host disables sending; gog admin
suspend/unsuspend and member-add/remove are off by default (domain-wide
blast radius) until the host enables admin writes. These are independent of the
write tier above.
- Preview writes with
--dry-run where supported. Most mutating commands
build and print the request without calling Google when --dry-run is passed
(a few simple writes — e.g. drive upload, tasks add — omit it). Use it
before a mutation when available; only mutate when that is the requested task.
- Command availability is host-controlled. The host registers only the
commands it allows; if a command isn't available, it wasn't enabled.
Identity
gog me --json
gog whoami
gog auth status
Drive
gog drive ls --max 20 --json
gog drive ls --parent <folderId> --json
gog drive search 'quarterly report' --json
gog drive get <fileId> --json
gog drive download <fileId> --out /gog/report.pdf
gog drive permissions <fileId> --json
gog drive revisions <fileId> --json
gog drive about --json
gog drive upload /gog/report.pdf --name Report.pdf
gog drive mkdir 'Q3 Reports' --parent <folderId>
gog drive rename <fileId> --name 'Final.pdf'
gog drive cp <fileId> --name Copy.pdf
gog drive untrash <fileId>
gog drive trash <fileId>
gog drive mv <fileId> --to <folderId> [--from <oldId>]
gog drive share <fileId> --email user@x.com --role reader
gog drive share <fileId> --anyone --role reader
gog drive unshare <fileId> --permission <permId>
download writes into the sandbox workspace — choose a path under a mount
(e.g. /gog/...).
Gmail
gog gmail messages --max 20 --json
gog gmail messages -q 'newer_than:7d from:example@example.com' --json
gog gmail get <messageId> --json
gog gmail send --to user@example.com --subject 'Hi' --body 'Hello' --dry-run
gog gmail labels --json
gog gmail threads -q 'newer_than:7d' --json
gog gmail thread <threadId> --json
gog gmail drafts --json
gog gmail draft --to user@example.com --subject 'Hi' --body 'Hello'
gog gmail attachments <messageId> --json
gog gmail attachment <messageId> <attachmentId> --out /gog/file.pdf
gog gmail modify <messageId> --add-label STARRED --remove-label UNREAD
gog gmail untrash <messageId>
gog gmail trash <messageId>
Drop --dry-run to actually send (subject to the host send policy). gog gmail draft only composes — it never sends (so it isn't gated by the send policy) — but it is an .edit write that saves a draft, so it needs the write tier.
Calendar
gog calendar events --max 20 --json
gog calendar events --from 2026-06-01T00:00:00Z --json
gog calendar get <eventId> --json
gog calendar create --summary 'Standup' \
--start 2026-06-02T10:00:00Z --end 2026-06-02T10:30:00Z --dry-run
gog calendar calendars --json
gog calendar freebusy --json
gog calendar freebusy --from <RFC3339> --to <RFC3339> \
--calendar primary --calendar team@example.com --json
gog calendar update <eventId> --summary 'Renamed' --dry-run
gog calendar delete <eventId>
Contacts
gog contacts list --max 20 --json
gog contacts get people/c123 --json
gog contacts search 'jane' --json
gog contacts other --json
gog contacts create --given Jane --family Doe --email jane@x.com
gog contacts update people/c123 --given Janet
gog contacts delete people/c123
Tasks
gog tasks lists --json
gog tasks list --list <listId> --json
gog tasks add 'Buy milk' --list <listId>
gog tasks complete <taskId> --list <listId>
gog tasks delete <taskId> --list <listId>
Docs
gog docs cat <documentId>
gog docs cat <documentId> --format markdown
gog docs cat <documentId> --out /gog/doc.md
gog docs create --title 'Notes'
gog docs append <documentId> --text 'A new paragraph.'
gog docs find-replace <documentId> --find foo --replace bar
gog docs clear <documentId>
gog docs insert-table <documentId> --rows 2 --cols 3
gog docs insert-image <documentId> --url https://ex.com/logo.png
gog docs fill-table <documentId> --values-json '[["a","b"],["c","d"]]'
Sheets
gog sheets get <spreadsheetId> 'Sheet1!A1:D20' --json
gog sheets update <spreadsheetId> 'Sheet1!A1' --values-json '[["hello","world"]]' --dry-run
gog sheets append <spreadsheetId> 'Sheet1!A1' --values-json '[["a","b"]]'
gog sheets clear <spreadsheetId> 'Sheet1!A1:D9'
Slides
gog slides export <presentationId> --out /gog/deck.pdf
gog slides export <presentationId> --mime text/plain --out /gog/deck.txt
gog slides create --title 'Deck'
gog slides add-slide <presentationId>
gog slides create-table <presentationId> <slideObjectId> --rows 2 --cols 3
gog slides create-textbox <presentationId> <slideObjectId> --text 'Hi'
gog slides create-image <presentationId> <slideObjectId> --url https://ex.com/logo.png
gog slides replace-text <presentationId> --find foo --replace bar
gog slides list-slides <presentationId>
gog slides delete-slide <presentationId> <slideObjectId>
gog slides read-slide <presentationId> <slideObjectId>
gog slides insert-text <presentationId> <objectId> --text 'Hi'
gog slides move <presentationId> <elementObjectId> --x 100 --y 100
gog slides reorder <presentationId> <elementObjectId> --to front
Chat
gog chat spaces --json
gog chat messages spaces/AAAA --json
gog chat send spaces/AAAA --text 'Hello' --dry-run
Forms
gog forms get <formId> --json
gog forms responses <formId> --json
YouTube
gog youtube my-channel --json
gog youtube search 'swift concurrency' --max 10 --json
gog youtube playlists --json
Admin (Directory + Reports)
Admin SDK. Requires a host token with the matching admin scopes (Directory for
users/groups, admin.reports.audit.readonly for activities) belonging to a
Workspace admin; otherwise Google returns 403. Directory listings default to
the admin's own customer.
gog admin users --json
gog admin user alice@example.com --json
gog admin groups --json
gog admin group eng@example.com --json
gog admin members eng@example.com --json
gog admin activities login --json
gog admin suspend alice@example.com --dry-run
gog admin unsuspend alice@example.com
gog admin member-add eng@example.com bob@example.com --role MEMBER --dry-run
gog admin member-remove eng@example.com bob@example.com
These directory writes are high-blast-radius and gated: they refuse with
exit 3 unless the host has enabled admin writes. Always --dry-run first. The
host token also needs the write Directory scopes (the read-only scopes are
not enough): …/auth/admin.directory.user for suspend/unsuspend, and
…/auth/admin.directory.group.member (or …/admin.directory.group) for
member-add/remove — otherwise Google returns 403.
Discovery
gog --help
gog <service> --help
gog <service> <command> --help
gog version
Notes
- With
--json the output is structured JSON; otherwise it is a compact
human / TSV form (id, then key fields, tab-separated).
- List commands accept
--fail-empty (aliases --non-empty /
--require-results): exit 3 instead of 0 when there are no results, so a
script can branch without parsing the output.
- Surface: identity, Drive, Gmail, Calendar, Contacts, Tasks, Docs, Sheets,
Chat, Slides, Forms, YouTube, Admin (Directory + Reports). More services are planned —
see
PLAN.md.