Agent Workflow Kit
Chapter 07
Technical engraving of type gauges, line samples, swatch cards, and timing instruments
Fig. 07The design spec as instruments.

07 — The design doc

When to read this: Before any UI work. If your project has zero user-facing surface (pure CLI, library, internal script), skip this chapter, though you may still read it for the philosophy.

DESIGN.md is a constraint system, not a style guide#

Most "design system" docs describe what the brand is. They list typefaces, show color swatches, document spacing scales.

DESIGN.md does that, but its primary job is different. It exists to prevent the agent from reaching for generic defaults. The same model that ships beautiful, distinctive UI when given specific constraints will, without constraints, ship Inter / purple-on-white / three-column feature grids: the average of its training data.

DESIGN.md is structured as a list of commitments and a list of forbids. Commitments say "Use this font, this color, this easing curve." Forbids say "Never these things, and here's why." Both are load-bearing. Without forbids, the agent fills silence with defaults. Without commitments, the agent has nothing positive to anchor on.

The forbidden defaults concept#

A "forbidden default" is a specific pattern the agent reaches for that doesn't fit the brand. The kit ships a starter list of universal forbids:

  • Type: Inter, Roboto, Open Sans, Lato, Arial, system stacks.
  • Color: Purple gradients on white. Generic SaaS blue/teal. Evenly distributed pastel palettes.
  • Layout: Three-column feature grids with identical card heights and centered icons. Hero with large heading + subtitle + two CTAs and nothing else.
  • Motion: Fade-in on scroll without intention. Decorative hover scales. Animations longer than 400ms for state change. Animating anything other than transform and opacity. Material default easing cubic-bezier(0.4, 0, 0.2, 1).
  • Backgrounds: Flat solid colors with no atmosphere. Generic noise textures pasted on top.
  • Components: Unmodified shadcn/ui defaults shipped without remixing.

These aren't aesthetic preferences. They're observed regression patterns: things the agent reaches for repeatedly across projects when no constraints are present. Forbidding them by name forces the agent to make a more specific choice.

On top of the universal list, your project gets project-specific rejections: patterns you notice the agent reaching for that don't fit. You add these via the /forbid slash command. More on that below.

What good DESIGN.md looks like#

A specific DESIGN.md commits to:

SectionSpecific to this project
Brand identityAesthetic direction (one named direction, e.g. "editorial brutalism"); 3 IS / 3 IS NOT adjectives; one-line tagline; the single thing a visitor remembers in a week
Type systemDisplay family + body family + mono family (real names); weight extremes; modular scale ratio; tracking rules
ColorBackground, foreground, surface, border, muted-foreground, one dominant accent, status colors — all in OKLCH
Space and shapeSpacing scale; border-radius philosophy; shadow philosophy; layout grid
MotionEasing curve (specific cubic-bezier); duration tiers; spring vs duration philosophy; stagger rhythm; what animates
Voice (if marketing surface)Sentence length; personality knobs; forbidden words
Forbidden defaultsUniversal list (kit-shipped) + project-specific list (grows over time)

The IS / IS NOT format for adjectives is intentional. "Confident" alone passes. You can imagine what confident UI looks like. "Confident" + "earnest" + "structured" tells you something different than "confident" + "playful" + "loose." And "NOT precious" + "NOT decorative" + "NOT corporate" rules out a lot of agent-default territory.

How design-md-builder works#

The design-md-builder skill does the interrogation:

design-md-builder

Same shape as prd-grill and architecture-md-builder: one question at a time, recommended answer with each, push past the first vague answer.

Phase 0: diagnose#

The skill checks for an existing DESIGN.md. Three states:

  • No file — full interrogation.
  • Vague file — interrogation only on vague sections.
  • Specific file — confirm what you want changed; don't rewrite working sections.

It also reads package.json, tailwind.config.*, and app/globals.css (or equivalent) to detect the stack. Tailwind v4 changes the token format (it uses @theme inline blocks with OKLCH custom properties), so the skill notes which version you're on.

Phase 1: reference gathering#

Before any abstract questions, the skill asks for concrete references. Visual references first, words second.

  • 3 sites whose visual design you'd steal. Real URLs.
  • 2 sites in your space whose design you actively dislike, and why. Often more diagnostic than the love list.
  • Optional: 2–3 screenshots you can paste directly.

If you have nothing to point to, the skill offers a short menu of named aesthetic directions (editorial brutalism, warm terminal/IDE, Japanese ma minimalism, Stripe-Press editorial, playful Memphis revival, industrial Bauhaus, etc.) for you to pick from.

Phases 2 through 6: brand, type, color, space, motion, voice#

For each section, the skill pushes past the first vague descriptor. Examples:

  • You say "modern and clean" → skill asks which kind: Apple/Linear restraint, brutalist swiss, editorial NYT, terminal/IDE, Japanese ma, mid-century printed, Bauhaus geometric.
  • You say "friendly approachable colors" → skill asks which brand's colors you'd kill to have. Stripe approachable is not Notion approachable is not Linear approachable.
  • You say "smooth animations" → skill asks which kind: Apple physical (springs, follow-through), Linear precise (200ms ease-out, near-invisible), Notion playful (soft overshoot), brutalist (instant, no motion), Disney (anticipation, squash).
  • You say "professional" → skill asks for the anti-version. Professional like a law firm is not professional like Stripe is not professional like Bloomberg.

For type, the skill pushes past Inter. The default font in 80% of AI-generated sites is Inter or Roboto. The skill forbids both unless you explicitly insist with reasoning. Acceptable directions: Bricolage Grotesque, Fraunces, Newsreader, Cabinet Grotesk, Clash Display, IBM Plex Sans, Söhne, GT America.

For color, the skill works in OKLCH. Tailwind v4 uses OKLCH natively. OKLCH is perceptually uniform and gamut-aware. Format every value as oklch(L C H) so it pastes directly into a @theme block.

Phase 7: voice (optional)#

If your project has marketing surface, the skill asks about voice: sentence length, personality knobs, forbidden words. The kit's default forbidden-words list catches AI-tells: "effortlessly," "seamlessly," "leverage," "empower," "revolutionize." You add to the list as needed.

Phase 8: forbidden defaults#

The skill restates the universal forbidden defaults from /craft-ui, then asks for project-specific additions. Examples:

  • "No purple anywhere. We are not another purple SaaS."
  • "No glassmorphism. No backdrop-blur on cards."
  • "No three-column feature grids with centered icons."
  • "No Material default easing. Use ours."

This list grows over time as you spot patterns. The growing happens via /forbid (next section).

Phase 9: write the file#

The skill shows you the full DESIGN.md inline in the chat before writing it to disk. You can copy-paste even if you don't want it written. After writing:

  1. The skill confirms the file is consumable by /craft-ui (the section headers match what /craft-ui Phase 0 looks for).
  2. The skill suggests two follow-ups: add project-specific forbids as patterns emerge; re-read DESIGN.md when you start a new project surface, since it gets stale.

Sharpening DESIGN.md over time with /forbid#

The /forbid slash command appends one project-specific forbidden default to DESIGN.md. Use it whenever you spot a pattern the agent keeps reaching for that doesn't fit.

/forbid backdrop-blur on cards — feels generic glassmorphism, not our editorial direction

The format is pattern — reason. Both halves are required.

Why the reason is required#

Forbids without reasons are brittle. Six months later, you read "no backdrop-blur on cards" and wonder why. Temporary stylistic choice, or permanent brand stance? A reason like "feels generic glassmorphism, not our editorial direction" makes the rule survive future re-reads. It's also what lets future-you (or a different team member) decide whether to revisit.

The /forbid command rejects vague forbids. Examples it rejects:

  • "No ugly things"
  • "Less generic stuff"
  • "Better animations"
  • "Make it nicer"

Examples it accepts:

  • "No backdrop-blur on cards. (Reason: feels like generic glassmorphism, not our editorial direction.)"
  • "No hover scales over 1.02. (Reason: decorative, not communicating state.)"
  • "No Lucide icons in marketing surfaces. (Reason: identifiable as default-stack; use our custom icon set.)"
  • "No animated gradient text. (Reason: 2023 SaaS cliche, undermines our seriousness.)"

The command parses the input, formats it into the DESIGN.md Project-specific rejections subsection, shows you the diff, asks for confirmation, then writes. After writing, it suggests:

git add DESIGN.md && git commit -m "design: forbid <short summary>"

so the rule is versioned and survives.

How fast does the project-specific list grow?#

In a healthy project, you'll add 2–5 forbids in the first month, then maybe one a month after that. They cluster around the design surfaces you're actively building: the first marketing page, the first dashboard, the first onboarding flow. If you're not adding any forbids, either (a) you're not paying attention to agent regression, or (b) you happen to be building something where the agent's defaults align with your brand. The first is more common.

Token discipline (preview)#

DESIGN.md commits to specific values for color, type, spacing. The agent's job is to consume those values via semantic tokens, not raw literals.

Examples:

bg-background, bg-card, bg-accent, text-foreground, text-muted-foreground

bg-zinc-900, bg-[#1a1a1a], text-blue-700, text-[#0080ff]

When the component consumes tokens, DESIGN.md is the single source of truth for color. Change the token in DESIGN.md → the entire app's color updates. When the component consumes raw literals, DESIGN.md is decorative. The actual color is whatever was hardcoded.

The kit ships scripts/check-tokens.sh, a bash linter that fails if it finds raw Tailwind color literals, hex codes in className, forbidden default fonts, or Material default easing. It runs on every Stop hook (if you wired the kit's example settings) and can be run manually before declaring a task done.

Chapter 11: Token discipline covers this in depth.

How /craft-ui consumes DESIGN.md#

The /craft-ui slash command is the kit's UI execution workflow. Its Phase 0 reads DESIGN.md before doing anything else:

Phase 0 — Context load. Read these files if they exist, in this order:

  1. DESIGN.md (project root) — brand, tokens, type, motion, forbidden defaults
  2. CLAUDE.md — project-wide context
  3. ...

If DESIGN.md doesn't exist, /craft-ui stops and tells you to run design-md-builder first. Without DESIGN.md, output drifts toward generic. Phases 3–4 of /craft-ui (aesthetic commitment, forbidden defaults) have nothing to anchor against.

That's by design. UI work without a written-down brand is the single largest source of generic regression.

Chapter 09 walks through /craft-ui end to end.

How design-reviewer consumes DESIGN.md#

The design-reviewer subagent is the kit's read-only design critic. It reads DESIGN.md, identifies what changed in the diff, takes screenshots at 4 viewports (375 / 768 / 1280 / 1920), and applies a rubric.

A representative finding from a design review report:

🔴 BLOCKING
- app/page.tsx:88 — body leading is 1.4; DESIGN.md §3 specifies 1.6 for body.
- components/Hero.tsx:23 — hover scale 1.05 violates DESIGN.md "no hover scales over 1.02".
- The hero uses Inter via Google Fonts import; DESIGN.md commits to Newsreader.

Notice that every finding cites either a specific DESIGN.md section or a project-specific forbid. The reviewer's job is to anchor against the written rules, not to hand-wave about taste.

Chapter 10: Verification gates covers design-reviewer in depth.

The unifying test#

Same as the PRD's unifying test, applied to UI:

"Could this UI be the home page of a different SaaS I've seen before?"

If yes, it's too generic. The fix is upstream: sharpen DESIGN.md, add a /forbid, re-run /craft-ui Phase 3 (aesthetic commitment).

Common stumbles#

SymptomFix
/craft-ui halts saying DESIGN.md is missingRun design-md-builder first
DESIGN.md exists but /craft-ui says required sections are missingThe doc is too vague. Re-run design-md-builder on the missing sections
Output looks generic despite DESIGN.mdDESIGN.md is too soft. Sharpen with /forbid, add specific aesthetic direction in Phase 3
design-reviewer says PASS but the work looks badDESIGN.md is too sparse. Nothing for the reviewer to anchor against. Add forbids and tighten
You keep arguing with the agent about a font choiceLock the font in DESIGN.md and reference it in CLAUDE.md ### Frontend aesthetics. Then the agent can't argue.
The forbidden defaults section is emptyRun design-md-builder Phase 8 again. The universal list alone is fine. The project-specific list grows via /forbid
You can't decide on an aesthetic directionUse the menu in design-md-builder's Phase 1 reference gathering. Pick the closest named direction and refine from there

Continue#

The three living docs are in shape. Next: use them in the daily build loop. Chapter 08: Roadmap and backlog.