Architecture
How Vektos is built and why, and where a wrong value gets caught.
This page explains how Vektos is built and why. It describes the code as it is today (week 2) and grows with it: every new capability adds a few lines here and a guide in guides/. For the roadmap and the business reasoning, read PLAN.md.
1. What Vektos does
Vektos gives an AI coding agent a UI task, hands it some context about a design system, and lets it write code. Then it measures two things:
- Violations: how often the generated code ignored the design system. A hand-written
#2563ebinstead of theaccent.defaulttoken is one violation. - Cost per run: what the agent spent in tokens to produce that code.
The question behind it: does giving the agent better context about the design system produce better code, and at what price?
2. The repository
Vektos is a single Bun workspace with one TypeScript version (7.0.2). Today it has eleven packages:
vektos/
apps/web/ The Next.js app: the dashboard (overview, runs, batches, run detail) and the chat, built with the design system.
apps/docs/ The docs site (Fumadocs). Serves docs/ with search, llms.txt and an MCP server.
packages/ds/ The design system: components, tokens, Storybook and its MCP server.
packages/bench/ The benchmark: graders, the task loader and the runner (`bun run bench`).
packages/ds-mcp/ The design-system MCP server: the optimized context for agents.
packages/pricing/ Model price tables and the cost of a model call.
packages/db/ Postgres schema and migrations: every run kept as history, and the chunks for retrieval.
packages/chat/ The chat: tools over the runs and the corpus, checked citations, conversations and spending caps.
packages/rag/ Chunking, ingest, search, reranking and retrieval evals over Markdown (`bun run rag:*`).
corpus/ WCAG 2.2 and the European Accessibility Act, as Markdown for retrieval.
tasks/ Five fintech tasks: prompt, fixture data and a reference solution each.
docs/ PLAN, this file, the guides, the anecdotes.The chat will arrive as the plan unfolds. It is listed in PLAN §5 so this page does not promise things that do not exist yet.
3. How a benchmark run flows
Every run starts from a task in tasks/: a product-style prompt, fixture data and the
texts the finished page must show (guides/08-tasks). Then read
the diagram left to right:
- Context. What the agent is allowed to know before it starts. This is the part we
vary in experiments: nothing, a standard MCP (Storybook's), or hand-tuned context
(
ds-mcp, see guides/07-ds-mcp). - Agent. Any coding agent. The first runner uses the AI SDK: a model, a small in-memory workspace and the context's tools (guides/10-runner). Claude Code and Codex come later.
- Generated code. Whatever the agent produced. We do not fix it.
- Graders. Independent checks that read the code and report problems. Some read
the source; others run it:
tsc, oxlint and a real Chrome with axe, on the page the agent wrote (guides/11-page-graders). - Score. Violations and cost, stored per run in Postgres (guides/12-database) so we can compare contexts. Cost is computed per request from the token usage and a date-versioned price table (guides/09-pricing).
4. Five places where a wrong value gets caught
The thesis of Vektos is that "wrong" can be defined precisely: a style value that is not a design token. We check that in five places, each at a different moment.
While you type. The editor runs the project's TypeScript 7. Inside css({ ... })
it suggests only real tokens and underlines anything else in red. This is what makes
the design system feel like a type system.
tsc -b. Same check, run from the terminal over every package. It is part of
bun run check, which runs before every commit.
oxlint with the Panda rules. The linter knows the Panda config, so it goes further
than types. It can say "12px is not a token, but 3 is", catch a :hover that Panda
would silently ignore, or flag marginLeft where the logical marginInlineStart is
expected.
next build. Next runs the type check during the production build. A wrong value
stops the build with "Failed to type check". Nothing ships.
The graders. These are different: they do not block, they count. The
benchmark needs agents to be free to make mistakes so we can measure them. The graders
parse the generated code (and any .css) and list, with line and column, every
hand-written value, every token used for the wrong job, every suppression comment and
every edit to the design system's own config. See
guides/03-graders. A second set opens the page in a browser
and checks that it renders, shows the required texts and passes axe in both themes
(guides/11-page-graders).
| Editor | tsc -b | oxlint | next build | Grader | |
|---|---|---|---|---|---|
| When | typing | pre-commit | pre-commit | deploy | benchmark |
| Knows the Panda config | yes | yes | yes | yes | no |
| On a wrong value | red squiggle | exit 1 | exit 1 + token hint | build fails | +1 violation |
Why does the grader ignore the Panda config? Because it has to run on code from any stack, including the Tailwind side of the benchmark matrix, and produce the same kind of report.
5. The design system, in five steps
-
Tokens are declared once, in
packages/ds/panda.config.ts. We use Panda's base preset, which brings utilities but no colors, so a token exists only if we wrote it. The CSS reset is scoped to a.vektosclass, so installing the design system never restyles the host page. -
Tokens become types.
panda codegen(it runs onbun install) writes thestyled-system/folder: thecss()function and the types behind it. WithstrictTokenson,css()accepts tokens and nothing else. The folder is generated and git-ignored; after you change a token, runbun run --filter @vektos/ds prepare. -
Components are Ark UI primitives styled with Panda recipes. Each component declares its props as an
interfacewith JSDoc comments, and its styles as acvaorsvarecipe, in the same file. That is not just style:react-docgenreads those comments and Storybook and the MCP display them. The eight components are listed in guides/06-components. -
Storybook is the documentation and the MCP server.
bun run storybookserves the stories on port 6006 and an MCP endpoint at/mcp. An agent can calldocs-listto see the components anddocs-showto get props, defaults and example code. Thetest-runtoolset is disabled because it needs Vitest; we usebun test. -
ds-mcp is the agent's view of the same sources.
packages/ds-mcpreads the components, stories,panda.config.tsand the MDX rules, and serves them as Markdown over stdio: semantic tokens with both theme values, examples rewritten to compile on their own, and the rules without the sections meant for maintainers.
6. Decisions worth knowing
- TypeScript 7 only. The native compiler is much faster, but it has no JavaScript
API yet. We accepted that: everything that needs to read code uses
oxc-parserinstead. No TS 5 fallback anywhere. - oxc instead of Biome. Panda publishes official lint rules for oxlint, and tsgolint (type-aware linting) is built on the exact TS 7 version we use. Biome could not run either. The cost: oxfmt is still 0.x and oxlint JS plugins are in alpha.
react-docgen, notreact-docgen-typescript. The TypeScript flavor needs the TS API. The default works fine as long as props are declared in the component file.postgresdriver everywhere. Next runs on Node, whereBun.sqldoes not exist.- MCP SDK v2.
@modelcontextprotocol/serveris the current line; the old@modelcontextprotocol/sdkpackage is legacy. - Bun isolated linker. Every package must declare everything it imports. Stricter, but it keeps the packages publishable.
7. Known gaps
Things we know are wrong and plan to fix (PLAN §7):
- Computed values. The graders read literals.
const c = "#fff"; css({ bg: c })slips through. There is atodotest for it. - Installing
@vektos/dsfrom npm.styled-system/*imports resolve through the tsconfig, which consumers will not have. Subpath imports are the likely fix.
8. Where the docs live
Three audiences, three places:
| Who | What they need | Where |
|---|---|---|
| Contributors | how it is built, how to extend it | this file and docs/guides/ |
| Contributors | what went wrong and what it taught us about the benchmark | docs/anecdotes/ |
| Agents | the same pages as Markdown, with search | apps/docs: /llms.txt, /api/mcp |
| Developers using the design system | components, tokens, rules | Storybook (MDX pages) |
| Teams running Vektos on their own design system | install, configure, read a report | docs/user/, from week 2 when the runner exists |
One rule keeps all of this alive: a feature is not done until its page is updated, in
the same commit. It is written down in AGENTS.md so coding agents follow it too.