Sheet

A spreadsheet in suggesting mode. People edit cells in place; an agent's edits show up on the cells they would change.

Hiring pipeline
CandidateRoleStageScoreNext step
1Maya ChenStaff engineerInterview86 
2Daniel OkaforProduct designerScreen72 
3Priya RamanStaff engineerOffer91 
4Lucas MoreauData scientistApplied  
5Sofia AlvarezProduct designerInterview78 
6Tom BeckerData scientistScreen64 

Installation

npx shadcn@latest add https://ui.usecube.io/r/sheet.json

Then import its styles from your Tailwind entry, as in Installation.

Usage

import { Sheet } from '@/components/sheet/Sheet'
import { sheetStore } from '@/components/sheet/store'

const store = sheetStore(initial, { name: 'pipeline', about: 'Our hiring pipeline, one candidate per row.' })

export function Pipeline() {
  return (
    <div className="h-[480px]">
      <Sheet store={store} />
    </div>
  )
}

The Sheet fills the box you give it and scrolls inside it.

Data

Every column and row has a key that never moves, so a model writes /rows/r3/cells/stage, never /rows/2/cells/4. Order is a field, sorted when the Sheet draws. An empty cell is a missing key.

const initial: SheetState = {
  columns: {
    name: { name: 'Candidate', type: 'text', order: 1 },
    stage: { name: 'Stage', type: 'enum', order: 2, enum: ['Applied', 'Screen', 'Interview', 'Offer'] },
    score: { name: 'Score', type: 'number', order: 3 },
  },
  rows: {
    r1: { order: 1, cells: { name: 'Maya Chen', stage: 'Interview', score: 86 } },
    r2: { order: 2, cells: { name: 'Daniel Okafor', stage: 'Screen' } },
  },
}

sheetStore explains this layout to the agent and checks every proposal against it: a number column takes numbers, an enum column takes one of its values. A proposal that breaks the sheet is refused with the reason, before anyone sees it.

Agent

const tools = store.tools({ by: 'Claude' }) // pipeline_read, pipeline_propose

What the model sends to fill a cell, add a row and remove one:

{
  "why": "Add Jonas, referred by Priya; Tom withdrew",
  "ops": [
    { "op": "add", "path": "/rows/r1/cells/next", "value": "Debrief with the panel" },
    { "op": "add", "path": "/rows/r7", "value": { "order": 7, "cells": { "name": "Jonas Weber", "stage": "Applied" } } },
    { "op": "remove", "path": "/rows/r6" }
  ]
}

A changed cell shows its current value struck through and the proposed one beside it. Rows the agent would add or remove are listed under the table. Agents shows how to connect a model.

Interactions

Do thisTo
Click a cellSelect it. Drag or Shift-click to select a range.
Double-click, Enter, F2 or start typingEdit the cell.
Right-clickRow and column menus: add, remove, sort, column settings.
Click a suggestionAccept or reject that proposal on its own.
Ctrl / ⌘ + EnterAccept all.
Ctrl / ⌘ + BackspaceReject all.

API Reference

Sheet

PropTypeDescription
storeSheetStoreThe data, from sheetStore, or a workspace store holding the sheet.
atstringWhere the sheet lives in the store, like /sheets/hiring. Leave it out when the store is the sheet. See Linking.
loadingbooleanThe data is still on its way: the Sheet shows its skeleton.
compactbooleanThe small form for a sheet embedded in a chat reply or a post: no Filter button, and the bar only while something is pending.
bulkbooleanShow Accept all and Reject all. On by default; a Doc turns it off for the sheets it draws, since its own bar takes them.

sheetStore

sheetStore(initial: SheetState, options?: { name?: string; about?: string }): SheetStore
OptionTypeDescription
namestringNames the tools: ${name}_read, ${name}_propose. Defaults to sheet.
aboutstringWhat this sheet is, for the agent. Added in front of the layout it is told.

A SheetStore is a usecube store: snapshot, propose, accept, reject, edit and tools all work on it. See Concepts.