| name | gws-sheets |
| description | Google Sheets operations via gws (Google Workspace CLI). Use when asked to read, write, append, or manage spreadsheets in Google Drive. Triggers on requests like "read the spreadsheet", "append rows to sheet", "create a new spreadsheet", "list Drive files", "share sheet with team".
|
| license | Apache-2.0 |
| metadata | {"author":"swen","version":"0.1"} |
| compatibility | Requires @campforge/gws-auth skill package (^0.1.0). |
Google Sheets Skill (gws CLI)
Authentication, installation, and token setup are handled by the gws-auth skill. Before proceeding, load/activate the @campforge/gws-auth skill dependency. If not already authenticated, the user must run gws-auth login themselves — the agent cannot perform this interactive browser OAuth step. The default scopes (spreadsheets, drive.file) are sufficient for core Sheets read/write operations and for accessing spreadsheets the app creates or opens. Drive-wide operations such as listing/searching files or managing sharing/permissions for arbitrary files (e.g., gws drive files list, gws drive permissions create) may require additional Drive scopes (drive.readonly or drive), which can be configured via gws-auth.
Environment variables
echo $GWS_SPREADSHEET_ID
If $GWS_SPREADSHEET_ID is not set and user doesn't specify one, ask for it.
How to call
Skill shortcuts (simple interface)
gws sheets +read --spreadsheet <SPREADSHEET_ID> --range "Sheet1!A1:D10"
gws sheets +read --spreadsheet <SPREADSHEET_ID> --range Sheet1
gws sheets +append --spreadsheet <SPREADSHEET_ID> --values 'Alice,95,2026-03-30'
gws sheets +append --spreadsheet <SPREADSHEET_ID> --json-values '[["Name","Score"],["Alice",95]]'
Direct API commands
gws sheets spreadsheets create --json '{"properties": {"title": "New Sheet"}}'
gws sheets spreadsheets values get \
--params '{"spreadsheetId": "<ID>", "range": "Sheet1!A1:C10"}'
gws sheets spreadsheets values update \
--params '{"spreadsheetId": "<ID>", "range": "Sheet1!A1", "valueInputOption": "USER_ENTERED"}' \
--json '{"values": [["Name", "Score"], ["Alice", 95]]}'
gws sheets spreadsheets values append \
--params '{"spreadsheetId": "<ID>", "range": "Sheet1!A1", "valueInputOption": "USER_ENTERED"}' \
--json '{"values": [["Bob", 88]]}'
gws sheets spreadsheets batchUpdate \
--params '{"spreadsheetId": "<ID>"}' \
--json '{"requests": [...]}'
gws sheets spreadsheets values clear \
--params '{"spreadsheetId": "<ID>", "range": "Sheet1!A1:D10"}'
Google Drive (spreadsheet file operations)
gws drive files list --params '{"q": "mimeType=\"application/vnd.google-apps.spreadsheet\"", "pageSize": 20}'
gws drive files list --params '{"q": "name contains \"Budget\" and mimeType=\"application/vnd.google-apps.spreadsheet\"", "pageSize": 10}'
gws drive permissions create \
--params '{"fileId": "<SPREADSHEET_ID>"}' \
--json '{"role": "writer", "type": "user", "emailAddress": "user@example.com"}'
gws drive files get --params '{"fileId": "<SPREADSHEET_ID>", "fields": "id,name,webViewLink,modifiedTime"}'
Discover commands
gws sheets --help
gws schema sheets.spreadsheets.values.get
gws sheets +read --spreadsheet <ID> --range Sheet1 --dry-run
Common Workflows
Read spreadsheet and summarize
gws sheets +read --spreadsheet <ID> --range Sheet1 -> get all data
- Summarize or analyze the data as requested
Append new rows from data
gws sheets +read --spreadsheet <ID> --range "Sheet1!1:1" -> get headers
- Format new data to match header columns
gws sheets +append --spreadsheet <ID> --json-values '[["col1","col2",...]]'
- Re-read to verify
Create new spreadsheet with initial data
gws sheets spreadsheets create --json '{"properties": {"title": "..."}}' -> capture both spreadsheetId and sheets[0].properties.title from the response. The first sheet's title is locale-dependent (e.g. 시트1 on Korean accounts, Sheet1 on English), so do not hardcode Sheet1!A1 in subsequent ranges -- use the title returned by create.
gws sheets +append --spreadsheet <NEW_ID> --json-values '[["Header1","Header2"],[...]]' (defaults to the first sheet), or pass the actual title in --params range for values update/append.
- Optionally share:
gws drive permissions create ...
Find and update specific spreadsheet
gws drive files list --params '{"q": "name contains \"keyword\""}' -> find spreadsheet
gws sheets +read --spreadsheet <ID> --range Sheet1 -> read current data
gws sheets spreadsheets values update ... -> update specific range
Windows Encoding Safety
When writing Korean or other non-ASCII text on Windows, prefer a bash-based
path for any command that sends JSON to gws.
If gws is not on PATH in a local workspace install, check ./.local/bin
first and export it before retrying:
export PATH="$(pwd)/.local/bin:$PATH"
gws --version
command -v gws-auth
- Use Git Bash for
gws sheets spreadsheets values update, append, and
batchUpdate.
- If generating a script or JSON file on Windows, save it as UTF-8 without
BOM before executing it from Bash.
- If terminal quoting or encoding is unstable, send text through JSON
\uXXXX escapes instead of raw Unicode.
- After any write containing non-ASCII text, immediately re-read a small
range such as
A1:C5 to verify the stored characters.
- Avoid
gws.cmd --json $json directly from PowerShell -- variable
interpolation reshapes quotes and produces Invalid --json body. The
same applies to deeply nested bash -lc '... --json ... ' one-liners,
where the inner JSON gets mangled by outer quoting.
Windows-safe end-to-end example
For JSON-heavy flows, write the whole workflow into a UTF-8 (no BOM) bash
script and run it from Git Bash. This is the prescriptive Windows path for
create -> write -> verify with non-ASCII content:
cat > sheets-flow.sh <<'EOF'
set -euo pipefail
export GOOGLE_WORKSPACE_CLI_TOKEN="$(gws-auth token)"
CREATE=$(gws sheets spreadsheets create \
--json '{"properties":{"title":"\uD68C\uC0AC \uBA85\uB2E8"}}')
SID=$(node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).spreadsheetId" <<<"$CREATE")
TITLE=$(node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).sheets[0].properties.title" <<<"$CREATE")
PARAMS=$(node -e 'console.log(JSON.stringify({spreadsheetId:process.argv[1],range:process.argv[2]+"!A1",valueInputOption:"USER_ENTERED"}))' "$SID" "$TITLE")
gws sheets spreadsheets values update --params "$PARAMS" \
--json '{"values":[["\uD68C\uC0AC","ACME"],["\uC0C1\uD0DC","\uC815\uC0C1"]]}'
gws sheets +read --spreadsheet "$SID" --range "$TITLE!A1:B2"
EOF
bash sheets-flow.sh
node -p is used instead of jq because Git Bash on Windows does not ship
jq by default, but Node is already present (gws is an npm package).
Notes
+read, +append are gws skill shortcuts (simpler syntax than direct API)
--dry-run flag previews the HTTP request without executing
--page-all flag auto-paginates large result sets (NDJSON output)
- Spreadsheet ID is the long string in the URL:
docs.google.com/spreadsheets/d/<SPREADSHEET_ID>/edit
valueInputOption: USER_ENTERED (parses formulas) vs RAW (literal strings)
- Windows:
--params / --json examples are bash syntax. On Windows, use Git Bash. PowerShell can corrupt JSON quoting passed to native executables, and raw Unicode writes need extra care as described above.