Skip to content
Mohammad Sharifi
Back

Fanoos Design System

Founding team of the design system behind Rahkaran, an ERP with 100K+ users. Then I made it readable by AI, so every designer's prototype comes out on-system: real tokens, real components, checked before anyone sees it.

  • Design system
  • B2B
  • ERP

Fanoos is the design system that took Rahkaran, a 30+ module ERP used by 100K+ people, to the web. I joined at Gen 2, was on the founding team of Gen 3, where I set up its tokens in Tokens Studio, and now maintain Gen 4 with the infrastructure team.

Most recently I made it AI-native: an agent skill and an automated check, so any designer on the team can build an interactive prototype that stays on the system. Other teams' PMs mistook one of these prototypes for the live product.

Role
Founding team, Gen 3 and 4, design systems, AI prototyping
Team
Designers from 2 to 8, plus devs, PM, QA, PO

Making the design system AI-native

In 2025, I demoed a prototype to the CRM team. Mid-meeting, my team lead asked: "Did our action colors change? Why did they move?"

Nothing had changed. It was a throwaway prototype, built with AI to explore a problem. It looked real enough that he took it for the product, and off enough that the meeting turned to colors instead of the idea.

That's when I realized my problem wasn't speed. It was trust.

People know Fanoos by how it looks. If every prototype comes out in a different style, it stops feeling like our product. Stakeholders start asking whether the design changed, and stop talking about the idea. And getting a prototype on-system took round after round of prompts and fixes. There was never time for that.

At first it was my problem. Then I saw the rest of the design team prototyping with AI too, and every output looked different. Each designer was finding their own way to the system, paying for it in prompts, tokens and time, and ending up somewhere else. A better prompt would fix one person's prototype. The team needed something shared.

It was infrastructure work before I joined the infrastructure team.

Better prompts weren't the answer

Without the design system, the AI's output was generic. My first instinct was to write better prompts. Then I tried feeding it Figma screenshots. Both helped a little. But the agent still didn't know what each component is for, how our patterns fit together, or how we write UX copy.

After a few rounds I saw that the prompt wasn't the problem. My intent was: stakeholders should trust what they see. A prompt can't carry a whole design system. Context can. So I stopped engineering prompts and started engineering context, and the context is the design system itself.

Prompt engineering

Build a customer list page for our ERP.Use our primary blue for actions, not purple.8px radius on cards and inputs.Right-to-left layout, Persian labels.Filters above the table, row actions at the end.Match the attached screenshot.

figma-screen.png

Helped a little. Every round still meant fixing the look.

Context engineering

Build the customer list page from the Confluence doc and Jira item CRM-142. /grill-me before you write code.

fanoos-ds skill

Design tokensComponent mapPatternscheck.mjs

On-system, and checked before the agent says done.

Recreated example. The real prompts and output are under NDA.

Not every prototype needs it

The question decides the fidelity.

  • Structure, layout, information architecture: a black-and-white interactive wireframe. Nobody argues about colors, so we decide fast.
  • Details, states and interaction: the skill. This is where a prototype has to look like Fanoos, so it's where on-system has to be guaranteed.

Context in four layers

I started this on my own initiative. Each layer fixes a failure I saw in the AI's output.

  1. Design tokens. I pulled colors, theming, type, spacing and radius from our Figma library, built on the tokens I'd set up in Gen 3, with the Figma MCP, into one tokens file for light and dark. It fixed the made-up colors.
  2. Components and behavior. A script reads the real production runtime and writes a map of every component, 123 tags, with the attributes they actually accept. The Storybook MCP adds the behavior layer: what each component is for and how it acts.
  3. Patterns. The guidelines were already in Figma, documented by the team over years. I turned them, plus page templates for master, detail and detail of detail, into a reusable agent skill. It fixed page structures that didn't feel like Fanoos. The MVP covers the patterns that repeat across the whole system. Module-specific patterns stay out until a module needs them.
  4. A check the agent can't skip. Rules alone didn't stop drift, so I wrote check.mjs, covered below.
  • fanoos-ds/
  • SKILL.md3 · Patterns
  • DESIGN.md3 · Patterns
  • tokens.css1 · Tokens
  • docs/
  • FIGMA_TOKEN_SYNC.md1 · Tokens
  • COMPONENT_MAP.md2 · Components
  • FANOOS_RUNTIME.md2 · Components
  • ICONS.md2 · Components
  • guidelines/3 · Patterns
  • examples/3 · Patterns
  • vendor/2 · Components
  • scripts/
  • generate-refs.mjs2 · Components
  • check.mjs4 · Check
  • smoke.mjs4 · Check
The real repo, trimmed to the files that hold each layer.

A check the agent can't skip

Agents still invented CSS variables, or reached for core tokens that don't exist. check.mjs runs on every output and checks that:

  • every tag and attribute exists in the runtime
  • every icon name is real
  • every CSS variable resolves to a real token
  • no color or pixel value is hardcoded
  • the page stays RTL, in Persian

The agent runs it itself and fixes what it finds before it says done.

$ node scripts/check.mjs supplier-list.html

ERRORS supplier-list.html
     3: <html> must have dir="rtl"
     3: <html> must have lang="fa"
     8: var(--spacing-md) is not defined in tokens.css or vendor theme — the reference resolves to nothing
     9: raw color "#7c3aed" — use a var(--*) token
    10: var(--color-surface-glow) is not defined in tokens.css or vendor theme — the reference resolves to nothing
    10: border-radius: hardcoded "14px" — use a var(--space-*) token
    15: <f-button icon="add-supplier"> is not an icon ligature — see docs/ICONS.md
    16: unknown component <f-data-grid> — not registered by the runtime
    17: <f-badge> has no attribute "variant" (valid: label, icon, size, color-scheme, unwrapped, ellipsis)

9 problem(s) in 1 file(s).
Real output, run on a fictional page with planted mistakes.

Prompts are suggestions. Checks are guarantees.

Plain HTML, not the production codebase

Iteration 1: tried
  • Prototyped on the real production codebase, in React
  • Its dependencies were too much, even with a developer's help. A designer who doesn't code couldn't use it
Iteration 2: shipped
  • Plain HTML with the real runtime web components
  • No npm install, no build step

Designers and developers use the same system in different ways, so they need different ways in. Developers get the codebase. Designers get the same runtime components with nothing to install.

The prototypes come close to production, in visuals and behavior, because they run on the real components. They're throwaway on purpose: built to answer questions fast, not to ship. A developer sees whether it can be built, a PM whether it fits the business need, and the designer finds the states and edge cases a static frame hides.

Back to Figma

Handoff still happens in Figma, so developers and other teams don't change how they work. With Claude, I bring the prototype back into Figma as real components on our tokens and variables, and document the notes there.

It still needs a review pass, so I move it in stages: tokens and components first, then one page at a time. One mistake can't spread across every page, and it's quick to fix.

Early signs

This is a beta. I haven't run a rigorous test yet, but the early signs are good.

  • No off-system values. check.mjs blocks any color, tag or icon outside the system, so a prototype can't drift the way that CRM demo did. It doesn't check composition yet: a page can still combine valid components in ways Fanoos wouldn't.
  • It passes for production. Recently the front-end lead showed the Embedded BI prototype to PMs of several teams that build on our infrastructure. He told me they all thought it was already live.
  • It's faster. Two days of Figma down to an afternoon, by my estimate over three tasks.
  • Fewer handoff questions. Clicking through a prototype answers most behavior questions: from about 4 developer questions per task to 1 or 2 est..

Rolling it out to the team

Adopting it takes one install. A designer types a slash command in an empty folder, gives the agent the context, and builds.

I run knowledge-sharing sessions for 8 designers every two weeks. In one session, a designer built a working prototype on the spot. The rest of the team is still learning it, and so far I'm the only one using it day to day. I'm checking in with each designer to find where they get stuck, and fixing it in the kit.

It also helps with onboarding. Fanoos docs are scattered across Figma, and new designers struggle. The skill doubles as a knowledge base: a new designer can ask the agent about the guidelines and components.

Better prompts make one good prototype. Context makes every prototype trustworthy.

The skill in use: Embedded BI

Embedded BI is an AI analysis panel inside the ERP. I built its prototype with the skill, and it passed check.mjs. After I fixed two small notes, the PM wrote:

From my side, it's final. I have no notes. I love it. I even demoed it myself.
PM, Embedded BI

Try the demo and read the full story.

What's next

  • Check composition, not just values. check.mjs knows the system's vocabulary. The next step is its grammar: which components belong together, and how.
  • From prototype to production code. The tokens and components in a prototype are the ones production uses. I've validated the HTML handoff with the head of the front-end core team. The next phase: a developer hands the prototype to their own agent and asks for production code.
  • Module patterns. Add patterns specific to a module, for the teams that need them.