Composable Google Sheets CLI for humans and agents. Read, write, update cells by key—with Agent Skills for Claude Code and OpenAI Codex.
SaferSkills independently audited sheets-cli (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
CLI for Google Sheets primitives. Read tables, append rows, update cells by key or index, batch operations.
Installation: sheets-cli is already installed and available in the user's PATH. Run commands directly—no installation needed.# Find spreadsheet by name
sheets-cli sheets find --name "Projects"
# List sheets/tabs
sheets-cli sheets list --spreadsheet <id-or-url>
# Read table data
sheets-cli read table --spreadsheet <id> --sheet "Sheet1" --limit 100
# Update by key column (preferred - rows can shift)
sheets-cli update key --spreadsheet <id> --sheet "Projects" \
--key-col "Name" --key "Acme" --set '{"Status":"Done"}'
# Append row
sheets-cli append --spreadsheet <id> --sheet "Projects" \
--values '{"Name":"NewCo","Status":"Active"}'Always follow read → decide → dry-run → apply:
# 1. Understand current state
sheets-cli read table --sheet "Tasks" --limit 100
# 2. Dry-run first
sheets-cli update key --sheet "Tasks" --key-col "ID" --key "TASK-42" \
--set '{"Status":"Complete"}' --dry-run
# 3. Apply if dry-run looks correct
sheets-cli update key --sheet "Tasks" --key-col "ID" --key "TASK-42" \
--set '{"Status":"Complete"}'sheets-cli auth login --credentials <oauth-client.json>
sheets-cli auth status
sheets-cli auth logoutsheets-cli sheets find --name "<query>" [--limit 10]Searches Google Drive for spreadsheets matching the name. Returns ID, name, URL.
Requires Google Drive API enabled in the project.
sheets-cli sheets list --spreadsheet <id>sheets-cli sheet info --spreadsheet <id> --sheet "<name>"
sheets-cli sheet info --spreadsheet <id> --gid <gid>Get sheet metadata by name or GID.
sheets-cli header --spreadsheet <id> --sheet "<name>" [--header-row N]Returns column headers. Auto-detects header row if not specified.
sheets-cli read table --spreadsheet <id> --sheet "<name>" [--limit N] [--raw]Returns { headers: ["_row", ...], rows: [{_row: N, ...}, ...], headerRow: N }.
Each row includes _row - the absolute sheet row number for use with update row.
sheets-cli read range --spreadsheet <id> --range "Sheet1!A1:B10"sheets-cli append --spreadsheet <id> --sheet "<name>" \
--values '<json>' [--dry-run]JSON object with column names as keys. Column matching is case-insensitive with normalized whitespace.
sheets-cli update key --spreadsheet <id> --sheet "<name>" \
--key-col "<column>" --key "<value>" --set '<json>' \
[--allow-multi] [--dry-run]Finds rows where key-col equals key, updates columns from --set. Throws if multiple matches unless --allow-multi.
sheets-cli update row --spreadsheet <id> --sheet "<name>" \
--row <n> --set '<json>' [--dry-run]Updates specific row by 1-indexed row number. Use _row from read table output directly.
read table returns headerRow and rows with _row field_row is the absolute sheet row number - use directly with update row --rowheaderRow: 2 means headers on row 2, first data row is _row: 3_row from read outputsheets-cli set range --spreadsheet <id> --range "Sheet1!A1:B2" \
--values '<2d-json-array>' [--dry-run]sheets-cli batch --spreadsheet <id> --ops '<json-array>' [--dry-run]Operations: append, updateRow, updateKey, setRange.
| Option | Description |
|---|---|
--spreadsheet <id> | Spreadsheet ID or full URL |
--dry-run | Preview without applying |
--header-row <n> | Header row (auto-detects if omitted) |
--value-input <mode> | USER_ENTERED (default) or RAW |
All commands return JSON:
{
"ok": true,
"cmd": "update key",
"spreadsheetId": "...",
"sheet": "Projects",
"result": { "matchedRows": 1, "updatedCells": 2 }
}Errors:
{
"ok": false,
"cmd": "update key",
"error": { "code": "VALIDATION_ERROR", "message": "..." }
}read table returns columns as A, B, ...; use column letters for --set / --key-colID or URL matches both a header name and a column letter pattern, the header match wins. Column letter addressing (A, B, AA) is only used as fallback when no header matchesappend can bootstrap by writing a header row from JSON keysA1:Z (auto-prefixed with the sheet)| Code | Meaning |
|---|---|
| 0 | Success |
| 10 | Validation error |
| 20 | Auth error |
| 30 | Permission error |
| 40 | API/transient error |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.