ui-sdk gives agents the building blocks to create components and the tools to use them.

Agents Build Components

You can ask an agent to build a component for your app, from a toggle button to an emoji picker or a kanban board.

@ui-sdk/core gives it behaviors: tested building blocks for focus, keyboard navigation, selection, popups, drag and drop, and more. The agent combines them to handle the interactions your component needs.

A primitive brings a component's state, actions and parts together. Here's a small one: a mute button.

import { definePrimitive } from "@ui-sdk/core"

const muteButton = definePrimitive({
  name: "mute-button",
  state: () => ({ muted: false }),
  api: (context) => ({
    toggle: () => context.store.set({ muted: !context.store.get().muted }),
  }),
  slots: (slot) => ({
    root: slot({
      attrs: (state) => ({
        type: "button",
        "aria-pressed": String(state.muted),
      }),
      press: ({ api }) => api.toggle(),
    }),
  }),
})

export { muteButton }

Pressing the button changes muted, and aria-pressed follows it. The same primitive can render in React, Vue, Svelte, Solid and Web Components. Build a Component walks through connecting it to your framework and adding styles.

The component skill gives the agent a workflow to follow. Each package includes Markdown docs for the installed version, and the testing kit helps it check keyboard behavior, focus and ARIA in the finished component.

Agents Use Your Components

Connect an agent to a UI built with ui-sdk and it can read component state and call component actions directly. For example, it can rename a project by calling the input's setValue action.

Create the bridge before the page renders. Import it from the same package as your components; this example uses React:

import { createAgent } from "@ui-sdk/react/agent"

const agent = createAgent()

Once the page has rendered, agent.snapshot() lists its components, their state and their available actions. For a project-name input, it includes:

{
  "ref": "c1",
  "component": "input",
  "label": "Project name",
  "value": "Apollo",
  "actions": ["setValue", "clear"]
}

The agent can use that label to change the value:

await agent.act({
  steps: [{ ref: "Project name", action: "setValue", args: ["Atlas"] }],
})

The change goes through the input's API and change callback. Your app can provide an allow callback to approve or refuse requested actions. Change callbacks receive source: "agent" and can cancel a change too.

You can give these tools to your own agent, or register them with a supported browser through WebMCP.

Benchmark

In a project-settings benchmark, agents renamed a project, updated members and notification settings, then saved. One used browser tools on a page built with another component library; the other used the agent bridge on the same screen built with ui-sdk.

Browser toolsui-sdk + agent bridgeDelta
Tool calls165−69%
Text read39.8k6.8k−83%
Time41 s16 s−61%
Cost$0.073$0.032−56%

These are medians from three runs per approach. Both agents used Sonnet through Claude Code with the same task and system prompt, plus instructions for their available tools. Every run completed the task. Text read counts characters returned by the tools. Time and cost are what Claude Code reported for those runs.

Where to Start