Skip to Content
Vektos

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 #2563eb instead of the accent.default token 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

4. Graders (output)1. Context (input)Storybook MCPds-mcp2. Coding agent3. Generated codetscoxlintAST gradersaxe · planned5. Violations + cost

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:

  1. 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).
  2. 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.
  3. Generated code. Whatever the agent produced. We do not fix it.
  4. 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).
  5. 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).

Editortsc -boxlintnext buildGrader
Whentypingpre-commitpre-commitdeploybenchmark
Knows the Panda configyesyesyesyesno
On a wrong valuered squiggleexit 1exit 1 + token hintbuild 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

  1. 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 .vektos class, so installing the design system never restyles the host page.

  2. Tokens become types. panda codegen (it runs on bun install) writes the styled-system/ folder: the css() function and the types behind it. With strictTokens on, css() accepts tokens and nothing else. The folder is generated and git-ignored; after you change a token, run bun run --filter @vektos/ds prepare.

  3. Components are Ark UI primitives styled with Panda recipes. Each component declares its props as an interface with JSDoc comments, and its styles as a cva or sva recipe, in the same file. That is not just style: react-docgen reads those comments and Storybook and the MCP display them. The eight components are listed in guides/06-components.

  4. Storybook is the documentation and the MCP server. bun run storybook serves the stories on port 6006 and an MCP endpoint at /mcp. An agent can call docs-list to see the components and docs-show to get props, defaults and example code. The test-run toolset is disabled because it needs Vitest; we use bun test.

  5. ds-mcp is the agent's view of the same sources. packages/ds-mcp reads the components, stories, panda.config.ts and 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-parser instead. 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, not react-docgen-typescript. The TypeScript flavor needs the TS API. The default works fine as long as props are declared in the component file.
  • postgres driver everywhere. Next runs on Node, where Bun.sql does not exist.
  • MCP SDK v2. @modelcontextprotocol/server is the current line; the old @modelcontextprotocol/sdk package 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 a todo test for it.
  • Installing @vektos/ds from 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:

WhoWhat they needWhere
Contributorshow it is built, how to extend itthis file and docs/guides/
Contributorswhat went wrong and what it taught us about the benchmarkdocs/anecdotes/
Agentsthe same pages as Markdown, with searchapps/docs: /llms.txt, /api/mcp
Developers using the design systemcomponents, tokens, rulesStorybook (MDX pages)
Teams running Vektos on their own design systeminstall, configure, read a reportdocs/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.

On this page