Logo do site Logo do site
  • Product
  • Venture
  • Content Hub
  • Contact Us
Close
  • Product
  • Venture
  • Content Hub
  • Contact Us
Blogpost

Shipping a Component Library That LLMs Can Actually Read

May 21, 2026 10 min

Written by

  • David Lange
    David Lange

Chapter

  • Introduction
  • The problem with how LLMs see your library
  • Enter AGENTS.md
  • Shipping the docs in the package
  • Setting up a consumer
  • A few things to watch out for

Share article

Coppied!

Category

AI
Engineering
Uncategorized
Web3

If you’ve ever asked an AI assistant to “build a form with our Button and Select components”, you already know how this conversation usually goes. The assistant nods enthusiastically, generating something that looks plausible. Perhaps it gets it right, or maybe it just invents a `<Button color=”blue”>` API that nobody on your team has ever implemented. The assistant sighs contentedly, another day’s work complete.

We faced this problem in a recent project, where a shared internal package provides UI components to be used across several client apps. While working on the actual UI package, LLMs had a pretty good grasp of how it worked, but once we switched over to the app that actually uses the UI package, things started getting messy.

The problem with how LLMs see your library

Coding assistants can read files. They can grep, follow imports, open `package.json`, read READMEs. However, we often hold important information about how to interact with code elsewhere — in Storybook, Github PRs, or simply documentation files that would be hard to find unless you know about them already. This places valuable knowledge outside the reach of our LLMs, or at best demands they run around burning tokens looking for information. 

As for TypeScript types, they’re technically readable, but reading them well is a different problem. Following a `Props` interface across three files of generic helpers, conditional types, and `forwardRef` wrappers to figure out what props a `Select` accepts is the kind of work that can be done, but it’s wasteful. Even when the assistant gets the types right, it still has no idea which component to pick. Your assistant may know “this is the type signature of `CheckboxSelect`”, but how does it even know to pick that component when all you asked it to was “make a component with our multi-select with chips component”?

The LLM needs a little guidance:

  • Where to look when you tell it to “use an Accordion/Select/Dropdown/etc”;
  • And then how to use that component. Both in a strict typing sense, but also understanding common patterns of usage. If the component needs to be used within a context or provider, the LLM should know about it.

Enter AGENTS.md

AGENTS.md is a widely adopted file convention when it comes to informing agents — Claude Code, Cursor, Copilot, and others all look for it as a hint that «this file is meant for you to read». You can think of it as a `README.md` for models. 

To solve our package conundrum, we use it in two places

  •  A registry at the package root, listing every exported component with a one-line description.
  •  Per-component docs: an AGENTS.md sitting next to the component source, with props, a usage example, and the import name.

Here’s what the root registry looks like, abridged:

# UI Components

Shared React component library. Import from `@acme/ui-components`.

## Components

| Component | Description | Docs |
| --- | --- | --- |
| Accordion | Collapsible accordion with Jotai-scoped state | [AGENTS.md](src/components/AccordionV2/AGENTS.md) |
| Button | Text button with optional leading/trailing icons | [AGENTS.md](src/components/Button/AGENTS.md) |
| CheckboxSelect | Multi-select dropdown with chips | [AGENTS.md](src/components/CheckboxSelectV2/AGENTS.md) |
| Drawer | Side panel opened via `useDrawer` hook | [AGENTS.md](src/components/DrawerV2/AGENTS.md) |
| ...

It’s really just a flat markdown table, one row per public export, every row pointing to a deeper file. It’s meant as a starting point for component discovery, where your coding assistant doesn’t need to know everything, just an overview of what exists and where to find out more.

The per-component file is just as small:

# Avatar

Circular avatar displaying the user's initials (up to two characters) on a neutral background.

## Props

| Prop | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| name | `string` | required | Full name used to derive up to two initials |
| size | `"s" \| "m"` | `"s"` | Avatar diameter. `"s"` = 36px, `"m"` = 40px |

## Usage

```tsx
import { Avatar } from "@acme/ui-components";

<Avatar name="Tim Grossheimann" size="s" />
```

## Notes

- `Avatar` displays text initials only — it does not support image avatars.
- The initials are derived from the first letter of each word in `name`, capped at two characters. Pass the full name (e.g. `"Tim Grossheimann"`), not just initials.

The file gives the assistant what it needs to make a correct decision: what the component is, the import path, the prop names, the literal string unions, and a working snippet. Things like implementation details, internal helpers, theming theory, are all interesting but not directly relevant here. 

By using a registry/detail pattern we also allow the assistant to only load the necessary context for any given component. If it needs more information, it can find it on demand.

The file gives the assistant what it needs to make a correct decision: what the component is, the import path, the prop names, the literal string unions, and a working snippet. Things like implementation details, internal helpers, theming theory, are all interesting but not directly relevant here. 

By using a registry/detail pattern we also allow the assistant to only load the necessary context for any given component. If it needs more information, it can find it on demand.

Shipping the docs in the package

Once we have this useful documentation ready, the question is how do consumers of the package actually get them?

You could publish them to a docs site, or push them to GitHub, or rely on the assistant to wander over and fetch them. All of these would work, but they live somewhere other than the place the LLM is already looking. So we decided to ship the docs along with the actual library, so all the LLM needs lives in `node_modules`.

When a consumer runs `npm install`, the AGENTS.md files land alongside the JavaScript bundle. The assistant doesn’t need network access, doesn’t need a fetch tool, doesn’t need any extra plumbing — it just reads files in the project, the way it always does.

The exact wiring depends on your build tooling. Our library is built with Vite, so the snippets below use `vite-plugin-static-copy`. Regardless of your setup, the basic idea is «copy these files into the output directory».

With that caveat out of the way, here’s what worked for us: First, the build copies the markdown files into `dist/`:

JavaScript
// vite.config.ts
import { viteStaticCopy } from "vite-plugin-static-copy";

export default defineConfig({
  plugins: [
    // ...other plugins
    viteStaticCopy({
      structured: true,
      targets: [
        { src: "AGENTS.md", dest: "" },
        { src: "src/components/*/AGENTS.md", dest: "" },
      ],
    }),
  ],
});
```

Second, `package.json` declares them as part of what gets published:

JSON
{
  "files": [
    "dist",
    "AGENTS.md",
    "src/**/AGENTS.md"
  ]
}

After a publish, every consumer of the package finds the docs at predictable paths inside `node_modules`:

JSON
node_modules
  /@acme-ui-components	
    AGENTS.md			
    /src
/components
  /Button/
    AGENTS.md
  /Select/
    AGENTS.md

This adds to the final library size, as we’re adding a few more KB weight per component. This is a tradeoff we need to consider as the library grows, but at this point it’s not an issue. Either way the extra AGENTS.md files are not included in the final build of the consumer apps, thanks to tree shaking.

Setting up a consumer

The library side is done, but the consuming app still has to tell its assistant where the docs live. Without that nudge, the files are sitting in `node_modules` like every other dependency — present, but ignored.

We do this with a single block in `CLAUDE.md` (or any equivalent project-level instruction file — Cursor’s `.cursorrules`, Copilot’s instructions, and so on):

JSON
This project uses `@acme/ui-components`. When working with this library,
read the documentation files:

- `node_modules/@acme/ui-components/AGENTS.md` — index
- `node_modules/@acme/ui-components/src/components/*/AGENTS.md` —
  per-component docs

Always consult these before using or suggesting components from this library.

With this, we’re able to prompt things like «build a page with a regular layout, a header with an avatar at the end, when you click on the avatar a dropdown menu will open with x options.» Our assistant now knows what a «regular layout» actually is, how to define its header, how to render an Avatar, how dropdowns work, etc.

A few things to watch out for

A couple of things to be aware of as you adopt this pattern:

  • Keep it up to date. This is the bane of our existence, right? It’s easy for any documentation to become outdated, and it’s no different here. We added an “Update component documentation” skill that automates this, but it’s still something you need to be mindful of.
  • Keep things brief, don’t overcomplicate the Agents.md files.

You don’t need to completely redesign your library to make it LLM-friendly. You just need to leave a note where the assistant is looking.

Share article

Coppied!

Category

AI
Engineering
Uncategorized
Web3

You may also like

AI-Pilled is not a binary: AI adoption is a game of autonomy
Blogpost
AI-Pilled is not a binary: AI adoption is a game of autonomy
AI
Company Building
Uncategorized
Web3
May 18, 2026 6 min
Roberto Machado
Roberto Machado
There are no recipes for startup success: a few notes on how the marketing is being reshaped
Blogpost
There are no recipes for startup success: a few notes on how the marketing is being reshaped
Company Building
Inside Subvisual
Web3
April 27, 2026
Roberto Machado
Roberto Machado
Subscribe to Subvisual Inspo

Go to

  • Product
  • Ventures
  • Blog
  • Jobs / Careers

We're social

  • Git
  • Dri
  • In
  • X

Contact us

contact@subvisual.com

Offices

Remote. Work anywhere in Europe.
Or join our mothership, landed in Braga, Portugal