> For the complete documentation index, see [llms.txt](https://docs.limio.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.limio.com/ai/limio-agents/vibe-coding-a-chat-surface.md).

# Vibe Coding a Chat Surface

[Getting Started](/ai/limio-agents/getting-started.md) shows how to hand-write a chat surface on `@limio/sdk/ai`. This guide takes the faster path: describe the surface you want and let Claude Code generate it as a Limio custom component, grounded in the SDK docs so it builds on the real primitives.

A chat surface is a custom component like any other, so the workflow is the one from [Guide: Vibe Code Custom Components with Claude Code](https://docs.limio.com/guides/developer-guides/guide-vibe-code-custom-components-with-claude-code): prompt, push, preview in Storybook, deploy in Page Builder. What differs is the grounding and the prompt, which is what this page covers.

{% hint style="info" %}
The agent client SDK (`@limio/sdk/ai`) is available from Release 117 onwards. You also need a published agent to test against; see [Configuring an Agent](/ai/limio-agents/configuring-an-agent.md).
{% endhint %}

## Prerequisites

* **Claude Code** (or Cursor or a similar AI coding tool)
* **Access** to your organisation's component repo ([getting started with the components repository](https://docs.limio.com/developers/custom-components/custom-components#getting-started-with-limio-components-repository))
* **CI/CD pipeline** connected, if you use GitHub or GitLab ([Connecting External CI](https://docs.limio.com/developers/custom-components/connecting-external-ci))
* The **Limio Skills plugin** installed ([Skills](/ai/vibe-coding/skills.md)), so Claude knows the repo conventions: component structure, `package.json` dependencies, Page Builder props, Storybook

## Ground Claude in the agent SDK

The Limio Skills plugin covers components in general; the agent knowledge comes from the SDK docs. Start the conversation by pointing Claude at them:

```
Read these two pages before writing any code:
- https://docs.limio.com/ai/limio-agents/getting-started
- https://docs.limio.com/ai/limio-agents/sdk-reference

Build only on the documented @limio/sdk/ai exports. Do not call the
Chat API directly and do not invent SDK methods.
```

The exports Claude should reach for:

| Primitive                        | What it does                                                                                                                               |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `useChat`                        | The conversation state machine: session bootstrap, lazy conversation creation, optimistic sends, the pending reply bubble, error rollback. |
| `MessageContent`                 | Renders a message's content blocks: markdown replies formatted, visitor text literal, component blocks via a registry.                     |
| `contentToText`                  | Flattens a message to a plain string, for rendering the visitor's own bubbles.                                                             |
| `createMessageComponentRegistry` | Optional. Renders interactive blocks the agent surfaces inline, such as a file upload.                                                     |
| `themeRootProps`                 | Optional. Applies the agent's admin-configured theme to a surface built on Limio design tokens.                                            |

## Write your prompt

Be specific about behaviour, states, and styling, the same as for any vibe-coded component. A worked example, a slide-in help sidebar:

```
Create a Limio component: a slide-in chat sidebar for our help pages,
built on @limio/sdk/ai.

Requirements:
- A "Need help?" tab fixed to the right edge opens the sidebar; a close
  button slides it away again
- Use useChat with autoStart: false and call start() when the sidebar
  first opens, so pages where nobody opens it never create a session
- Render assistant messages with MessageContent (markdown formatted) and
  visitor messages as plain text via contentToText
- Show a typing indicator for the pending reply bubble
- When a send fails, show the error above the composer and put the
  visitor's text back in the input so they can retry
- Read the agent's configured colours from session.presentation?.theme
  (hex values: accentColor, backgroundColor, textColor; see the SDK
  reference for the full ChatTheme shape) and use them for the header,
  send button, and visitor bubbles
- Make the tab label a configurable Page Builder prop
- Follow Tailwind CSS conventions; full-height on mobile
```

Claude inspects existing components in the repo before generating, to match structure and styling conventions. Expect it to declare the configurable props via `limioProps` in the component's `package.json`.

## Review what it generated

The SDK does the heavy lifting, so the review is mostly checking Claude used it instead of reimplementing it:

* Messages come from `useChat`'s `messages` array, greeting included. There should be no hand-rolled `fetch` to `/api/chat/`.
* The pending bubble (`message.pending` is `true`) renders a typing indicator, not empty content.
* Sending is disabled while `status === "sending"`.
* Visitor text renders literally, never through a markdown renderer.
* Any "start over" affordance calls `reset()`, which keeps the session but drops the conversation.

{% hint style="info" %}
Two ways to pick up the agent's theme. `themeRootProps(session.presentation?.theme)` spreads Limio design-token overrides onto your root element, which restyles anything that consumes those tokens; this suits surfaces built on the Limio design system. A component with its own palette should instead read the hex fields off `session.presentation?.theme` directly, as the example prompt does. The [SDK Reference](/ai/limio-agents/sdk-reference.md#chattheme) lists all nine theme fields and the bubble-style presets; [Theming an Agent](/ai/limio-agents/theming.md) covers what each one controls for admins.
{% endhint %}

## Preview in Storybook

`useChat` calls the Chat API, so stories need it mocked:

```
Set up Storybook stories for this component with @limio/sdk/ai mocked:
an empty state, a short conversation, a pending reply, and a send error.
```

This gives you every visual state without a live agent, including the ones that are awkward to reproduce by hand, like the pending bubble and the error banner.

## Test against a real agent

Storybook validates the UI; the conversation needs a real agent. Push the component through your CI/CD pipeline, then add it to a page in a sandbox environment where an agent is published. Pages on your shop domain authenticate with the visitor's Limio session cookie automatically, so there is nothing to configure. Send a message and check:

1. The greeting and replies render formatted.
2. The reply to a real question arrives in the surface, with the typing indicator while it is pending.
3. Component blocks the agent surfaces (a file upload, for example) either render through your registry or are skipped cleanly.

## Iterate

Chat-specific follow-up prompts that work well:

```
Show the agent's suggested questions (session.presentation?.pointers) as
tappable chips before the first visitor message
```

```
Add a "New conversation" button that calls reset()
```

```
Register a renderer for the file_upload component block that requests a
presigned upload with initiateUpload and sends the bytes with
uploadFileToS3
```

## Tips and troubleshooting

* **No greeting appears?** The page's domain may not route to an agent, or the agent has no greeting configured. Domains are matched by a [workflow](/ai/limio-agents/workflows.md), not by the agent itself, so check that a published workflow lists the domain and reaches an agent.
* **Component blocks render nothing?** `MessageContent` skips them when no registry entry matches. Register a renderer, or leave them unhandled deliberately.
* **Theme not applying?** `themeRootProps` only affects styles that consume Limio design tokens. If your component has its own palette, read the hex values from `session.presentation?.theme` directly.
* **401 responses on a non-shop domain?** Cross-origin embeds need `configureChatTransport` with a bearer-token source; same-origin shop pages need nothing. See the [SDK Reference](/ai/limio-agents/sdk-reference.md#configuring-the-transport).

{% hint style="info" %}
We are actively improving this experience. Please reach out to <support@limio.com> if you hit any issues.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.limio.com/ai/limio-agents/vibe-coding-a-chat-surface.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
