| name | gog-wrapper |
| description | CLI wrappers for Google Workspace (Gmail, Calendar, Drive, Docs, Sheets, Photos) via gogcli. Use when the user asks you to read or write email, calendar events, Drive files, Docs, or Sheets. |
| metadata | {"openclaw":{"requires":{"bins":["gog","jq"]}}} |
gog-wrapper
These bash scripts wrap gogcli (invoked as gog) to give you CLI access to Google Workspace. Use them whenever the user asks you to read or write Gmail, Google Calendar, Drive, Docs, Sheets, or Photos on their behalf.
All scripts live in this directory. Run them with bash <script>.sh or ./script.sh if executable. They all source vars.sh for the default account.
Install
git clone git@github.com:stoleas/gog-wrapper.git
cd gog-wrapper
brew install steipete/tap/gogcli
vi vars.sh
chmod +x *.sh
gog auth credentials /path/to/client_secret.json
gog auth add you@gmail.com --services gmail,calendar,drive,contacts,docs,sheets
ollama pull llava
analyze-for-auction.sh extra dependencies
brew install jq
sudo apt install jq
python3 --version
Install as a Claude Code skill
mkdir -p ~/.claude/skills
ln -s "$(pwd)" ~/.claude/skills/gog-wrapper
Claude will pick up SKILL.md automatically from ~/.claude/skills/gog-wrapper/.
Install as an OpenClaw skill
npm install -g openclaw@latest
openclaw onboard --install-daemon
mkdir -p ~/.openclaw/skills
ln -s "$(pwd)" ~/.openclaw/skills/gog-wrapper
OpenClaw hot-reloads skills — no restart needed after the symlink. To verify it loaded:
openclaw doctor
To enable the skill and pass required env vars, add to ~/.openclaw/openclaw.json:
{
skills: {
entries: {
"gog-wrapper": {
enabled: true,
env: {
GOG_ACCOUNT: "you@gmail.com"
}
}
}
},
agents: {
defaults: {
skills: ["gog-wrapper"]
}
}
}
Account
The active Google account is set by GOG_ACCOUNT or DEFAULT_GOG_ACCOUNT in vars.sh. Override per-command with -a <email>.
Output modes
| Flag | When to use |
|---|
--json | Scripting — structured output, pipe to jq |
--plain | TSV — stable columns, pipe to awk/cut |
--results-only | With --json — strips wrapper, emits array directly |
--dry-run | Preview what would happen without executing |
--no-input | CI/non-interactive — fail instead of prompting |
gmail.sh
Wraps gog gmail. Use for reading and sending email.
./gmail.sh search 'is:unread newer_than:1d' --max 20 --json
./gmail.sh get <messageId> --json
./gmail.sh send --to someone@example.com --subject "Subject" --body "Body"
./gmail.sh send --to someone@example.com --subject "Subject" --body-file ./body.txt
./gmail.sh archive <messageId>
./gmail.sh mark-read <messageId>
./gmail.sh trash <messageId>
./gmail.sh archive $(./gmail.sh search 'older_than:30d' --json --results-only | jq -r '.[].id')
./gmail.sh drafts create --to a@b.com --subject "Draft" --body-file draft.txt
./gmail.sh drafts list --json
calendar.sh
Wraps gog calendar. Use for reading, creating, and managing calendar events.
./calendar.sh calendars --json
./calendar.sh events primary --from 2026-04-23T00:00:00Z --to 2026-04-30T00:00:00Z --json
./calendar.sh event <calendarId> <eventId> --json
./calendar.sh create primary --summary "Standup" --from 2026-04-24T09:00:00Z --to 2026-04-24T09:30:00Z
./calendar.sh update <calendarId> <eventId> --summary "New title"
./calendar.sh delete <calendarId> <eventId> --force
./calendar.sh search "standup" --max 10 --json
./calendar.sh freebusy --from 2026-04-24T00:00:00Z --to 2026-04-25T00:00:00Z --json
./calendar.sh respond <calendarId> <eventId> --status accepted
./calendar.sh users --json
./calendar.sh team engineering@example.com --json
./calendar.sh conflicts --json
drive.sh
Wraps gog drive. Use for browsing, uploading, downloading, and sharing files.
./drive.sh ls --json
./drive.sh ls --folder <folderId> --json
./drive.sh search "Q1 report" --max 10 --json
./drive.sh get <fileId> --json
./drive.sh url <fileId>
./drive.sh download <fileId> --out ./local.pdf
./drive.sh upload ./report.pdf --name "Q1 Report" --folder <folderId>
./drive.sh copy <fileId> "Copy of Doc"
./drive.sh move <fileId> --folder <targetFolderId>
./drive.sh rename <fileId> "New Name"
./drive.sh delete <fileId> --force
./drive.sh mkdir "Project Assets" --folder <parentFolderId>
./drive.sh share <fileId> --email colleague@example.com --role reader
./drive.sh permissions <fileId> --json
./drive.sh unshare <fileId> <permissionId>
docs.sh
Wraps gog docs. Use for reading and writing Google Docs.
./docs.sh cat <docId>
./docs.sh info <docId> --json
./docs.sh structure <docId>
./docs.sh create "Meeting Notes"
./docs.sh copy <docId> "Copy of Doc"
./docs.sh write <docId> --body "Full replacement content"
./docs.sh insert <docId> --body "Inserted text" --index 1
./docs.sh find-replace <docId> "old" "new"
./docs.sh sed <docId> 's/foo/bar/g'
./docs.sh clear <docId> --force
./docs.sh export <docId> --format txt --out ./doc.txt
./docs.sh export <docId> --format md --out ./doc.md
./docs.sh export <docId> --format pdf --out ./doc.pdf
sheets.sh
Wraps gog sheets. Use for reading and writing Google Sheets.
./sheets.sh get <spreadsheetId> "Sheet1!A1:D10" --json
./sheets.sh metadata <spreadsheetId> --json
./sheets.sh update <spreadsheetId> "Sheet1!A1:B2" --values-json '[["Name","Score"],["Alice","95"]]' --input USER_ENTERED
./sheets.sh append <spreadsheetId> "Sheet1!A:C" --values-json '[["2026-04-23","item","10"]]'
./sheets.sh clear <spreadsheetId> "Sheet1!A2:Z" --force
./sheets.sh find-replace <spreadsheetId> "old" "new"
./sheets.sh create "New Spreadsheet"
./sheets.sh add-tab <spreadsheetId> "Tab2"
./sheets.sh rename-tab <spreadsheetId> "Tab2" "Summary"
./sheets.sh delete-tab <spreadsheetId> "OldTab" --force
./sheets.sh export <spreadsheetId> --format xlsx
./sheets.sh export <spreadsheetId> --format csv
photos.sh
Calls the Google Photos Library REST API using gog OAuth tokens. Unlike other wrappers, this uses curl directly (gog has no native photos command).
One-time setup — re-authorize with photos scopes:
gog auth add edward.quail.claw@gmail.com \
--extra-scopes "https://www.googleapis.com/auth/photoslibrary.readonly,https://www.googleapis.com/auth/photoslibrary" \
--force-consent
./photos.sh list --max 10 --json
./photos.sh search "sunset" --max 20 --json
./photos.sh get <mediaItemId> --json
./photos.sh download <mediaItemId> --out ./photo.jpg
./photos.sh albums --json
./photos.sh album <albumId> --max 50 --json
./photos.sh create-album "Trip 2026"
./photos.sh upload ./photo.jpg
./photos.sh upload ./photo.jpg --album <albumId>
photos-to-drive.sh
Bulk-uploads a local folder of photos/videos to a Google Drive folder. Designed for saving a downloaded Google Photos shared album to Drive.
Workflow:
- In Google Photos, open the shared album → select all → three-dot menu → Download (saves a zip)
- Unzip:
unzip ~/Downloads/Photos*.zip -d ~/Downloads/album
- Upload to Drive:
./photos-to-drive.sh ~/Downloads/album --album-name "Beach Trip 2026"
./photos-to-drive.sh ~/Downloads/album --folder <driveId>
./photos-to-drive.sh ~/Downloads/album --album-name "Trip" --dry-run
analyze-for-auction.sh
Analyzes photos in a Google Drive folder using a local Ollama vision model, groups identical items into lots, researches market prices (eBay, Etsy, comparable auctions), and writes everything to a Google Sheet.
Requirements:
- Ollama running with a vision model pulled (e.g.
llava)
- Photos already uploaded to Drive (use
photos-to-drive.sh first)
One-time model pull (on the Ollama server):
ollama pull llava
ollama pull llama3.2-vision
./analyze-for-auction.sh kellystore4242026
./analyze-for-auction.sh kellystore4242026 --sheet-name "Kelly Store April 2026"
./analyze-for-auction.sh kellystore4242026 \
--ollama-host http://openclaw:11434 \
--model llava \
--sheet-name "Kelly Store April 2026"
./analyze-for-auction.sh kellystore4242026 --dry-run
./analyze-for-auction.sh kellystore4242026 --resume ./analysis_kellystore4242026.json
Output spreadsheet columns: Lot #, Category, Item Name, Brand, Qty, Condition, Description, eBay Low/High, Etsy Low/High, Other Markets, Rec. Low/High, Pricing Notes, Keywords, Photos
Checkpoints: Raw photo analysis is saved to ./analysis_<folder>.json after step 1. If the script is interrupted during grouping/pricing, rerun with --resume to skip straight to the sheet creation.
Patterns
Pipe JSON to jq
./gmail.sh search 'is:unread' --json --results-only | jq -r '.[].id'
Collect IDs then batch-act
ids=$(./gmail.sh search 'label:newsletters older_than:7d' --json --results-only | jq -r '.[].id')
./gmail.sh archive $ids
Dry-run before a destructive action
./drive.sh delete <fileId> --dry-run
./drive.sh delete <fileId> --force
Non-interactive / CI
./calendar.sh create primary --summary "Deploy" --from ... --to ... --no-input --json