# For AI Agents

Make your AI coding assistant fluent in AI/UI — index it in Context7, run the MCP server, or point it at the machine-readable reference, and it wires components correctly the first time.

Make your coding assistant fluent in AI/UI before you build. Pick whichever channel your tools already use — index it in Context7, run the MCP server, or point it at the machine-readable reference.

## Index it in Context7

If you use [Context7](https://context7.com) — the documentation MCP most assistants support — search for **Kitn AI/UI**. The full docs, the `kai-` element reference, and the integration guides are indexed there, so your assistant pulls the real API on demand. No install, no copy-paste.

> **tip:** Context7 serves the reference on demand. For a one-off prompt without Context7, paste `llms.txt` (below).

## Use the AI/UI MCP server

`npx @kitn.ai/ui mcp` is a stdio MCP server that gives any MCP harness four tools: **`component_reference`** (look up the real `kai-*` API), **`scaffold`** (generate a working chat wired to your backend), **`theme`** (brand it from a color or a description), and **`debug`** (catch the classic mistakes). It runs locally, holds no state, and makes no network calls.

Where Context7 hands the agent the reference, the MCP server lets it *act* — generate a route, emit theme tokens, diagnose a broken snippet.

Add the server to your harness:

<Tabs>
<TabItem label="Claude Code">

```bash
claude mcp add kai -- npx -y @kitn.ai/ui mcp
```

Or add it to `.mcp.json` (project scope) by hand:

```json
{
  "mcpServers": {
    "kai": {
      "command": "npx",
      "args": ["-y", "@kitn.ai/ui", "mcp"]
    }
  }
}
```

</TabItem>
<TabItem label="Codex">

In `~/.codex/config.toml` (global) or `.codex/config.toml` (project):

```toml
[mcp_servers.kai]
command = "npx"
args = ["-y", "@kitn.ai/ui", "mcp"]
```

</TabItem>
<TabItem label="OpenCode">

In `opencode.json`:

```json
{
  "mcp": {
    "kai": {
      "type": "local",
      "command": ["npx", "-y", "@kitn.ai/ui", "mcp"],
      "enabled": true
    }
  }
}
```

</TabItem>
<TabItem label="GitHub Copilot">

In `.vscode/mcp.json`:

```json
{
  "servers": {
    "kai": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@kitn.ai/ui", "mcp"]
    }
  }
}
```

</TabItem>
<TabItem label="Pi">

Pi reads MCP servers from `~/.pi/agent/mcp.json`, using the same `mcpServers` shape as Claude Code:

```json
{
  "mcpServers": {
    "kai": {
      "command": "npx",
      "args": ["-y", "@kitn.ai/ui", "mcp"]
    }
  }
}
```

If Pi's config has moved, check [Pi's MCP documentation](https://github.com/earendil-works/pi) for the current path and keys.

</TabItem>
</Tabs>

The server reads the installed package's own `custom-elements.json` and integration catalogs, so the API it reports and the code it scaffolds always match the version you have — no drift between the docs and your `node_modules`.

## Machine-readable files

`@kitn.ai/ui` ships two auto-generated files that follow the [llmstxt.org](https://llmstxt.org) convention — prop names, event names, and the property-vs-attribute rule, so an agent gets them right without hallucinating.

| File | Size | Use |
|---|---|---|
| `llms.txt` | ~4 KB | Orientation: install, the property rule, framework wiring, theming. Paste into a prompt. |
| `llms-full.txt` | ~60 KB | Everything in `llms.txt` plus a generated props/events table for every element, a streaming recipe, and a build runbook. |

Every docs page also has a **Markdown twin** at `<page-url>.md` (e.g. `/components/chat.md`) — clean source you can hand to any model.

### Where they live

After `npm install @kitn.ai/ui`, both files are in the package:

```
node_modules/@kitn.ai/ui/llms.txt
node_modules/@kitn.ai/ui/llms-full.txt
```

They are also published at:

- **https://ui.kitn.ai/llms.txt**
- **https://ui.kitn.ai/llms-full.txt**

### Point an agent at them

| Tool | What to do |
|---|---|
| **Claude Code** | Add `@node_modules/@kitn.ai/ui/llms.txt` to `CLAUDE.md`, or run `read node_modules/@kitn.ai/ui/llms-full.txt` in the session |
| **GitHub Copilot** | Add the path to `.github/copilot-instructions.md`; workspace indexing picks it up |
| **Cursor** | Reference the file in `.cursorrules` |
| **Codex / ChatGPT** | Paste `https://ui.kitn.ai/llms.txt` into the prompt, or fetch it with a browsing tool |
| **Any agent** | `npm install @kitn.ai/ui` — file is at `node_modules/@kitn.ai/ui/llms.txt` |

## What agents most commonly get wrong

These facts appear in both files. They are the three mistakes that produce silent failures.

### 1 — Array and object data goes on JS properties, not HTML attributes

An HTML attribute is always a string. Passing `messages`, `models`, `context`, `suggestions`, or `triggers` as an attribute silently fails.

```js
// Works — set the property in JavaScript
const chat = document.querySelector('kai-chat');
chat.messages = [{ id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hello!' }] }];
```

```html
<!-- Fails — an array can't be an HTML attribute -->
<kai-chat messages="[...]"></kai-chat>
```

Only scalar props — `placeholder`, `loading`, `theme` — work as attributes.

### 2 — Events are non-bubbling `kai-*` CustomEvents

Listen directly on the element, not on a parent:

```js
chat.addEventListener('kai-submit', (e) => {
  console.log(e.detail.value); // the text the user typed
});
```

Common events: `kai-submit`, `kai-feedback`, `kai-model-change`, `kai-new-chat`, `kai-select`.

### 3 — Streaming requires a new array and a new object on every chunk

Mutating an existing message object in place does not trigger a re-render. Replace instead:

```js
// Triggers a re-render on every chunk
chat.messages = chat.messages.map(
  (m) => (m.id === assistantId ? { ...m, parts: [{ type: 'text', text: accumulated }] } : m)
);

// Does NOT trigger a re-render
chat.messages[i].parts = [{ type: 'text', text: accumulated }];
```

The same rule applies to every array/object property: always assign a new reference.

## Runbook: wire a streaming chat in 15 lines

```js

await customElements.whenDefined('kai-chat');

const chat = document.querySelector('kai-chat');
chat.messages = [];

chat.addEventListener('kai-submit', async (e) => {
  const userText = e.detail.value;

  // Append user message — new array
  const history = [
    ...chat.messages,
    { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text: userText }] },
  ];
  chat.messages = history;
  chat.loading = true;

  // Empty assistant placeholder to stream into
  const assistantId = crypto.randomUUID();
  chat.messages = [...history, { id: assistantId, role: 'assistant', parts: [] }];

  // Stream — replace with a new array + new object on every chunk
  let accumulated = '';
  for await (const token of streamFromYourAPI(history)) {
    accumulated += token;
    chat.messages = chat.messages.map((m) =>
      m.id === assistantId ? { ...m, parts: [{ type: 'text', text: accumulated }] } : m
    );
  }
  chat.loading = false;
});
```

## Custom Elements Manifest

The raw machine-readable spec — every property, event, attribute, and type — is published at:

```
https://unpkg.com/@kitn.ai/ui/dist/custom-elements.json
```

This is the source from which `llms.txt` and `llms-full.txt` are generated. IDE plugins that consume the [Custom Elements Manifest](https://custom-elements-manifest.open-wc.org/) format can read it directly.

## Related

- [Installation](/guides/installation/) — install the package and register the web components
- [Getting Started](/guides/getting-started/) — first steps with `<kai-chat>`
