Foundations
The five patterns that every Quilt sheet is built from. Master these and the rest is composition.
01. Hello, cell
The smallest possible sheet: a value cell.
┌─────────┐
│ 📦 │
│ "hi" │
└─────────┘
value cell
Use when you just need a named value. A constant, a setting, a label. The atom of the spreadsheet model.
02. Reactive cascade
One value flows through a chain of formulas. Change the input, every dependent updates.
┌──────┐ ┌──────┐ ┌──────┐ │ 📦 │────────▶│ ƒ │────────▶│ ƒ │ │ raw │ │ norm │ │ final│ └──────┘ └──────┘ └──────┘ value formula formula wire: raw → norm → final change raw, both formulas recompute
Use when you have a value that needs transformation. The reactive engine handles the propagation order. You just write the math.
03. Sensor & actuator
Read the world, decide, act on the world. The cyber-physical loop.
┌──────────┐ ┌──────┐ ┌──────┐ │ 👁 │────────▶│ ƒ │────────▶│ 🔌 │ │ sensor │ │ logic│ │ motor│ │ .temp │ │ │ │ │ └──────────┘ └──────┘ └──────┘ sensor formula io read temp → decide → drive motor
Use when you're reading from the physical world (sensors, APIs, user input) and driving something back (LEDs, motors, HTTP). The fundamental input → process → output loop.
04. Listener & alert
React to changes by firing side effects. The "if X then Y" pattern.
┌──────┐ ┌──────┐ │ ƒ │────────▶│ 🔔 │ │ temp │ │alert │ └──────┘ └──────┘ formula listener when temp changes, fire if condition
Use when you need to act on a change, not just see a value. Notifications, logging, audit, external side effects.
05. API call
Call out to the world. An outbound HTTP call as a cell.
┌──────┐ ┌──────┐ ┌──────┐ │ 📦 │────────▶│ 🌐 │────────▶│ ƒ │ │ url │ │ api │ │ parse│ │ │ │ │ │ │ └──────┘ └──────┘ └──────┘ value api formula build url → fetch → parse response
Use when the data you need isn't in your sheet. APIs, webhooks, microservices. The cell model is uniform, so the engine doesn't care if the data is local or remote.
State
How to manage state in a reactive system. The patterns that turn a sheet into a finite-state machine.
06. State machine
A cell whose value is constrained to a finite set of named states.
┌────────┐ ┌───▶│ idle │◀────┐ │ └────────┘ │ │ │ │ │ start│ stop │ │ ▼ │ │ ┌────────┐ │ │ │ running│─────┘ │ └────────┘ │ current_state: formula (one of: idle, running) transitions: program (validate + apply)
Use when you have a system with discrete states (UI modes, workflow stages, protocol states). A cell as a finite-state machine is cleaner than nested if-else.
07. Counter
A cell that increments. The simplest possible stateful reactive system.
┌──────┐ ┌──────┐ ┌──────┐
│ 📦 │────────▶│ ▶ │────────▶│ 📦 │
│ 0 │ │ incr │ │ N │
└──────┘ └──────┘ └──────┘
on increment: count = count + 1
Use when you need to count events, clicks, requests, anything. The pattern is universal — it's the "how many?" question, encoded in cells.
08. Toggle / latch
A boolean that flips on each trigger. The "is it on?" question.
┌──────┐ ┌──────┐ ┌──────┐
│ 📦 │────────▶│ ƒ │────────▶│ 📦 │
│ false│ │ NOT │ │ true │
└──────┘ └──────┘ └──────┘
on trigger: state = !state
Use when you have a binary state (on/off, enabled/disabled, show/hide). A toggle is the latch — flip it, it stays.
09. Debounce
Wait until a stream of events stops, then fire. The "user is done typing" pattern.
┌──────┐ ┌──────┐ ┌──────┐
│ 📦 │────────▶│ ▶ │────────▶│ 📦 │
│ input│ │ 250ms│ │ final│
└──────┘ │ wait │ └──────┘
└──────┘
resets on each input
Use when you have a fast stream of events (typing, scrolling, sensor readings) but only want to act on the "settled" value. The classic search-as-you-type case.
10. Throttle
Fire at most once per time window. The "don't spam me" pattern.
┌──────┐ ┌──────┐ ┌──────┐
│ 📦 │────────▶│ ▶ │────────▶│ 📦 │
│input │ │ 1Hz │ │ last │
│ │ │ limit│ │ │
└──────┘ └──────┘ └──────┘
only emit at most every 1s
Use when you have a fast event source but want to limit the rate of actions. Network requests, UI updates, hardware writes. Don't over-drive your actuators.
Data
Patterns for transforming, filtering, and remembering data. The data engineering layer.
11. Transform pipeline
A series of cells that each apply one transformation. Unix pipes as cells.
raw ──▶ parse ──▶ clean ──▶ enrich ──▶ save 📦 ƒ ƒ ƒ 📦 each step is a cell output of one is input of the next
Use when you have data that needs many transformations. Each step is a cell — you can inspect, swap, and reuse them independently.
12. Filter & map
Apply a function to every element of a list. The "transform all the things" pattern.
list ──▶ map ──▶ filtered ──▶ sum 📦 ƒ ƒ ƒ map: x → f(x) filter: keep only where predicate(x)
Use when you have a list and want to derive a new list. Map, filter, reduce are universal primitives — they compose as cells.
13. Reducer
Fold a stream of values into a single accumulated value. The "running total" pattern.
┌──────┐ ┌──────┐
│ events│────┐ │ │
└──────┘ │ │ │
┌──────┐ ├───▶│ ƒ │──▶ total
│ events│────┤ │ fold │
└──────┘ │ │ │
┌──────┐ │ │ │
│ events│────┘ │ │
└──────┘ └──────┘
each event: total = (total, event) → total'
Use when you have a stream and want a single derived value. Running totals, averages, max, min — all reducers.
14. Cache
Remember a computed value so you don't recompute it. The "memoize" pattern.
┌──────┐ ┌──────┐ ┌──────┐ │ 📦 │────────▶│ 💾 │────────▶│ ƒ │ │ input│ │ cache│ │expensive └──────┘ └──────┘ └──────┘ on input change, recompute & store on no change, return cached
Use when computation is expensive, or you don't want to re-hit an API. The cache cell is the layer. You can swap it (LRU, TTL, distributed) without touching the rest.
15. Time series
A cell whose value is a list of timestamped values. The "I have data over time" pattern.
┌──────┐ ┌──────┐ ┌──────┐ │ 📦 │────add──│ 📦 │──window─▶│ ƒ │ │ new │ │series│ │ avg │ └──────┘ └──────┘ └──────┘ on new value: append to series on change: compute windowed stats
Use when you care about how something changes over time. Heart rate, temperature, latency, sales. The series is the model.
Composition
Patterns for combining cells into larger systems. The architectural layer.
16. Router
A cell that returns different values based on who is asking. The "context-aware" pattern.
caller A ──▶ router ──▶ result_A
caller B ──▶ router ──▶ result_B
(same cell, different output)
based on caller.role, return different value
Use when the same logical cell should return different things to different callers. Authorization, A/B tests, multi-tenant, feature flags. The cell is the policy.
17. Sub-sheet
A cell that is itself a sheet. The "composable unit" pattern.
┌─────────────────┐
│ parent sheet │
│ │
│ ┌────────────┐ │
│ │ sub-sheet │ │ (a cell, itself a sheet)
│ │ │ │
│ │ cells:{} │ │
│ │ │ │
│ └────────────┘ │
│ │
└─────────────────┘
sub-sheet has its own scope, but
exposes named outputs to parent
Use when you have a meaningful subsystem that should be reusable. A weather module, a payment flow, a search. Sub-sheets are like functions, but they're inspectable.
18. Retry / fallback
If the primary call fails, try the fallback. The "resilient" pattern.
┌──────┐
│ │ success ──▶ result
│ 🌐 │
│primary│ failure
│ │ │
└──────┘ ▼
┌──────┐
│ 🌐 │ success ──▶ result
│backup│
│ │ failure
└──────┘ │
▼
┌──────┐
│ 📦 │
│empty │
└──────┘
Use when reliability matters. The network is unreliable, APIs go down, services have outages. The fallback is the resilience.
19. Rate limit
Allow at most N calls per time window. The "be polite" pattern.
┌──────┐ ┌──────┐ ┌──────┐
│ 📦 │────────▶│ ▶ │────────▶│ 🌐 │
│request│ │limit │ │ api │
│ │ │ 10/m │ │ │
└──────┘ └──────┘ └──────┘
(drop if over)
Use when you're calling an external API with rate limits (Twitter, OpenAI, Stripe). Stay under the limit, get a 429 if you go over. The cell is the budget.
20. Audit log
Every change to a cell is recorded. The "who did what when" pattern.
┌──────┐ ┌──────┐ ┌──────┐
│ ƒ │────────▶│ 🔔 │────────▶│ 📦 │
│value │ │ log │ │ log │
│ │ │ on │ │ │
└──────┘ │change│ └──────┘
└──────┘
│
▼ append
┌──────┐
│ 📦 │
│ audit│
│ log │
└──────┘
Use when compliance matters, or you want to know what happened. Every change has a who, a what, and a when. The audit log is automatic.