Number 8Oct 2026
KAIROS is a design system for consoles where a person supervises autonomous aircraft and approves or rejects what an AI recommends, often against a clock. I built it object first: define what things are, then let every component follow from that. This is how the grammar came together and what it changed on screen. Pinned to October 2026.
Devon Kim Building an Object-Oriented Design System
A component library tells you what a button, a card and a badge look like. It doesn't tell you what the thing inside them is.
In an operations console that gap is the whole problem. The operator keeps asking the same questions about every number on screen. Did a sensor measure this, or did the AI guess it? Is this already happening, or is it only a suggestion? Can I act on it alone, or does someone else have to sign? A card component has no answer, so every screen answers differently, and the operator has to learn each one.
So I started somewhere else. Before any component, I wrote down the objects the operator deals with and the few properties every one of them has to declare.
The objects come first: an aircraft, an alert, a recommendation, a decision, a contact at sea, a search-and-rescue case. Each has an id and a state, and each can appear in more than one place.
A screen is a projection of those objects. The same aircraft is a marker on the map, a row in the list, a page in the inspector, an item in the event timeline, and a chip inside a sentence. Two rules hold across all of them:
This sounds obvious. It is here because the failure it prevents is easy to build by accident: the list says one thing, the map says another, and the operator reconciles them in their head.
Every component is a function of five values
render(object, projection, epistemic, attention, authority)
The epistemic axis has a known flaw. It answers two questions at once: where a fact came from (observed, derived, inferred) and how far an action has got (proposed, authorized, executed). One item can be inferred by the AI and authorized by an operator, or sent without being confirmed, and a single value can't say both. The next version splits it into source and stage.
The look follows from the values. Nobody picks "the red one" or "the one with the dashed border" by hand. If two components show the same epistemic stage, they show it the same way, because the stage is the input.
Interaction states like hover and focus still exist. They are the substrate, not the point.
The epistemic axis turned out to matter most. The AI in KAIROS can be wrong, and the operator has to be able to tell at a glance what the sensors saw from what the AI concluded.
The rules
One rule changed along the way. Early on, inferred blocks carried a diagonal hatch. It looked distinctive and it read as noise. Now the stage is said in words ("inferred", "not executed", "AUTHORIZED") and the colour only repeats it. A screen reader gets the same information, and so does anyone who can't tell violet from blue.
Attention is a budget. At most one thing on screen may interrupt, and at most three may ask for attention. When more happens at once, the console aggregates instead of adding another red banner.
What counts as critical took a while to get right. The first version promoted anything with a deadline, and a simulated hour of one scenario produced 27 critical interrupts. The rule now is narrower: critical means a deadline and a harmful default, so doing nothing would make things worse. The same hour produces three.
Authority is graded by consequence
Authorize only appears after the operator has previewed the outcome. If there isn't time to wait for concurrence, the operator can act alone, and the decision is flagged for review. Every step, from preview to outcome, writes one audit entry in the same operation as the state change, so there is no path that skips the log.
The tokens follow the same idea. They use the DTCG format and come in three layers:
A name says what a colour means, not what it looks like. There is no purple-dashed token, only an inferred one.
The build checks the rules instead of trusting them. Text contrast has to reach 4.5:1, warning and critical have to stay different colours (orange and red; a critical also gets the countdown and the banner position), and a raw rgb() shadow or a pixel radius in a stylesheet fails the build. The same source also generates a QML theme, so the grammar isn't tied to the web.
A grammar is easy to admire and hard to use, so I had it critiqued twice from a human factors point of view. The second review found 26 issues. Most were about honesty: the console promising more than it could know, or making one choice easier than another for reasons that had nothing to do with the situation.
The biggest redesign came after that, and it was about hierarchy, not new features. The same critical alert showed up in five places and its countdown three times. The inspector was 1,658 px tall, with the decision at the bottom.
What changed
The decision tab is now 626 px and fits a 1440×900 screen without scrolling.
What the checks can't tell me is whether a person decides better with this. A user test is next: twelve participants, six conditions, half of them with the AI wrong. It is exploratory. It can find where people misread the console, not prove it safe, and it counts needless rejections when the AI is right as well as errors missed when it is wrong.