Quickstart

Install and run the Aomi chat widget in a Next.js project with a single CLI command.

Prerequisites

  • Next.js 15 app with the App Router
  • Tailwind CSS configured
  • shadcn/ui initialized (npx shadcn init already run, components.json present)

Starting from scratch:

npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
npx shadcn init

Install the Widget

npx shadcn add https://aomi.dev/r/aomi-frame.json

This installs the AomiFrame component, all sub-components, and every dependency in one step.

What Gets Installed

npm packages:

  • @aomi-labs/react -- headless runtime, hooks, API client
  • @assistant-ui/react -- chat primitives from the assistant-ui library

Component files:

your-project/
├── components/
│   ├── aomi-frame.tsx                    ← Main shell (from aomi.dev/r)
│   ├── control-bar/
│   │   ├── index.tsx                     ← ControlBar component
│   │   ├── model-select.tsx              ← Model dropdown
│   │   ├── app-select.tsx                ← App/agent dropdown
│   │   ├── api-key-input.tsx             ← API key dialog
│   │   ├── wallet-connect.tsx            ← Wallet button
│   │   └── network-select.tsx            ← Network dropdown
│   ├── assistant-ui/
│   │   ├── thread.tsx                    ← Chat thread (from aomi.dev/r)
│   │   ├── thread-list.tsx               ← Thread list (from aomi.dev/r)
│   │   ├── threadlist-sidebar.tsx         ← Sidebar wrapper (from aomi.dev/r)
│   │   ├── tool-fallback.tsx             ← Tool display (from aomi.dev/r)
│   │   ├── markdown-text.tsx             ← Markdown renderer (from r.assistant-ui.com)
│   │   ├── tooltip-icon-button.tsx        ← Icon buttons (from r.assistant-ui.com)
│   │   └── attachment.tsx                ← File attachments (from r.assistant-ui.com)
│   ├── ui/
│   │   ├── button.tsx                    ← shadcn primitive
│   │   ├── sidebar.tsx                   ← shadcn primitive
│   │   ├── popover.tsx                   ← shadcn primitive
│   │   └── ...                           ← Other shadcn primitives
│   └── wallet-tx-handler.tsx              ← Wallet transaction handler
├── lib/
│   └── utils.ts                           ← cn() utility
└── package.json                           ← npm deps added

Registry Architecture

Components are pulled from three registries, all resolved automatically by the CLI:

SourceWhatWhy
aomi.dev/rCustomized components (AomiFrame, Thread, ThreadList)Aomi-specific features like wallet integration
r.assistant-ui.comUnchanged upstream components (markdown, tooltips)Maintained by assistant-ui, receives upstream fixes
ui.shadcn.comPrimitives (Button, Sidebar, Dialog)Standard UI building blocks
npx shadcn add https://aomi.dev/r/aomi-frame.json


   aomi.dev/r ──► r.assistant-ui.com
        │                │
        ▼                ▼
   ui.shadcn.com      npm packages

Since components are copied into your project, you own the source code and can edit anything.

Set Environment Variables

Create or update .env.local:

# Required: URL of the Aomi backend
NEXT_PUBLIC_BACKEND_URL=https://api.aomi.dev

If you want the Para-based wallet flow shown in the landing example, also add:

# Required for wallet connect / social auth
NEXT_PUBLIC_PARA_API_KEY=your_para_api_key

# Required for external wallets in the Para modal
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_walletconnect_project_id

If you want wallet connect or social auth, render the widget inside the same Para + wagmi provider tree used in the landing example.

Add AomiFrame to a Page

import { AomiFrame } from "@/components/aomi-frame";

export default function ChatPage() {
  return (
    <div style={{ height: "100vh" }}>
      <AomiFrame
        backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!}
        height="100%"
        width="100%"
      />
    </div>
  );
}

Configure Your API Key

Option A: Via the ControlBar UI

The widget includes a ControlBar with an API key input. Click the key icon, paste your API key, and select your app from the dropdown. The key is stored in localStorage for subsequent visits.

Option B: Programmatically

Set the API key and app in code:

import { AomiFrame } from "@/components/aomi-frame";

export default function ChatPage() {
  return (
    <AomiFrame
      backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!}
      height="100%"
    />
  );
}

Then use the useControl hook in a child component to set state programmatically:

import { useControl } from "@aomi-labs/react";
import { useEffect } from "react";

function ConfigureOnMount() {
  const { setState } = useControl();

  useEffect(() => {
    setState({
      apiKey: "sk-your-api-key",
      app: "mycoindex",
    });
  }, []);

  return null;
}

Run Your App

npm run dev

Open http://localhost:3000. You should see the full chat interface with:

  • A sidebar for thread management
  • A message composer at the bottom
  • A ControlBar with model and app selectors
  • Streaming AI responses when you send a message

When you type a message and send it:

  1. The message appears in the chat thread.
  2. The assistant streams its response in real-time.
  3. Tool calls and their results appear inline.
  4. The composer is ready for the next message once the response completes.

Customizing the Layout

Hide controls you do not need using the compound component API:

<AomiFrame.Root height="100%" backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!}>
  <AomiFrame.Header
    withControl={true}
    controlBarProps={{
      hideWallet: true, // No wallet connect
      hideApiKey: true, // API key set programmatically
    }}
  />
  <AomiFrame.Composer />
</AomiFrame.Root>

Namespace Configuration

For shorter install commands, add a registry namespace to your components.json:

{
  "registries": {
    "aomi": "https://r.aomi.dev"
  }
}

Then install with:

npx shadcn add @aomi/aomi-frame

Updating Components

Re-run the install with the --overwrite flag to pull the latest versions:

npx shadcn add https://aomi.dev/r/aomi-frame.json --overwrite

Review changes before committing:

git diff components/

Next Steps

On this page