oficina / sheets Public
Product
<!-- impeccable:product-schema 1 -->
Platform
web
Users
Confirmed by Paul, 2026-09-01: Paul and his collaborators, dogfooding. Real use, small N. Design for the people actually in it rather than a hypothesised market — a feature nobody here uses is not evidence of anything.
They are running the CARLOS suite already, so Sheets is not entered cold: a person arrives from the suite home with a session, and the spreadsheet is one of several apps on one instance. The job is the ordinary one — put numbers in a shared grid, have the other person see them — under a storage rule that is stricter than the ordinary one.
Two roles exist beyond the team: a guest holds no team-wide rights and sees exactly the sheets granted to them; a link viewer is anonymous, read-only, and mints no membership at all. Both are real audiences for the read surfaces even though neither is the primary user.
Product Purpose
A spreadsheet for one team, on that team's own instance, whose contents are sealed at rest.
Success is that a team can do its actual spreadsheet work — grid editing, formulas, live collaboration, import and export — without the storage layer ever holding a plaintext cell, and without the product lying to them about what that does and does not protect.
Positioning
Three claims a neighbouring product could not truthfully copy, all confirmed binding by Paul on 2026-09-01:
- Sealed at rest, honestly scoped. The bucket never holds a plaintext cell. The instance holds the key while it runs, so a compromised live host can read an open sheet — and the README says so. We never claim "we can't read your data." The UI must never imply otherwise, in copy, in iconography, or by omission.
- One instance per team. Sharing is membership across teams: the sheet never moves, and an outside person becomes a scoped member of the team that owns it. There is no federation story across teams and there will not be one. Within a team, Sheets is one of several apps sharing one trust domain (suite ruling 1), and a same-team sibling may pull team-visible sheets under the suite contract.
- No affordance is script-required. Sign-in, the sheet list, sharing and membership, settings, version history, comments, import and export all work scriptless, as does a paginated table view of any sheet with per-cell edit forms. The grid editor is an enhancement on top of a floor, not the floor.
Operating Context
- One binary per instance,
CGO_ENABLED=0, cgo-free SQLite, deployed to CARLOS. Review happens on a deployed canary, never localhost. - The suite home is a separate product in a separate repo. Sheets depends on it for identity and consumes a five-call contract; it does not define it. Passkeys enroll at the home's origin only — instances never enroll them.
- Sheets sits beside Docs and the home under the Oficina suite, which shares a design system (
estilo). Chrome that appears in more than one app is the suite's, not Sheets'. - Live collaboration is cell-level last-write-wins over SSE. Version history replays inputs and recomputes; derived values are never logged.
Capabilities and Constraints
Built and working as of 2026-09-02: sign-in, sheet list and creation with a live preview thumbnail on every row, a grid backed by a Go calc engine, live sync across tabs over SSE, a scriptless paginated table view with per-cell editing, XLSX import and export (import by upload or by dragging a file onto the list; it runs as a background job and lands on the new sheet), and a contrast notice for imported fills.
The editing surface is a menu bar (File, Edit, Insert, Format, Data, Help), a formatting toolbar, a name box and formula bar, and a tab strip. Cells carry bold, italic, alignment, a number format, a fill and a text colour; columns and rows can be resized and stay resized. A colour picked here is stored as hue and chroma with no lightness, so it follows the reader's light/dark choice; a colour an imported file authored is painted exactly as the file wrote it.
Not reachable yet, though the code is there. This line previously read "XLSX/CSV import and export", which was true of the converter and false of the product. Import stopped being an example of that on 2026-09-02 and export stopped being one the same day — xlsx.Export now has a route and File ▸ Download as .xlsx reaches it. What remains true is CSV: there is no CSV code in the repo at all, and the line above does not claim any.
Constraints that bind design:
- No build step. Jspreadsheet CE v5 is vendored as a static asset — no CDN, no bundler. Its own formula engine is disabled; Go owns calc.
- 300-line cap on any JS module we write, test-enforced, ratchet-down only. The vendored grid blob is exempt and named as such.
- Light/dark is per person, not per document (confirmed binding, 2026-09-01), and must resolve before first paint from a cookie read server-side. Cell fills resolve against the theme, so a late preference repaints every coloured cell. Never a fetch.
- Every drag-only affordance has a menu equivalent.
- No cell content, sheet title or tab name in any log line, error string, job status or metric label. Errors carry coordinates and codes. This constrains error copy directly.
- Cell values are IEEE doubles end to end; currency is a number format, not a type.
- Cell fill is stored as OKLCH intent; an imported hex is retained as authored, even when it fails contrast (see Accessibility).
- Link sharing is viewer-or-commenter, never editor — an anonymous editor would write unattributed rows into version history.
Explicitly undecided: the suite's own domain (the passkey relying party is provisionally an oncarlos.com host). Sheets' own visual world beyond the suite theme — see Brand Commitments.
Brand Commitments
- Name: Sheets, within the Oficina suite (CARLOS).
- Design system:
rastrillo(the framework) withestiloas the suite's shared variant. estilo's theme is rastrillo'sday— not derived from it, identical — until a named need says a token has to differ. "It would look better" is explicitly not such a need; the bar is "Sheets' grid requires a denser row token that day does not declare". Any divergence is recorded as a decision, not applied. - Markup grammar: the attribute spelling (
rst-btn="primary compact"), never the class spelling. Utilities stay classes. Adopt per screen, never per element. - Voice: plain, exact, and never reassuring beyond the facts. The repo's own prose is the reference — it names its residual risks in the same breath as its guarantees.
- Authorship is disclosed. 🤖 / 👨 markers, published prompt and carbon ledgers. Every path works with AI switched off.
Evidence on Hand
docs/superpowers/specs/2026-08-30-sheets-design.md— the design spec. §1 is a dated, attributed settled-decisions table with the rejected alternative beside each ruling. §2 is the leak list. §14 is the deferred table, each row carrying a written trigger.AGENTS.md— binding engineering rules, several of them design-facing.- A working deployment at
https://sheets.bds.oncarlos.com. tools/drive/drive.mjs— drives the real binary in a real browser, for live sync across two tabs.tools/drive/chrome.mjs— its sibling, for the editing chrome: the menu bar, the toolbar, the formula bar, the cell paint, export, and the 320px reflow budget. It earned its place on the day it was written, by finding a menu bar that worked perfectly from the keyboard and not at all with a mouse.
Absences future work must not fabricate: there are no customers, no testimonials, no benchmarks, no pricing and no usage numbers. There is no market claim of any kind. Sheets is being dogfooded by its author and his collaborators, and nothing in the product may suggest more than that.
Product Principles
- Say the true thing, including the unflattering half. The trust model is a genuine differentiator and has a named residual risk. Copy that states the first without the second is a defect, not a simplification.
- The scriptless path is the product, not the fallback. If an affordance exists in the grid and not in the table view, the table view is unfinished. "Fallback" is the wrong word and invites the wrong design.
- One instance, one team, no federation. Never design a flow that implies data can move to another instance, or that a person outside this team is a first-class participant.
- The chrome is the suite's; the grid is ours. Anything that appears in Docs and the home too belongs to
estiloand should look identical there. A spreadsheet's menu bar and formula bar are Sheets'. - A preference resolves before first paint or it is a bug. This is a correctness rule that happens to be about design.
Accessibility & Inclusion
- WCAG AA (4.5:1) is the floor for text, and it is test-enforced against the theme's own pairs.
- A retained imported fill may fail that floor, and that is correct. Rendering an imported file as authored is the ruling; silently correcting a colour would lie about the document. The obligation that follows is to say so — a per-cell marker plus a notice — and leave the decision to the person. Never quietly recolour a cell.
- The page header's rule is decorative and carries no contrast floor. It is deliberately absent from rastrillo's contrast pair table; a later pass must not argue it up to 1.4.11's 3:1.
- The theme switcher must work with scripting off — a person who needs a high-contrast theme is not well served by being told to enable JavaScript first.
- Three light/dark states, not two: "follow the machine" is a real preference.