https://github.com/gmickel/sheets-cli
Composable Google Sheets CLI for humans and agents. Read, write, update cells by key—with Agent Skills for Claude Code and OpenAI Codex.
https://github.com/gmickel/sheets-cli
agent-skills automation bun claude-code cli google-sheets openai-codex spreadsheet typescript
Last synced: 27 days ago
JSON representation
Composable Google Sheets CLI for humans and agents. Read, write, update cells by key—with Agent Skills for Claude Code and OpenAI Codex.
- Host: GitHub
- URL: https://github.com/gmickel/sheets-cli
- Owner: gmickel
- Created: 2025-12-16T12:44:58.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2025-12-31T08:54:02.000Z (about 2 months ago)
- Last Synced: 2026-01-13T22:33:12.048Z (about 1 month ago)
- Topics: agent-skills, automation, bun, claude-code, cli, google-sheets, openai-codex, spreadsheet, typescript
- Language: TypeScript
- Size: 97.7 KB
- Stars: 12
- Watchers: 0
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- Agents: AGENTS.md
Awesome Lists containing this project
- awesome-agent-skills - Sheets CLI
- awesome-agent-skills - gmickel/sheets-cli - Google Sheets automation via CLI. (Phase 3: Build and Integrate / Reference Implementations)
README
sheets-cli
Composable Google Sheets primitives for humans and agents
Installation •
Quick Start •
Commands •
For Agents
---
> **📢 New Project:** Check out [**GNO**](https://gno.sh) — local hybrid search for your documents (Markdown, PDF, Word, Excel). Combines BM25 + vector search with MCP integration for AI agents. Great companion to sheets-cli: search your local docs, query your cloud sheets.
---
Fast, deterministic CLI for Google Sheets. Read tables, append rows, update cells by key or index, batch operations—all with JSON output for programmatic consumption.
```bash
# Read a sheet as structured data
sheets-cli read table --sheet "Projects" --limit 10
# Update by key column (no fragile row indices)
sheets-cli update key --sheet "Projects" --key-col "Name" --key "Acme" --set '{"Status":"Done"}'
```
> **🆕 Agent Skills** — Install as a skill for [Claude Code](https://claude.ai/code), [OpenAI Codex](https://openai.com/index/openai-codex/), or VS Code (Insiders preview; enable `chat.useAgentSkills`). The agent automatically discovers sheets-cli when you mention spreadsheets. See [For Agents](#for-agents).
## Installation
**Prerequisites:** [Bun](https://bun.sh) runtime
```bash
git clone https://github.com/gmickel/sheets-cli.git
cd sheets-cli
bun install
bun run build
# Binary at ./dist/sheets-cli
```
Add to PATH
```bash
# Symlink
ln -s "$(pwd)/dist/sheets-cli" /usr/local/bin/sheets-cli
# Or add to shell config
echo 'export PATH="$PATH:/path/to/sheets-cli/dist"' >> ~/.zshrc
```
## Quick Start
### 1. Enable APIs
1. Go to [Google Cloud Console → APIs](https://console.cloud.google.com/apis/library)
2. Enable **Google Sheets API**
3. Enable **Google Drive API** (required for `sheets find` command)
### 2. Create OAuth Credentials
1. Go to [Google Cloud Console → Credentials](https://console.cloud.google.com/apis/credentials)
2. Create **OAuth 2.0 Client ID** → Desktop app
3. Download the JSON file
> Desktop apps auto-allow localhost redirects. CLI captures OAuth code via `http://localhost:3847`.
### 3. Authenticate
```bash
sheets-cli auth login --credentials ./client_secret.json
```
Browser opens → authorize → done.
### 4. Set Default Spreadsheet (optional)
```bash
# Set env var to avoid passing --spreadsheet every time
export SHEETS_CLI_DEFAULT_SPREADSHEET_ID="your-spreadsheet-id"
```
Get the ID from your sheet URL: `docs.google.com/spreadsheets/d//edit`
### 5. Use
```bash
sheets-cli sheets list --spreadsheet
sheets-cli read table --spreadsheet --sheet "Sheet1" --limit 5
sheets-cli append --spreadsheet --sheet "Sheet1" --values '{"Name":"New Item","Status":"Active"}'
```
## Commands
### Auth
```bash
sheets-cli auth login --credentials [--token-store ]
sheets-cli auth status
sheets-cli auth logout
```
### Metadata
```bash
sheets-cli sheets list [--spreadsheet ]
sheets-cli sheets find --name "" [--limit 10] # Search by name
sheets-cli sheet info --sheet "" [--spreadsheet ]
sheets-cli sheet info --gid [--spreadsheet ]
sheets-cli header --sheet "" [--header-row 1]
```
### Read
```bash
sheets-cli read table --sheet "" [--limit 500] [--range "A1:Z500"] [--raw]
sheets-cli read range --range "!A1:Z50"
```
### Write
```bash
sheets-cli append --sheet "" --values '' [--value-input USER_ENTERED|RAW] [--dry-run]
sheets-cli update row --sheet "" --row 12 --set '' [--dry-run]
sheets-cli update key --sheet "" --key-col "Col" --key "Val" --set '' [--dry-run] [--allow-multi]
sheets-cli set range --range "!M2:M2" --values '' [--dry-run]
sheets-cli batch --ops '' [--dry-run]
```
All flags
| Flag | Description | Default |
|:-----|:------------|:--------|
| `--spreadsheet ` | Spreadsheet ID or full URL | env var or required |
| `--dry-run` | Preview without applying | `false` |
| `--value-input ` | `USER_ENTERED` or `RAW` | `USER_ENTERED` |
| `--header-row ` | Header row number | Auto-detect |
| `--limit ` | Max rows to return | unlimited |
| `--raw` | Return unformatted values | `false` |
| `--allow-multi` | Update multiple matching rows | `false` |
## JSON Formats
### Append/Update values
```json
{"Name": "Acme Corp", "Status": "Active", "Start Date": "2025-01-15"}
```
Headerless sheets (column letters):
```json
{"A": "Acme Corp", "C": "Active"}
```
### Set range (2D array)
```json
[["Value1", "Value2"], ["Value3", "Value4"]]
```
### Batch operations
```json
[
{"op": "append", "sheet": "Tasks", "values": {"Name": "New Task"}},
{"op": "updateRow", "sheet": "Tasks", "row": 5, "set": {"Status": "Done"}},
{"op": "updateKey", "sheet": "Tasks", "keyCol": "ID", "key": "TASK-123", "set": {"Status": "Active"}},
{"op": "setRange", "range": "Tasks!A1:B1", "values": [["Col1", "Col2"]]}
]
```
## Output Format
All commands return JSON to stdout:
```json
{
"ok": true,
"cmd": "read table",
"spreadsheetId": "1abc...",
"sheet": "Projects",
"result": {
"headers": ["Name", "Status", "Date"],
"rows": [{"Name": "Alpha", "Status": "Active", "Date": "2025-01-15"}],
"headerRow": 1
}
}
```
**Errors:**
```json
{
"ok": false,
"cmd": "update key",
"error": {"code": "VALIDATION_ERROR", "message": "...", "details": {}}
}
```
### Exit Codes
| Code | Meaning |
|:-----|:--------|
| `0` | Success |
| `10` | Validation error |
| `20` | Auth error |
| `30` | Permission error |
| `40` | API/transient error |
## For Agents
### Install Skill
```bash
# Claude Code
sheets-cli install-skill # Project: ./.claude/skills/sheets-cli/SKILL.md
sheets-cli install-skill --global # Personal: ~/.claude/skills/sheets-cli/SKILL.md
# OpenAI Codex
sheets-cli install-skill --codex # ~/.codex/skills/sheets-cli/SKILL.md
```
Installs an [Agent Skill](https://docs.anthropic.com/en/docs/agents-and-tools/agent-skills/overview) that teaches the agent how to use sheets-cli. After installing, the agent automatically discovers sheets-cli when you mention spreadsheets, Google Sheets, or sheet names.
> **Codex**: Requires `skills = true` in `~/.codex/config.toml` under `[features]`.
> **VS Code**: Agent Skills support is in preview and only available in VS Code Insiders. Enable `chat.useAgentSkills` to use Agent Skills.
**Restart the agent** after installing to load the skill.
### Workflow Pattern
Follow **read → decide → dry-run → apply**:
```bash
# 1. Understand current state
sheets-cli read table --sheet "Tasks" --limit 100
# 2. Dry-run
sheets-cli update key --sheet "Tasks" --key-col "ID" --key "TASK-42" --set '{"Status":"Complete"}' --dry-run
# 3. Apply
sheets-cli update key --sheet "Tasks" --key-col "ID" --key "TASK-42" --set '{"Status":"Complete"}'
```
### Best Practices
1. **Use `sheets find`** to get spreadsheet ID from name
2. **Prefer key-based updates** over row indices—rows shift on insert/delete
3. **Always dry-run** before writes
4. **Check `ok` field** before proceeding
5. **Batch related operations** for atomicity
6. **Column names match case-insensitively** with normalized whitespace
7. **Header row auto-detects**—skips empty rows to find first row with data
8. **Headerless sheets:** `read table` returns columns as `A`, `B`, ...; use column letters for `--set` / `--key-col`
9. **Empty sheets:** `append` can bootstrap by writing a header row from JSON keys
10. **`read table --range`** accepts `A1:Z` (auto-prefixed with the sheet)
11. **`--spreadsheet` accepts URLs**—paste full Google Sheets URL directly
## Development
```bash
bun run dev # Hot-reload
bun run build # Compile binary
bun run typecheck # Type check
bun run lint # Lint
bun run test # Tests
```
## License
MIT
---
Built with Bun • Styled for machines and humans alike