Skip to content
kitn AI/UI

For AI Agents

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.

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.

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:

Terminal window
claude mcp add kai -- npx -y @kitn.ai/ui mcp

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

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

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.

@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.

FileSizeUse
llms.txt~4 KBOrientation: install, the property rule, framework wiring, theming. Paste into a prompt.
llms-full.txt~60 KBEverything 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.

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:

ToolWhat to do
Claude CodeAdd @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 CopilotAdd the path to .github/copilot-instructions.md; workspace indexing picks it up
CursorReference the file in .cursorrules
Codex / ChatGPTPaste https://ui.kitn.ai/llms.txt into the prompt, or fetch it with a browsing tool
Any agentnpm install @kitn.ai/ui — file is at node_modules/@kitn.ai/ui/llms.txt

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 JavaScript
const 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 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

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;
});

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 format can read it directly.