Gsheet model
Skill NovateStudioGit/novate-studio-skills/ecommerce/gsheet-model
Build or rebuild a formatted, multi-section financial model directly on a user's LIVE Google Sheet via the Composio v3 REST API (no Apps Script paste, no broken MCP Tool Router). Authors + formats tabs end to end — build the grid in Python, write via Composio REST, read-back verify, colour-band format. Use when the user says "build this into the sheet", "add a section to the planner", "rebuild this tab", "put returns into the model", or `/gsheet-model`. The author-and-format path proven on the ExampleBrand numbers sheet. NOT /ecom-data-analyst (that reads + analyses a catalog, doesn't author live tabs), NOT /gsheet-bridge (Apps Script paste — the fallback for when Composio is down), NOT /sheet-create (creates a NEW blank sheet). See memory composio-connection-broken for the full recipe + gotchas.From its SKILL.md
npx -y skills add NovateStudioGit/novate-studio-skills --skill gsheet-modelAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.4 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it
/gsheet-model — author & format a live Google Sheet model via Composio REST
Stand up or rebuild a calculator / financial model directly on the user's live multi-tab Google Sheet, fully automated, no copy-paste. This became possible once we learned to drive Composio through its REST API directly instead of the MCP "Tool Router" connect flow (which is broken vendor-side). Everything here is the hardened recipe from the ExampleBrand build — read memory composio-connection-broken for the source of truth; this skill is the operational playbook.
When to use vs siblings:
- This skill — author/format/rebuild tabs on a live sheet via Composio REST. Default when Composio is working.
/gsheet-bridge— the Apps-Script-paste fallback for when Composio is down. Same job, clunkier path./ecom-data-analyst— read + analyse a catalog (doesn't author formatted tabs)./sheet-create— make a brand-new blank sheet.
0. Auth (do this first, every run)
- API key: never hardcode it. Pull the live key at runtime:
claude mcp get composio→ theX-API-Key:header (or thecomposioentry in~/.claude.json). The helper does this for you. - Endpoint base:
https://backend.composio.dev/api/v3(v1 is retired). - Connected account (ExampleBrand Google):
ca_xxxxxxxxxxxx,user_idpg-test-xxxxxxxxxxxx. BOTHuser_idandconnected_account_idare required on every execute call (omitting user_id → error 1811). For a different account, re-list connections. - Every tool call:
POST /tools/execute/{TOOL_SLUG}with body{"user_id":..., "connected_account_id":..., "arguments":{...}}. - POST via curl, not python urllib — this Mac's python has no CA bundle (SSLCertVerificationError). Build the JSON in python, write to a tmp file,
curl --data @file. The helper (scripts/gsheet.py) already does this.
1. The operations (tool slugs)
| Need | Tool | Key args |
|---|---|---|
| Read values | GOOGLESHEETS_BATCH_GET | spreadsheet_id, ranges:[ "Tab!A1:Z40" ] |
| Read FORMULAS | GOOGLESHEETS_GET_SPREADSHEET_BY_DATA_FILTER | spreadsheetId, includeGridData:true, dataFilters:[{a1Range}] → each cell's userEnteredValue.formulaValue |
| Write a block | GOOGLESHEETS_BATCH_UPDATE | spreadsheet_id, sheet_name, first_cell_location (A1), valueInputOption:"USER_ENTERED", values (2D) |
| Format cells | GOOGLESHEETS_FORMAT_CELL | spreadsheet_id, worksheet_id (sheetId), 0-based start/end_row/col_index, + red/green/blue (0-1), bold, italic, fontSize |
| Add a tab | GOOGLESHEETS_ADD_SHEET | spreadsheetId, properties:{title} |
| Insert rows/cols | GOOGLESHEETS_INSERT_DIMENSION | insert_dimension:{range:{sheetId,dimension:"ROWS",startIndex,endIndex}, inheritFromBefore:false} |
| Clear values | GOOGLESHEETS_CLEAR_VALUES | spreadsheet_id, range |
| Tab list + sheetIds | GOOGLESHEETS_GET_SPREADSHEET_INFO | spreadsheet_id → sheets[].properties.{title,sheetId} |
GOOGLESHEETS_FORMAT_CELL does ONLY background colour + bold/italic/underline/fontSize. No borders, no number format ($/%/comma), no text colour, no column width. Those four are manual one-clicks the user does (tell them).
2. The build workflow
- Read first. Pull the target tab's structure (values, and FORMULAS via includeGridData if splicing into an existing model). Map columns/rows by their LABELS, never by remembered addresses.
- Build the grid in Python with row positions as VARIABLES (
R_TOTAL=23, DATA0=80...) and derive every formula reference off those vars. Hardcoded row numbers break the moment a section shifts. Keep ONE shared assumptions block and reference it cross-tab (tab-qualified, e.g.'COGS + BEROAS'!$T$3) so all tabs move in lockstep. - Avoid the merge trap. A rebuild on an existing tab inherits leftover merged cells (CLEAR_VALUES does NOT remove merges) — writes land only in a merge's top-left and the rest read blank. So for a fresh layout,
ADD_SHEETa clean tab. To add INTO a live model,INSERT_DIMENSIONblank rows (Google auto-adjusts same-sheet AND cross-sheet refs, so nothing downstream breaks) then populate. - Write the block with
BATCH_UPDATE. Batch many cells into ONEvaluesblock — don't loop single-cell writes (per-minute read quota throttles you at ~15; 429 → wait 30-60s, retry). - Verify by behaviour, not by eyeballing the script. Read back: totals correct, no
#DIV/0!/#ERROR!, and INJECT a sample data row to confirm computed columns actually flow. Don't "fix" working formulas off a readback hunch — test it. - Format with restrained, consistent colour bands (one palette, not rainbow): section-header band, highlight input cells (one accent), highlight the answer row, light tint for auto-calculated cells. Then tell the user the manual finish: auto-fit columns, add borders, apply
#,##0number format.
3. Gotcha checklist (every one cost real time on ExampleBrand)
AND()/OR()do NOT short-circuit →AND(C>0, D/C>=x)still divides on blank rows →#DIV/0!that poisonsSUM. Guard:=IF(C>0, IF(D/C>=x,1,0), 0).- A label written USER_ENTERED that STARTS with
=+-@is parsed as a formula →#ERROR!. Use a plain bold label for subtotals, not"= Revenue gap". - zsh: never name a shell var
UID(reserved → "bad math expression"); useEID. - CHECK BEFORE OVERWRITING a column: read the exact target range first; don't assume empty because you only read up to column L. (We overwrote Target CAC/ROAS this way — recover via Sheets File ▸ Version history; there's no API for it.)
- Never rename the tab a cross-tab formula points to.
- Returns/chargebacks etc.: keep assumptions in ONE block, reference cross-tab; tab-qualify or refs silently resolve local.
4. Helper
scripts/gsheet.py (stdlib only, shells to curl) wraps the operations: read_values, read_formulas, write_block, format_cell, add_sheet, insert_rows, clear, plus sheet_ids(). It auto-pulls the API key from claude mcp get composio. Import it or copy the calls. Default account/user are the ExampleBrand ones — pass account=/user= to override.
from gsheet import write_block, read_formulas, format_cell
write_block(SHEET_ID, "META PLANNER", "A1", grid) # grid = 2D list
read_formulas(SHEET_ID, "FINANCIAL MODELING!B22:C40") # {A1: formula}
format_cell(SHEET_ID, worksheet_id, 3,4, 1,6, bold=True, rgb=(0.85,0.73,0.40))
Always end a build by reading back and reporting the verified numbers, then naming the manual finish (borders / number format / column widths) since the API can't do them.
What ships with it: 1 file
6.9 KB alongside SKILL.md, 1 of them executable
scripts/
- gsheet.pyruns6.9 KB
Gives 0 of the 12 instructions most finance skills give in ~1.8k tokens
Counted across 469 of the 469 authors here whose files we hold, read 2026-08-07
- Extract date vendor amount and descriptionin 15 of 469, across 3 files
- Scan folder for invoice filesin 14 of 469, across 2 files
- Rename files to standard formatin 14 of 469, across 2 files
- Show organization plan before movingin 14 of 469, across 2 files
- Generate summary CSVin 14 of 469, across 2 files
- Organize files by categoryin 13 of 469, across 1 file
- Preserve original filesin 13 of 469, across 1 file
- Flag files missing critical infoin 13 of 469, across 1 file
- Produce the requested output filein 9 of 469, across 4 files
- Build best, base, and worst case scenariosin 9 of 469, across 5 files
- Implement backoff if rate limit errors occurin 8 of 469, across 3 files
- Determine the weighted average cost of capitalin 8 of 469, across 4 files
Said here and by no other author read
- pull the api key at runtime
- send post requests via curl not python
- pass both user id and connected account id
- read target tab structure first
- map columns and rows by labels
- build the grid in python with row position variables
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.