← Blog

Making design decisions survive the next session

John Jeong

Vibe coding a consistent product, Part 2. Previously: Abstraction is beautiful.

On October 9, I told Claude Code: "I'm looking at the overview page and storybook and it's something that's not used in our application."

We were building shared components for Char. We also had a place to look at them. Those two things still weren't enough to make the app consistent.

An agent could build a convincing example in Storybook while the app used another implementation. It could also fix the app by adding local styles, leaving the shared component unchanged. Either way, the next session had more than one version to choose from.

In the first post, I wrote about bringing Cards, Chips, and Prompts into shared components. This is about what happened around that code: giving people and agents a way to find the decisions, review them, and carry them into the next change.

The problem had already come up in our October 8 team meeting. Smaller components across the app had mostly been one-shotted. Search interfaces and popovers had diverged. Sometimes an agent would choose a plain dropdown even though we already had a menu for that interaction.

Artem wanted to be able to ask for a button, a dropdown, or a tab group and know which component the agent would use. I wanted the same thing. We needed the names in our conversations to lead to actual implementations.

That starts earlier than writing code. We renamed a confirmation "dialog" to a "Prompt" partly because dialog could suggest a modal. In Char, that approval belongs inside the Card, above the composer. A familiar word was pointing the agent toward the wrong shape.

I wanted those distinctions to be available without explaining them again in every chat.

Our root design.md became an index. It points to four areas: Foundations, Components, Product Concepts, and Experiences. That gives an agent somewhere to start, then a way to read only the guidance relevant to the change.

Foundations cover things such as typography and spacing. Components describe the shared building blocks and their responsibilities. Product Concepts explain what a Card or a Schedule means in Char. Experiences describe how those pieces work together in each app.

The last distinction matters. A shared Card can appear on both desktop and mobile, but interacting with a phone is different from interacting with a desktop window. App-specific guidance gives those differences a home without turning every surface into an independent design system.

Storybook supplies the concrete examples. I can open a Card, expand it, inspect its Prompt, and point to the space above its composer. The names in design.md should lead to the same parts I'm looking at.

Getting that right took some repetition. I asked for all the Chips in a grid so I could compare their previews. I kept asking to see Prompts inside real Cards with the composer present. An isolated Prompt could look fine while the complete Card had repeated borders and padding applied twice.

The composition was where I could see the problem. It was also where I could explain the correction precisely: use the Card's spacing here; keep this approval above the composer; remove the title that's already visible elsewhere.

By October 19, Storybook itself was difficult to navigate. Prompt examples contained Card structure, and it wasn't obvious where to look for either. We decided to rebuild the visible catalog around the same four areas as design.md, while preserving the existing stories and workflow tests. The new catalog would grow as we reviewed examples from the current codebase.

I said to Codex, "the code base is the truth right now." A polished story is useful only if we understand how it relates to the product. When the app and a story disagree, we have to inspect their implementations.

We then put the procedure into a design skill. Its reuse gate is simple:

  1. Find the existing component and its stories.
  2. Reuse it if it fits.
  3. Extend it if a state is missing.
  4. Create a new component only after checking that nothing covers the need.

The skill also tells the agent to inspect consumers before changing a shared component. A correction that looks right in one Card might affect another. Shared behavior belongs in the component that owns it; an interaction specific to mobile belongs in the mobile composition.

For example, if a Prompt has too much space around it, I want the agent to check which part owns that space. The Card might already provide the padding. Adding another wrapper in the Email Card could make that one example look right while leaving Cleanup and Chat different again.

The intended path is to inspect the shared parts, make the correction where it belongs, and review the affected examples. If the correction changes a component's responsibility or the user experience, the relevant design guidance and stories change with it.

That gives a correction somewhere to go. The code carries the implementation, the docs explain the rule, and the story lets us inspect it. The skill tells the next agent how to use them together.

We still have to check the app. On October 19, I was asking why the Cleanup Card didn't seem to use the shared Card. Writing the rule hadn't migrated every path. Looking at a story hadn't verified the installed build.

I don't have a measurement showing that this process has eliminated design drift. What I do have is a more specific way to work on it. When something looks wrong, we can ask which component it uses, which example represents it, and where the decision is written down.

I want to keep the speed of opening a chat and trying an idea. I also want the next chat to start with the design decisions we've already made. A good correction should leave something behind that the next session can use.