Every @voila.dev package ships as source. After bun add @voila.dev/ui,
node_modules/@voila.dev/ui/src contains the same .tsx files the maintainers
edit: no dist/, no minified bundle, no type stubs standing in for the real
thing. That is a nice property for you. For a coding agent, it changes the
game.
Why source makes generation reliable
An agent working against a compiled library has to guess. It saw some version of the API during training, the package on disk is opaque, and the gap between the two is where hallucinated props and invented imports come from.
An agent working against source-shipped components does not guess. It opens
node_modules/@voila.dev/ui/src/button/components/button.tsx, reads the props, the
variants and the cva block, and writes code against what is actually installed.
The code is the documentation, and it is always the right version. That is what
we mean by AI-readable.
Point the agent at the source
Tell your agent where the components live, once, in whatever standing-context
file your tool uses (CLAUDE.md for Claude Code, rules for Cursor, the
equivalent elsewhere):
## UI components
- UI comes from @voila.dev/ui. The full source is in
node_modules/@voila.dev/ui/src. Read the component file before using it.
- Import one component per path:
import { Button } from "@voila.dev/ui/button";
- Styling goes through the tokens. Use semantic classes (bg-primary,
text-muted-foreground, border-border), never raw colours.That is the whole setup. There is no plugin, no MCP server and no index to build. The package manager already put the source where the agent can read it.
Prompts that work
The pattern is always the same: name the component, and tell the agent to read the real file first.
Read
node_modules/@voila.dev/ui/src/dialog/components/dialog.tsx, then build a confirm step for deleting a workspace. Follow the composition the file exports.
Build the project form with components from
@voila.dev/ui. Check each component's source undernode_modules/@voila.dev/ui/src/<name>/components/before using it, and copy the prop names from there, not from memory.
Restyle this page for our brand. Use the tokens as the contract:
--primaryfor the accent,--mutedfor surfaces. Do not hard-code a single colour.
The last one is the trick most people miss. The tokens declared in
@voila.dev/ui/styles/tokens/*.css are the contract between your brand and the
components; a theme is just one set of values for them.
An agent told to "use --primary" produces output that follows every future
rebrand for free; an agent left to pick hex values produces output you will be
hunting down for months.
Why the output is predictable
Consistency is what makes a model accurate, and the system is consistent by construction:
- One convention across 85 components. Every component is built the same way: Base UI for behaviour, a cva block for variants, tokens for colour. An agent that has read three components has effectively read all of them.
- One import shape.
@voila.dev/ui/<name>— one subpath per component, never deeper, so there is no ambiguity about where a symbol comes from. - Tokens as the contract. Semantic custom properties mean the agent never has to invent a palette, and its output survives a rebrand.
Patterns a model can infer from one file and apply to the next 84 are patterns it will not get wrong.
When you want the agent to change a component
Because the source is readable, it is also forkable. If a component needs to become something the variants do not cover, have the agent copy the file out and own it:
Copy
node_modules/@voila.dev/ui/src/badge/components/badge.tsxintosrc/components/badge.tsx, add abetavariant to the cva block, and update the imports in this feature to use the local copy.
Same file, same convention, now yours. Everything else stays on the dependency and keeps receiving lockstep updates.
Next: Theming and tokens, the contract the prompts above lean on.