About google-sheets
A skill for reading and managing Google Sheets through the Sheets API with curl and jq. It supports spreadsheet inspection, value operations, spreadsheet creation, and adding tabs, while noting OAuth scope requirements.
Key features
- 01Inspect spreadsheet titles and tabs
- 02Read ranges using A1 notation
- 03Append and update cell values
- 04Create spreadsheets and add tabs
- 05Account for OAuth scopes and input modes
Use cases
- 01Review spreadsheet structure and contents
- 02Append rows or update cell ranges
- 03Create a spreadsheet for a report
- 04Add a worksheet tab to an existing file
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ acedatacloud/ skills --skill google-sheetsAfter installing, type/google-sheetsin Claude Code to confirm it loaded.
Details
From the project READMEDrive Google Sheets via curl + jq. The user's OAuth bearer token is in
$GOOGLE_SHEETS_TOKEN; every call needs Authorization: Bearer $GOOGLE_SHEETS_TOKEN. Base URL: https://sheets.googleapis.com/v4/spreadsheets.
The token carries spreadsheets.readonly (+ identity); writes need the broader
spreadsheets scope.
Failures are {"error":{"code","message","status"}} — show verbatim. 401 =
re-install. 403 PERMISSION_DENIED on a write = read-only scope → re-connect
with read+write.
The spreadsheet id is the …/spreadsheets/d/<ID>/edit segment of the URL.
S="https://sheets.googleapis.com/v4/spreadsheets"; AUTH="Authorization: Bearer $GOOGLE_SHEETS_TOKEN"
# Tabs + title
curl -sS -H "$AUTH" "$S/SPREADSHEET_ID?fields=properties.title,sheets.properties(title,sheetId)" \
| jq '{title: .properties.title, tabs: [.sheets[].properties.title]}'
Read / append / update values
ID="SPREADSHEET_ID"
# Read a range (A1 notation; values are rows of cells)
curl -sS -H "$AUTH" "$S/$ID/values/Sheet1!A1:D20" | jq '.values'
# Append rows (confirm first). valueInputOption=USER_ENTERED parses formulas/dates.
curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d '{"values":[["2026-06-21","Acme",4200]]}' \
"$S/$ID/values/Sheet1!A1:append?valueInputOption=USER_ENTERED" | jq '.updates'
# Update a fixed range: PUT /values/{range}?valueInputOption=USER_ENTERED
curl -sS -X PUT -H "$AUTH" -H "Content-Type: application/json" \
-d '{"values":[["done"]]}' \
"$S/$ID/values/Sheet1!E2?valueInputOption=USER_ENTERED" | jq '.updatedCells'
Create a spreadsheet / add a tab
# New spreadsheet
curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d '{"properties":{"title":"Report 2026"}}' "$S" | jq '{spreadsheetId, spreadsheetUrl}'
# Add a tab via batchUpdate (addSheet request)
curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d '{"requests":[{"addSheet":{"properties":{"title":"Q3"}}}]}' \
"$S/$ID:batchUpdate" | jq '.replies'
Gotchas
- A1 notation:
Sheet1!A1:D20; quote tab names with spaces as'My Tab'!A1. valueInputOption=RAWstores strings as-is;USER_ENTEREDinterprets them like the UI (numbers, dates,=FORMULA). Pick deliberately.valuesis row-major ([[row1...],[row2...]]); a missing trailing cell just comes back short — don't assume rectangular.