The ten-family design system
ยท Case study
Every app in the portfolio inherits a design family. There are ten. An app does not get to pick colours; it gets to pick a family, and the family decides.
What a family fixes
Each family is six decisions, made once:
| Decision | Example, from Instrument |
|---|---|
| Layout | Split pane, dark input left, light output right, one action top right, no nav bar |
| Palette | bg #0E1116, surface #161B22, ink #E6EDF3, muted #7D8590, accent #A855F7 |
| Type pair | IBM Plex Sans with IBM Plex Mono |
| Density | Tight |
| Surface strategy | Bordered |
| Radius | 2px |
The ten are Ledger, Paper, Instrument, Arcade, Void, Field, Bench, Drill, Console and Inspector. The definitions live in families.json in the skill library, mirrored from the app-inventory sheet.
Why ten and not one
One system across twenty-odd apps produces twenty-odd apps that look like a template. Twenty free hands produce twenty apps with nothing in common. Ten families is the middle: enough that a single-purpose tool can feel like itself, few enough that I can hold the whole set in my head and audit it with a script.
The families are also functional, not decorative. Instrument is a split pane because the apps that use it take an input and produce an output. Console puts the result above the inputs because the result is what you came for. Paper has chrome in the corners and no toolbar because the artifact is a document. Picking a family is picking a layout argument, and the colours come along with it.
Governance, which is the actual system
The families themselves are the easy part. The part that keeps the portfolio coherent is the process around them:
- The app-inventory sheet is canonical. Name, host, meta description, surface, status, family and build prompt all live in a row. Nothing gets renamed, rehosted or redescribed without the row changing first.
families.jsonandhouse-rules.mdare mirrors of that sheet, synced by a command, not edited by hand.- A new app is scaffolded from its row. The family tokens, the footer, the store key, the favicons and the metadata are all wired before any product code is written.
/house-auditchecks a repo against the rules deterministically./design-auditchecks that an app still matches the family its row claims.- A rule learned in one repo reaches the shared rules as a pull request, never as a direct push.
Two of those steps are worth naming precisely, because they are the ones people assume are more magical than they are:
V-3 recorded
Source control is GitHub, in the bryancalabro org. calabrodesign and its sibling repos live there, and pull requests and Actions run against it. Data held: repo contents, commit history, Actions logs.
Source: the calabrodesign git remote and .github/workflows/. Last verified 2026-09-21.
V-5 recorded
The AI provider is Anthropic, via Claude Code. It is used to build, audit and draft across every first-party repo. Data passed in: repo source and app-inventory sheet content.
Source: AGENTS.md and CLAUDE.md in calabrodesign. Last verified 2026-09-21.
The rules are dull on purpose: one footer line, one version scheme, one theme toggle shape, one storage key convention. Dull rules are the ones a script can check, and a rule a script can check is a rule that survives contact with a deadline.
What the system does not do
It does not stop an app from being ugly. A family fixes the palette and the layout; it says nothing about whether the thing you built inside it is worth using. The audits catch drift, not bad ideas.
It also did not, until recently, guarantee accessible text. Seven of the ten family palettes fail WCAG 2.2 AA on their own muted or accent colour, and the system had no way to notice. That is the subject of the next piece.
The evidence
The families, the house rules and the audit scripts are all in the calabrodesign repo under .claude/commands/skill-library/. The apps that use them are in the app-inventory sheet, with their family named in the row.