google-sheets
Google Sheets via gws: read/write cells, append rows, structured batch edits.
git clone --depth 1 https://github.com/Open-Curiosity/gini-agent /tmp/google-sheets && cp -r /tmp/google-sheets/skills/google/google-sheets ~/.claude/skills/google-sheetsSKILL.md
# Google Sheets
Use `gws sheets` to create spreadsheets, read cell ranges, append rows, update values, and run structured batch updates against the Sheets v4 API. This is the **content** surface for Google Sheets — for the file as an object (sharing, copying, moving, trashing) use `google-drive` instead.
## Prerequisites
- If this deployment is managed/hosted, the Google credential is already provisioned at sign-in — `gws` is installed and authenticated, so skip the setup flow below and run `gws` directly. Scopes are fixed at sign-in on a managed deployment: when a call fails with `scope required` or HTTP 401, tell the user which action needs a scope their account wasn't granted, instead of trying to set anything up. (The scope list below still describes which verb needs which scope.)
- `gws` installed and authenticated. If `gws` is not on PATH OR `gws auth status` reports no authenticated user, do NOT silently call setup. Instead, in a single short reply to the user:
1. State plainly what's missing — e.g. "Google Workspace access isn't set up on this machine yet" or "your Google sign-in has expired."
2. Ask one sentence: "Want me to walk you through setting it up?" Wait for the user's answer.
3. If they say yes, call `read_skill` with name `google-workspace-setup` and run that skill's onboarding flow turn-by-turn. If they say no or ask to defer, acknowledge briefly and stop — do not retry the original request.
- Apply the same flow when any `gws sheets ...` call fails mid-task with `command not found` / ENOENT, HTTP 401, "no credentials", or "scope required". Don't report the failure as a dead end — surface the missing prerequisite and ask if the user wants to set it up before moving on.
- OAuth scopes the user picked at login must cover the verbs the agent will use:
- Read and write Sheets: `sheets` (maps to `https://www.googleapis.com/auth/spreadsheets`)
- Read-only Sheets: pass `--scopes "https://www.googleapis.com/auth/spreadsheets.readonly"` at login
- Find sheets by title (or list recent sheets) before reading: pair with `drive.readonly`
- The Sheets API also accepts the broader `drive` scope, which covers finding sheets by title too — an account with a full `drive` grant needs no separate `sheets` scope
## Selecting a Google account
The connected Google accounts (each with its tag, email, and config dir) are listed in your system context under **"Connected Google accounts"**. To target a specific account, prefix the command with its config dir:
```bash
GOOGLE_WORKSPACE_CLI_CONFIG_DIR="<configDir>" gws sheets spreadsheets create --json '{"properties":{"title":"Tracker"}}'
```
Selection rule: one account connected → just use it. Two or more:
- The user named or clearly implied one account (a tag, an email, or unambiguous context) → use only that account.
- A read/lookup/search the user didn't tie to an account (e.g. listing events, searching mail, finding a doc) → run it against **every** connected account (one `gws` call per config dir) and aggregate, labeling each result by its tag and email. Don't pick just one, and don't ask — the user wants the whole picture across accounts.
- A write (send, create, edit, delete) with no account named → ASK which account first; never guess.
If no accounts are connected yet, fall back to the setup flow in Prerequisites (`read_skill` with `google-workspace-setup`). On a managed/hosted deployment an account is always connected, so this case doesn't arise.
## When to Use
- The user asks Gini to read cell values, ranges, or whole sheets out of a Google Spreadsheet.
- Appending rows to a tracking sheet (CRM log, expense tracker, AI run log, etc.).
- Updating specific cells or ranges with computed values.
- Creating a new spreadsheet from scratch as a starting point.
- Running structured edits (insert sheets, freeze rows, format ranges, conditional formats) via `spreadsheets.batchUpdate`.
## When NOT to Use
- Sharing, moving, renaming, copying, trashing, or permission-managing a spreadsheet — use `google-drive` for the file-as-object surface.
- Long-form prose or formatted documents — use `google-docs`.
- Slide decks — use Slides (`gws slides ...`), not Sheets.
- Lightweight key-value state the agent owns internally — use the `memory` tool, not a sheet.
- Numeric analysis Gini can do in-process (sum, average, sort, filter) — fetch the data once with `+read`, compute locally, write the result back if needed. Don't round-trip every calculation through the Sheets API.
## Quick Reference
The Sheets surface splits into two layers: helper commands for the common cases (`+read`, `+append`) and the raw API (`spreadsheets.get`, `spreadsheets.values.*`, `spreadsheets.batchUpdate`) for everything else.
### Create a blank spreadsheet
```bash
gws sheets spreadsheets create --json '{"properties":{"title":"Weekly tracker"}}'
```
The response includes a `spreadsheetId` you will need for subsequent reads and writes. The `spreadsheetUrl` field is the user-facing URL — surface that, not the bare ID, when telling the user where the new sheet is.
### Read a range (helper)
```bash
gws sheets +read --spreadsheet <SHEET_ID> --range 'Sheet1!A1:D10'
gws sheets +read --spreadsheet <SHEET_ID> --range Sheet1
```
`+read` is read-only. The response is the matched `values` array (rows of cells), already unwrapped from the raw API envelope. Pass `--format csv` if the user wants to pipe the result somewhere; `--format table` for human review in chat.
### Append a row (helper)
```bash
# Simple single row, comma-separated
gws sheets +append --spreadsheet <SHEET_ID> --values 'Alice,100,true'
# Bulk multi-row insert as JSON
gws sheets +append --spreadsheet <SHEET_ID> --json-values '[["a","b"],["c","d"]]'
```
`+append` finds the first empty row at the bottom of the existing data range and writes there. To write to a specific range (overwriting), use `spreadsheets.values.update` instead.
### Read a range (raw API)
```bash
gws sheets spreadsheets vaHow to dogfood and verify a Gini behavior change by driving a real chat turn as a real user would. Use when verifying that the agent reaches for a tool or path on its own — a behavioral steer, a new tool, an INSTRUCTIONS.md change, or a dispatch/provider/memory/skill change — or before claiming a steer "works". Enforces bare, uncoached prompts so the test measures the default, not instruction-following.
Delegate coding work to Claude Code CLI for repository edits, reviews, and multi-turn implementation sessions.
Delegate coding work to the OpenAI Codex CLI for repository changes, reviews, and focused fixes.
Gini's self-knowledge: how Gini configures, extends, and operates on its own state via /api/* and registered tools. Load when the user asks Gini about its own capabilities or asks Gini to modify its own configuration.
Manage Apple Notes via memo CLI: create, search, edit.
Apple Reminders via remindctl: add, list, complete.
Move bytes between Gini upload space, external URLs, and workspace files. Used by every attachment / file-upload / file-download flow regardless of the target system (Linear, GitHub, S3, Notion, etc.).
File a locally-captured, already-redacted Gini crash report as a GitHub issue, with the user's consent. Reads the pending crash queue and delegates the actual filing to the github-issues skill.