# Spreadish — full agent brief
> Comprehensive guidance for coding agents integrating or contributing to Spreadish.
> Companion to https://spreadish.aitistack.com/llms.txt
Spreadish is an open-source sparse spreadsheet engine for React applications. It is not an Excel clone. V1 focuses on a programmable workbook with strong TypeScript APIs, deterministic commands, formulas (no eval), virtualization, drag-and-drop presentation, persistence via Sometic, and deep testing.
Site: https://spreadish.aitistack.com
Repository: https://github.com/aitistack/spreadish
Package manager for this monorepo: Bun only
---
## What to read first
1. https://spreadish.aitistack.com/docs/getting-started
2. https://spreadish.aitistack.com/docs/architecture
3. https://spreadish.aitistack.com/docs/api/core
4. https://spreadish.aitistack.com/docs/api/react
5. https://spreadish.aitistack.com/docs/api/sometic
6. https://spreadish.aitistack.com/playground (live behavior reference)
For repository contributors, the in-repo agent contract is `AGENTS.md` plus the numbered docs under `docs/` and phase specs under `phases/`. Public READMEs must link only to https://spreadish.aitistack.com, never to `AGENTS.md` or `docs/NN-*.md`.
---
## Package map and dependency direction
```text
@spreadish/utils
↓
@spreadish/core ← @spreadish/formula-engine
↓
@spreadish/react
↓
@spreadish/sometic (official app persistence only)
@spreadish/testing → all packages (tests only)
```
Never invert or cycle dependencies.
### Hard boundaries
| Package | Owns | Must not |
| --- | --- | --- |
| `@spreadish/core` | Workbook, sparse cells, rows/columns, selection, commands, history, formulas wiring, serialize, import/export | Import React, Sometic, Tailwind, daisyUI, or browser UI libs |
| `@spreadish/react` | Virtualized grid, keyboard, a11y, visual interaction | Own canonical workbook state |
| `@spreadish/sometic` | Sessions, IndexedDB StorageAdapter, workspace catalog, persistable event filter | Invent non-Sometic state/query libraries |
| `@spreadish/formula-engine` | Lexer, parser, AST, evaluator | Use `eval` / `new Function` |
| `@spreadish/utils` | Pure shared helpers | Depend on React or Sometic |
Do not add Zustand, TanStack Query, Redux, or another app state/query library for the official integration path.
---
## Data model rules (critical)
1. **Sparse storage.** Only existing cells, rows, and columns are stored. Empty cells remain addressable without a dense matrix source of truth.
2. **Index is not identity.** Rows and columns have stable IDs plus separate order arrays. Reorder changes display indexes; IDs stay stable.
3. **Commands are the only mutation path.** Hosts call `workbook.execute(command)`. UI callbacks must dispatch validated commands, not mutate core state directly.
4. **Selection drafts may live in React.** Document truth stays in core.
5. **Serialization is versioned.** Prefer `serialize()` / `loadWorkbook(...)` and the JSON helpers for interchange.
---
## Minimal React host pattern
`SpreadsheetGrid` is controlled. Pass core state in; dispatch commands from callbacks. Give the grid a bounded-height parent.
```tsx
import { useEffect, useMemo, useState } from 'react'
import { createWorkbook } from '@spreadish/core'
import { SpreadsheetGrid } from '@spreadish/react'
import '@spreadish/react/styles.css'
export function SpreadsheetHost() {
const workbook = useMemo(
() => createWorkbook({ name: 'Demo', sheetName: 'Sheet 1' }),
[],
)
const [, bump] = useState(0)
useEffect(() => workbook.subscribe(() => bump((n) => n + 1)), [workbook])
const sheetId = workbook.getState().activeSheetId
const editor = workbook.getEditor()
const draft = editor.status === 'editing' ? editor.draft : ''
if (!sheetId) return null
return (
{
workbook.execute({ type: 'selectCell', sheetId, row, column })
}}
onDraftChange={(value) =>
workbook.execute({ type: 'updateDraft', draft: value })
}
onBeginEdit={(intent) =>
workbook.execute({ type: 'startEditing', intent })
}
onCommit={(move) =>
workbook.execute({ type: 'commitEditing', move })
}
onCancelEdit={() => workbook.execute({ type: 'cancelEditing' })}
/>
)
}
```
Install (any manager):
```text
bun add @spreadish/core @spreadish/react @spreadish/sometic
pnpm add @spreadish/core @spreadish/react @spreadish/sometic
npm install @spreadish/core @spreadish/react @spreadish/sometic
yarn add @spreadish/core @spreadish/react @spreadish/sometic
```
---
## Commands and formulas
Typical cell write:
```ts
workbook.execute({
type: 'setCellValue',
sheetId,
row: 0,
column: 0,
value: '=SUM(1,2,3)',
})
```
After commit, the display value is computed; formula text remains available for a formula bar. Errors surface as typed cell errors (for example `#CIRC!`, `#NAME?`), not thrown UI crashes.
Never evaluate formulas with `eval` or `new Function`. Use `@spreadish/formula-engine` through core recalculation.
---
## Persistence: session vs workspace
### Single document session
Use `createWorkbookSession` when the host has one active workbook key.
- Storage: `createIndexedDBStorageAdapter({ dbName })`
- Commit only persistable domain events via `isPersistableDomainEvent`
- Selection, draft typing, and clipboard churn should not spam storage
### Multi-workbook workspace
Use `createWorkbookWorkspace` when users need a catalog of documents.
```ts
import {
createIndexedDBStorageAdapter,
createWorkbookWorkspace,
} from '@spreadish/sometic'
import { createWorkbook, loadWorkbook } from '@spreadish/core'
const workspace = createWorkbookWorkspace({
storage: createIndexedDBStorageAdapter({ dbName: 'my-app' }),
prefix: 'app.workbook',
defaultName: 'Untitled Workbook',
})
await workspace.hydrated
const session = workspace.getActiveSession()
const snap = session.getSnapshot()
const workbook = snap.serialized
? loadWorkbook(snap.serialized)
: createWorkbook({ name: 'Untitled Workbook', sheetName: 'Sheet 1' })
await workspace.create('Budget FY26')
await workspace.switchTo(/* id */)
```
The docs playground header dropdown is this workspace API under product chrome. Playground IndexedDB database name is `spreadish-playground` with prefix `playground.workbook`.
Verified Sometic packages used by the official adapter:
- `@sometic/store`
- `@sometic/store/persistent`
- `@sometic/query`
- `@sometic/core`
- `@sometic/react` (when React bindings are needed)
IndexedDB must be implemented as a real `StorageAdapter`. Prefer reading installed `.d.ts` files before inventing APIs.
---
## Import and export
From `@spreadish/core`:
- `exportWorkbookJson` / `importWorkbookJson` / `loadWorkbook`
- `exportSheetCsv` / `exportSheetTsv` / `planDelimitedSheetImport`
- Import limits and schema migration helpers are exported; respect max bytes/cells/rows/columns
---
## Playground product shell (V1)
Live demo: https://spreadish.aitistack.com/playground
Composition:
1. App header: brand mark, workbook title + switcher, Saved status, undo/redo, theme, import/export
2. Formula + format strip on one row
3. Full-width virtualized grid (only this region scrolls)
4. Status bar: sheet tabs, zoom, fullscreen
Not in V1 layout: left Sheets sidebar, right Properties sidebar, Share/Comments/search chrome as live features.
Brand mark on the docs-embedded playground links home (`/`). Standalone playground may leave that unset.
Favicon and header brand mark use product `icon.png`. Home hero uses the full Spreadish wordmark (`spreadish.png`) unchanged, with aspect ratio clamped.
---
## Docs site conventions (apps/docs)
- Visual tokens: emerald `#10B981`, page wash `#EEF1F4`, Urbanist body / Chakra Petch display / JetBrains Mono code (self-hosted fonts)
- Do not use internal design-system codenames in public copy
- Icons: `lucide-react` for chrome, CTAs, copy buttons, and navigation affordances
- Header is transparent at rest; solid frosted background after scroll; Ctrl/Cmd+K command palette
- Site footer on home, `/docs/*`, and `/legal/*`; omitted on `/playground`
- Legal hub: `/legal`, privacy, terms, security, license
- Why Spreadish: `/docs/why-spreadish`
- Code blocks and install tabs share one dark shell with slate gray dividers (`#334155`)
- Primary emerald CTAs use page-bg text color (`#EEF1F4`)
- Preview images are live playground captures under `apps/docs/src/assets/previews/`
Public LLM discovery files:
- https://spreadish.aitistack.com/llms.txt
- https://spreadish.aitistack.com/llms-full.txt (this file)
---
## Local monorepo gates
From repository root:
```bash
bun install
bun run format:check
bun run lint
bun run typecheck
bun run test:unit
bun run check:circular
bun run build
bun run package:check
bun run test:e2e
bun run docs:build
bun run docs:dev # or bun run dev → open /playground
```
Do not claim a gate passed without running it. Do not skip phases while exit criteria fail. Do not publish manually; releases use Changesets + OIDC Trusted Publishing.
Edge-case-first tests are mandatory for engine features: unit, typecheck, lint, E2E when user-visible, undo/redo when mutating, persistence when persisting.
---
## Security and reliability notes for hosts
- Treat imported workbook JSON/CSV/TSV as untrusted input; respect import size limits
- Formula evaluation must remain sandboxed (engine path only)
- Persistence keys and IndexedDB database names should be scoped per app
- Do not store secrets in workbook cells or local snapshot documents
---
## Contribution posture for agents
1. Prefer extending existing packages over inventing parallel APIs
2. Keep core free of UI and Sometic imports
3. Dispatch commands from UI; never mutate workbook maps from DnD/React callbacks
4. Update `apps/playground` and/or docs playground wiring when user-visible behavior changes
5. Match docs visual tokens; avoid purple-on-white, cream/serif/terracotta, or broadsheet newspaper aesthetics
6. Use 4-space TypeScript, EditorConfig, Prettier
7. When package public behavior changes, update docs pages and a changeset
---
## Quick link index
### Guides
- https://spreadish.aitistack.com/docs/getting-started
- https://spreadish.aitistack.com/docs/architecture
- https://spreadish.aitistack.com/docs/core-model
- https://spreadish.aitistack.com/docs/react
- https://spreadish.aitistack.com/docs/formulas
- https://spreadish.aitistack.com/docs/persistence
- https://spreadish.aitistack.com/docs/import-export
- https://spreadish.aitistack.com/docs/recipes
- https://spreadish.aitistack.com/docs/playground
- https://spreadish.aitistack.com/docs/roadmap
- https://spreadish.aitistack.com/docs/contributing
### API
- https://spreadish.aitistack.com/docs/api/core
- https://spreadish.aitistack.com/docs/api/react
- https://spreadish.aitistack.com/docs/api/sometic
- https://spreadish.aitistack.com/docs/api/formula-engine
- https://spreadish.aitistack.com/docs/api/utils
### Demo and discovery
- https://spreadish.aitistack.com/
- https://spreadish.aitistack.com/playground
- https://spreadish.aitistack.com/llms.txt
- https://spreadish.aitistack.com/llms-full.txt
- https://github.com/aitistack/spreadish
### V1 maturity and next phases
V1 engine surface (sparse core, React grid, formulas, Sometic sessions/workspaces, import/export, playground, docs) is feature-complete and verified green. Phase 10 Release is next (npm publish, Changesets, Trusted Publishing). Post-V1 glimpse: broader formulas, XLSX (permissive license), charts/pivots as separate packages, collaboration above commands, richer cells, host plugins. Details: https://spreadish.aitistack.com/docs/roadmap
Use **Copy Prompt** on the docs site header or home hero to paste a self-contained agent brief into a coding chatbot.