Skip to content
Aihio v2.3.0
Search
GitHub
Search Describe what you are building, or name a component, intent, or token. Components and patterns are ranked the way the MCP server's find tool ranks them for an agent.

Start here

Built to be written by agents

Every component has a machine-readable contract, and the same build turns it into a prompt fragment, a linter that suggests fixes, an MCP server, types, and this site. They are generated from one schema, so they cannot disagree: if the linter accepts markup, the prompt taught it and the docs show it.

Connect an agent

The package ships a local stdio server, started with aihio mcp. Add it to the client that writes your UI: npx runs the project's copy of @luntta/aihio when it is installed, and fetches the package otherwise.

Claude Code

claude mcp add aihio -- npx -y @luntta/aihio mcp

Any client with a JSON config

Claude Desktop, Cursor, and other clients with an mcpServers config take the same entry. VS Code's .vscode/mcp.json takes it under servers instead.

{
  "mcpServers": {
    "aihio": {
      "command": "npx",
      "args": ["-y", "@luntta/aihio", "mcp"]
    }
  }
}

Without MCP

Put the prompt fragment in the system prompt or the project's instructions, and lint what comes back.

import prompt from '@luntta/aihio/prompt';
import { lintMarkup } from '@luntta/aihio/lint';

MCP tools

Read from the server itself. It also serves the prompt fragment as the prompt aihio-authoring.

find
query
Start here. Given what the UI has to do — free text such as "confirm before deleting a project", or an intent name such as "destructive-action" — return the best-matching components and canonical patterns. Adapt a returned pattern with get_pattern rather than composing from scratch.
list_components
List every top-level Aihio component with its one-line purpose, intents, commands, and subcomponents.
list_patterns
List the canonical multi-component patterns (auth form, settings section, destructive confirmation, ...) with their purpose and intents.
get_pattern
id
Return a canonical pattern's complete, lint-clean markup and its variations. Adapt it instead of freehanding the structure.
describe
component
Return the schema entry for a component tag such as "aihio-button" or "button".
lint
markupsource?
Validate markup against the Aihio schema and return structured issues. Run it on every snippet before returning it; an issue with a "suggestion" can be fixed by applying that replacement.

What find returns

Run at build time, for "confirm before deleting a project". Scores are trimmed from the full entries.

{
  "components": [
    {"tag":"aihio-dialog","score":8},
    {"tag":"aihio-alert","score":2},
    {"tag":"aihio-button","score":1}
  ],
  "patterns": [
    {"id":"destructive-confirmation","score":6},
    {"id":"auth-form","score":1},
    {"id":"data-table","score":1},
    {"id":"empty-state","score":1},
    {"id":"inline-form-validation","score":1}
  ]
}

The lint loop

Lint every snippet before returning it. An issue with a suggestion is fixed by applying the suggestion, so a model needs one round trip, not a reading of the docs. This is the linter's real output.

1. Markup in the shape of other design systems

<aihio-button variant="primary" href="/pricing">See pricing</aihio-button>

2. lintMarkup() returns

[
  {
    "ruleId": "unknown-attribute",
    "severity": "error",
    "message": "<aihio-button> has no attribute \"href\": a button does not navigate. Put the link inside it, and it becomes the control, styled as the button: <aihio-button variant=\"primary\"><a href=\"/pricing\">See pricing</a></aihio-button>",
    "suggestion": "<aihio-button variant=\"primary\"><a href=\"/pricing\">See pricing</a></aihio-button>"
  },
  {
    "ruleId": "invalid-enum-attribute",
    "severity": "error",
    "message": "invalid variant=\"primary\". Use variant=\"default\". Expected one of: default, secondary, outline, ghost, link, destructive.",
    "suggestion": "variant=\"default\""
  }
]

3. Both suggestions applied

0 issues. The link is a real link, drawn as the button.

<aihio-button variant="default"><a href="/pricing">See pricing</a></aihio-button>

Files to read

Everything ships in the package. This site also serves llms.txt, llms-full.txt, and every component page as markdown (components/button/index.md), which the "Copy for agent" button on each component page copies.

dist/aihio.prompt.md
import@luntta/aihio/prompt.md 64 KB
The prompt fragment: rules, every component, the intent map, patterns, obligations, and each mistake beside its fix.
dist/schema.json
import@luntta/aihio/schema 186 KB
The full schema: components, sub-components, intents, patterns, examples, and counterexamples.
dist/schema.min.json
import@luntta/aihio/schema/min 90 KB
The same, with the prose stripped, for a tight context budget.
dist/semantic-tokens.md
import@luntta/aihio/tokens.md 12 KB
Every semantic token, its source, and what it is for.
dist/tokens.json
import@luntta/aihio/tokens 56 KB
Every token in every tier, with resolved light and dark values and the contrast contract.
dist/aihio.d.ts
import@luntta/aihio 24 KB
Types generated from the schema, including JSX intrinsic elements.

In the browser

The rules an agent reads are the ones the page enforces while you build.

aihio/dev
The same components, with console warnings for invalid attribute values and broken accessibility obligations, checked by the same rules as the linter. The production bundle carries none of it.
Aihio.describe(tag)
A component's schema at runtime, for tools that inspect a live page.
data-aihio-intent
Says what an element is for, from the intent vocabulary. Optional, but the linter rejects an annotation the component's schema does not back.
dist/aihio.d.ts
Types generated from the schema: attribute unions, intents, and JSX intrinsic elements.