SafeMom: a design system the AI builds with

SafeMom: a design system the AI builds with

SafeMom's founder built it fast with Claude Code and no designer. I came in to give it a brand, a token system and new screens, plus the rules and checks that keep the agent building on them.

Brand & product designer · July 2026, ongoing with the founder

The problem

It worked, but someone had cloned it. Looking generic meant looking like the copy.

When I opened the code, I counted eight purples. One came from the theme. The other seven were hardcoded, so a brand color change would have missed them.

It worked, but someone had cloned it. Looking generic meant looking like the copy.

When I opened the code, I counted eight purples. One came from the theme. The other seven were hardcoded, so a brand color change would have missed them.

Eight purple swatches from the old app code, each with its hex value and the file it came from. Only one came from the theme. The other seven were hardcoded.

The real user

The founder writes the prompts and merges the pull requests. Claude writes the code. So the first reader of anything I design is an agent, and when a spec has a gap, an agent guesses where a person would ask. Eight purples is what that looks like.

A PDF brand guide wasn't going to fix that, so I designed the system for the thing doing the building.

The system

I kept it to two layers. Every raw value lives in one primitives file, and screens can only read semantic tokens: surface, accent, the verdict colors.

I also wrote down what each token is not for. A designer would pick that up from context, but a model only knows what's written down. So accent is never a button, and nothing on the screen competes with a safety verdict.

The token preview screen in light and dark mode. The same token names cover text on surfaces, the marine accent, the primary button and two border tokens.

Keeping it on brand

Before Claude Code touches any UI, it reads a CLAUDE.md file I wrote: never type a raw value, here's every token, here's how to add one.

I hand off each screen as a packet: a spec, every state as a PNG, the data and one prompt. On the first build, the agent flagged 5 gaps instead of guessing.

I also added a design check that runs on every pull request.

The design check before and after. Before, one direct AppPalette color fails the check on main. After, a new scrim token replaces it and every count is zero.

Fixing the verdict

Most scans are skincare, and almost every skincare label lists fragrance. So almost every result came back caution, and after ten scans the word meant nothing.

I changed the rule: fragrance on its own isn't a caution anymore. It gets a plain note about what the label can't tell you. A real concern gets a one-line reason from an ingredient file we wrote, and if the file and the model disagree, the file wins.

Before and after of the result screen. Before, fragrance helps put a toner in the Use in Moderation state. After, the caution comes from niacinamide, and fragrance gets a short note: it can mean dozens of ingredients, is rarely a safety issue, and fragrance-free options exist.

Reflection

All five gaps the agent flagged were gaps in my spec. A person would have just asked. Now my specs name every token and file, and say what already exists and what doesn't yet. They're better for people too.

Interested?

I’m open to roles where design is a true partner in shaping product direction. If you’re building something with purpose, I’d love to chat.

Interested?

I’m open to roles where design is a true partner in shaping product direction. If you’re building something with purpose, I’d love to chat.

Interested?

I’m open to roles where design is a true partner in shaping product direction. If you’re building something with purpose, I’d love to chat.

© 2026 Kelli Novotny | Crafted with love

New York, United States

© 2026 Kelli Novotny | Crafted with love

New York, United States

© 2026 Kelli Novotny | Crafted with love

New York, United States