lianghsun/open-sheet/sheet-authoring
Claude Code and agent skill by lianghsun/open-sheet
- community
Checking that the SKILL.md file is still in the repository.
Technical reference for writing open-sheet workbooks — the file contract, the component surface, references and formulas, number formats, and the rules that keep a workbook a live model. Use this whenever writing or editing a file under `sheets/<id>/index.tsx`. The workflow for drafting a new workbook from scratch lives in the `create-sheet` skill.
Install
npx vskill@latest install lianghsun/open-sheet/sheet-authoringSKILL.md
Authoring an open-sheet workbook
The one rule
Never write a cell address.
Not B5. Not SUM(B2:B13). Not $A$1. The framework assigns every coordinate after it has laid the blocks out, and references resolve against that layout. Writing an address by hand means writing a number that is correct only until someone adds a row — and then it is silently wrong, which in a financial model is worse than broken.
If you catch yourself counting rows to work out where something landed, stop. The thing you want is a reference.
The single exception is raw('...'), the deliberate escape hatch — see references/formulas.md.
The file contract
The default export must be a <Workbook> containing <Sheet> children. meta and design are plain object literals — the dev UI parses and rewrites them, and a spread or an imported value makes the workbook untweakable.
Structure in JSX, data in TypeScript
JSX describes the report. Rows are plain arrays.
Do not write a thousand rows of JSX. If the data is generated, generate the array and hand it to data.
The component surface
| Component | What it is | |
|---|---|---|
<Workbook> | The root. Children must be <Sheet>. | |
<Sheet name freeze origin> | One tab. freeze="B2" freezes the rows above and columns left of that cell. | |
<Stack gap> | Stacks blocks downward. gap is in rows (default 1). | |
<Row gap> | Places blocks side by side. gap is in columns. | |
<Table> | A named data block. See below. | |
<KpiBand items> | A label row above a value row — a headline strip. | |
<Cell value formula format style span> | One cell. | |
<Note cols> | A line of prose spanning cols columns. | |
<Spacer rows cols> | Deliberate empty space. |
<Table> has two shapes:
- grid (default) —
name,data,columns, optionaltitle,showHeader,
total
- key-value —
kind="keyValue"withdata={[{ key, label, value, format }]}.
Every key becomes an Excel defined name, so formulas referencing it read =B5*growth in the exported file. This is how assumptions should be written.
name is workbook-global, because ref() looks blocks up by name. A duplicate throws at compile time.
total applies to grid tables only — a key-value block is a list of named scalars, not a column to aggregate. To total a key-value block, reference the entries you want and add them.
Separate assumptions from calculations
Put every number a reader might want to change on its own sheet, in a kind="keyValue" table, and reference it. That is what makes the export a model rather than a picture of one.
A number hard-coded inside a formula is a number the recipient cannot change.
Further reference
- references/placement.md — how blocks are sized and placed
- references/formulas.md — references, the builder API, the function whitelist
- references/formats.md — number formats, styles, data bars, themes
- references/charts.md — what is live and what is not
- references/printing.md — headers, footers, page breaks, print areas
- references/recipients.md — validation and the other affordances the person opening the file gets
What the framework cannot check for you
The framework guarantees referential integrity: addresses are right, formulas point where you meant, nothing breaks when a row is inserted. It cannot guarantee that the things being compared are comparable.
Every failure of this kind looks identical to a correct result. There is no error, no #NOT_EVALUATED, no trace in any cell — just a number that is arithmetically right and analytically wrong. Three shapes seen in real workbooks:
| Shape | Example | |
|---|---|---|
Ordering decided in data | a sorted array: right this month, silently stale next month | |
| Periods of different length | two days of data beside thirty → a growth rate of +790% | |
| Sources with different coverage | 30 days of cost ÷ 20 days of requests → wrong by 50% |
So whenever two numbers go into one expression — a division, a difference, a ranking — ask once: do they cover the same ground?
Normalise before you combine
When two figures come from different sources, divide each by its own coverage first. The spans cancel, and what is left is comparable:
Two extra columns, and both earn their place as diagnostics: a daily cost of 810, 1,225, 1,068 across three months shows which one is off. Collapsed into a single costPerRequest, it does not.
Make the coverage gap itself a column when the sources may disagree — a visible number with a threshold flag beats a footnote nobody reads.
Self-review before finishing
- [ ] No A1 address anywhere in the file
- [ ] Every number a reader might change lives in an assumptions block, not inside a formula
- [ ] Every
colthat computes usesformula, not a pre-computed value indata - [ ] Nothing that depends on the values is decided in the `data` array — no
sorting, filtering, grouping, or top-N. Those must be formulas. Easier to miss than a pre-computed value, because a sorted array leaves no trace in any cell: the workbook is right this month and quietly wrong next month, while still looking like a sorted table.
- [ ]
r.prev()/r.next()are guarded withr.isFirst/r.isLast - [ ] Formats are set on the columns that need them — a bare
0.0829reads as noise - [ ] Nothing was invented: every figure came from the user or a named source
- [ ] Everything compared covers the same ground — see "What the framework
cannot check for you". Provenance is not comparability, and this class of error leaves no trace in any cell. Prefer not generating a comparison over generating one with a caveat: a caveat gets skipped, a column that does not exist cannot be misread.
- [ ] The viewer shows no unexpected
#NOT_EVALUATED
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingpackages/core/skills/sheet-authoring/SKILL.md
Popularity
- Repository stars
- 127
- Repository forks
- 14
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/lianghsun/open-sheet/sheet-authoring)