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
Section titled “Index it in Context7”If you use Context7 — 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.
Use the AI/UI MCP server
Section titled “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:
claude mcp add kai -- npx -y @kitn.ai/ui mcpOr add it to .mcp.json (project scope) by hand:
{ "mcpServers": { "kai": { "command": "npx", "args": ["-y", "@kitn.ai/ui", "mcp"] } }}In ~/.codex/config.toml (global) or .codex/config.toml (project):
[mcp_servers.kai]command = "npx"args = ["-y", "@kitn.ai/ui", "mcp"]In opencode.json:
{ "mcp": { "kai": { "type": "local", "command": ["npx", "-y", "@kitn.ai/ui", "mcp"], "enabled": true } }}In .vscode/mcp.json:
{ "servers": { "kai": { "type": "stdio", "command": "npx", "args": ["-y", "@kitn.ai/ui", "mcp"] } }}Pi reads MCP servers from ~/.pi/agent/mcp.json, using the same mcpServers shape as Claude Code:
{ "mcpServers": { "kai": { "command": "npx", "args": ["-y", "@kitn.ai/ui", "mcp"] } }}If Pi’s config has moved, check Pi’s MCP documentation for the current path and keys.
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
Section titled “Machine-readable files”@kitn.ai/ui ships two auto-generated files that follow the 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
Section titled “Where they live”After npm install @kitn.ai/ui, both files are in the package:
node_modules/@kitn.ai/ui/llms.txtnode_modules/@kitn.ai/ui/llms-full.txtThey are also published at:
Point an agent at them
Section titled “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
Section titled “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
Section titled “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.
// Works — set the property in JavaScriptconst chat = document.querySelector('kai-chat');chat.messages = [{ id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hello!' }] }];<!-- 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
Section titled “2 — Events are non-bubbling kai-* CustomEvents”Listen directly on the element, not on a parent:
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
Section titled “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:
// Triggers a re-render on every chunkchat.messages = chat.messages.map( (m) => (m.id === assistantId ? { ...m, parts: [{ type: 'text', text: accumulated }] } : m));
// Does NOT trigger a re-renderchat.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
Section titled “Runbook: wire a streaming chat in 15 lines”import '@kitn.ai/ui/elements';
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
Section titled “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.jsonThis is the source from which llms.txt and llms-full.txt are generated. IDE plugins that consume the Custom Elements Manifest format can read it directly.
Related
Section titled “Related”- Installation — install the package and register the web components
- Getting Started — first steps with
<kai-chat>