Migrating to Astryx with AI: An Experiment


ReactUI designAI developmentAstryxcomponent librarydesign system
8 min read
Table of Contents

I keep hearing about Astryx, “an open source design system that is fully customizable and agent ready.” As Meta describes in their guide on working with AI, the system is “built to be AI-friendly: consistent naming, predictable prop patterns, and a CLI that feeds structured documentation directly into AI context windows.” Unlike Material UI or Chakra, its CLI (astryx component, astryx template, astryx docs) outputs structured documentation in markdown, designed to be consumed by both humans and AI agents. That sounded like more than marketing. I wanted to test it.

I had a real project ready: a company expense tracker with ~2,500 lines of hand-rolled Tailwind CSS across 15+ components. Firebase auth, Firestore, React Router, Recharts, dark mode, PWA support - a proper production app. The code worked but the styling was inconsistent and tedious to maintain. If the AI could migrate this to a proper design system with minimal human effort, that would be a real signal.

Scope and How We Approached It

The project had a clear scope: swap every hand-rolled UI element with an Astryx equivalent while preserving all business logic, auth flows, chart visualizations, and data wiring. No functional changes, just a UI migration.

Before any code was written, we planned the entire migration in dependency-ordered phases:

PhaseGoalFiles
1Setup: install Astryx, create custom theme, wire up app shellApp.tsx, ocean.ts, index.css
2aToast: replace custom toast context with useToast()ExpenseForm.tsx, ExpenseEntries.tsx, Settings.tsx
2bNavigation: rewrite with TopNav, TopNavItemNavigation.tsx
2cShell: wrap auth-gated routes in AppShell with LinkProviderApp.tsx
3aAuth forms: Login, Signup, ResetPassword with Astryx primitives3 auth form files
3bEverything else: Dashboard, Analytics, Settings, charts, PWA9 component files

The ordering mattered: you can’t see components without the theme and shell wired up, and you can’t test anything behind login without auth forms migrated. Each phase was immediately verifiable: npx tsc --noEmit && npx vite build && npx eslint . after every change. No half-working state was ever committed.

A running todo list tracked every task from pendingin_progresscompleted, surfaced blockers, and showed overall progress at a glance.

The workflow per file:

  1. Read the file
  2. Fetch Astryx component docs: astryx component Button --dense
  3. Rewrite using Astryx while preserving business logic
  4. Run type-check, build, lint
  5. Fix any issues, repeat

The average file took 2–4 iterations. Most were one-and-done; a few needed a runtime fix after seeing the dev server output.

What Was Done

Every UI component was replaced:

Hand-rolled ElementAstryx Replacement
Glass div containers<Card>
Custom <button> elements<Button> / <IconButton>
<input> with Tailwind<TextInput> / <NumberInput> / <DateInput>
<select> with Tailwind<Selector>
Loading spinners<Spinner>
Loading skeletons<Skeleton>
Flexbox layout divs<VStack> / <HStack>
Custom nav bar<TopNav> / <TopNavItem> / <TopNavHeading>
Custom toast context + provideruseToast() from @astryxdesign/core/Toast
Auth form layouts<Card> + <Center> + <TextInput> + <Button> + <Banner>
Theme toggle button<IconButton> with Sun / Moon icons
App layout wrappers<AppShell> with topNav, contentPadding
React Router link integration<LinkProvider> + RouterLink adapter
<html> class-based dark mode<Theme mode={...}> + DarkModeProvider bridge

Chart components (BudgetRing, MealDistribution, ExpenseChart) kept their Recharts internals but were wrapped in <Card>. The PrivateRoute component was the only file left untouched: it’s 9 lines of pure auth logic with zero UI.

A custom ocean theme was created extending @astryxdesign/theme-neutral, preserving the original color palette (blue primary, meal-type colors), fonts (DM Sans, Plus Jakarta Sans), and rounded design tokens.

Tokens and Cost

Note: exact token counts aren’t available without per-session instrumentation. The numbers below are rough estimates reconstructed from file sizes and operation counts.

The session consumed roughly 170K–200K tokens total (input + output):

CategoryCountEst. tokens
astryx component --dense doc fetches~12 calls~8K
File reads via Read tool~15 files, ~180 lines avg~75K
File rewrites via Write tool~12 files, ~200 lines avg~72K
Targeted edits via Edit tool~10 edits~1K
Type-check / build / lint runs~6 runs~2K
Sub-agent tasks (parallel exploration)~3 tasks~20K–40K
Planning, orchestration, overhead-remainder

The bulk of the token budget went to reading existing files and generating rewrites: accurately representing file contents and producing correct Astryx equivalents.

At cloud inference pricing that’s roughly $0.03–$0.06. With DeepSeek V4 Flash Free’s free tier it was effectively zero. The entire migration took about 90 minutes of wall-clock time, most of which was human review rather than waiting on the model.

Plus Points We Saw

1. CLI-first docs eliminate web scraping. The astryx component Button --dense command returns a clean markdown table of props, types, defaults, import path, and best practices: no HTML parsing, no navigation filtering, no stale cached pages. The --dense flag strips template examples, keeping just the API surface. This is the biggest practical advantage over every other design system.

2. The IconType vs ReactNode distinction is the only real gotcha. Astryx uses IconType (pass a component reference) for props like NumberInput.startIcon and Selector option .icon, but ReactNode (pass a JSX element) for Button.icon and IconButton.icon. The docs state this clearly but it’s easy to mix up on the first pass. Once learned, it’s consistent.

3. Practical scope. Astryx doesn’t try to own everything. Charts stay in Recharts, routing stays in React Router. It replaces the UI shell (buttons, inputs, cards, nav, toasts) and leaves the rest alone. This makes migration incremental rather than all-or-nothing.

4. The theming system works. defineTheme with component overrides and CSS variables meant the custom ocean theme preserved the app’s existing visual identity. astryx theme build compiled it without extra tooling.

5. Glassmorphism → Card. The original code had extensive backdrop-blur-xl bg-white/80 glass effects. <Card> replaced these with consistent, theme-aware containers. Some visual character was lost, but the gain in consistency and maintainability was worth it.

Tools and Model Used

Opencode was the AI coding agent: it ran in the terminal, read/wrote files via dedicated tools, searched code, executed build commands, and maintained a persistent session with full context across all phases.

DeepSeek V4 Flash Free was the model: a cost-efficient offering with a 1 million token context window. The large context was critical: the model could reference any earlier file, previously fetched component doc, or past decision without needing to re-query. During the Phase 3a auth forms migration, it still recalled the TextInput props fetched in Phase 1 without re-fetching.

The model ran entirely locally via Opencode. No source code ever left the machine: important for production codebases where sending code to third-party APIs is a non-starter.

Astryx CLI provided the astryx component, astryx template, and astryx docs commands. The --features agents flag during astryx init generated an MCP config that let the AI fetch docs directly. The --dense flag on component docs stripped examples and returned just the prop API, optimized for the model’s context window.

The combination formed a tight loop: astryx component Button --dense → AI reads → AI writes → npx tsc --noEmit → repeat. No browser tabs, no web scraping, no manual doc hunting.

In Short

Would I do it again? Yes. The migration cost ~$0.05 in cloud-equivalent tokens, took 90 minutes of human time, and produced a codebase that’s visually consistent, type-safe, and ready for new components. The CLI-first documentation model is genuinely better for AI agents: not incrementally better, but categorically different from every other design system.

For anyone evaluating design systems with an eye on AI tooling, the experiment is worth running. Install Astryx, point an agent at a real codebase, and see what happens. The answer may surprise you.


Tooling: Opencode (AI coding agent) · DeepSeek V4 Flash Free (model) · Astryx Design System (component library) · Vite + React 19 + TypeScript (stack)