Building a UI Plugin

UI plugins extend Vertesia Studio with custom React pages. Each plugin is a unified project containing a React UI (frontend) and a Hono tool server (backend for custom tools, skills, and interactions), built and deployed as a single unit.

Prerequisites

  • Node.js 22+ and npm or pnpm
  • Vertesia CLI installed and authenticated (vertesia auth login)

1. Scaffold Your Plugin

npm init @vertesia/plugin@latest

You will be prompted for the plugin name (kebab-case), version, description, and isolation strategy (shadow recommended). The generated project includes everything needed: React UI, Hono tool server, Vite + Rollup build configs, Vercel deployment config, and example tools/skills.

2. Develop Locally

cd my-plugin
npm install
npm run dev

Open https://localhost:5173. You'll see:

  • /app/* -- your plugin UI with hot module replacement
  • /* -- the tool server admin UI (manage tools, skills, interactions)
  • /api -- the tool server API endpoint

HTTPS is required for authentication. The dev server uses a self-signed certificate.

3. Register Your App in Vertesia

Create a manifest.json:

{
  "name": "my-plugin",
  "title": "My Plugin",
  "description": "What this plugin does",
  "publisher": "your-org",
  "visibility": "private",
  "status": "beta"
}

Register and install in one step:

vertesia apps create --install -f manifest.json

This creates the app manifest, installs it in your current project, and grants you access.

Then set the app name in .env.local so the dev server knows which app context to use:

VITE_APP_NAME=my-plugin

Restart npm run dev and navigate to /app/ to see your plugin running with full Vertesia authentication.

4. Deploy to Vercel

Vercel is the easiest way to deploy your plugin — its generous free tier is more than enough for development and small-scale production.

npm i -g vercel
vercel --prod

The template includes a vercel.json and api/index.js adapter that handles routing: static UI files from dist/, API requests through the serverless function.

After deploying, update your app manifest with the production endpoint:

vertesia apps update my-plugin --manifest '{
  "endpoint": "https://my-plugin.vercel.app/api"
}'

The endpoint URL tells Vertesia where to find your plugin's tools, skills, interactions, and UI configuration. It replaces the older ui.src and tool_collections fields.

Important: Disable deployment protection in Vercel project settings for the plugin to be publicly accessible.

Isolation Strategies

The manifest ui.isolation field controls how the plugin CSS interacts with the host app:

  • shadow (default, recommended) -- Shadow DOM fully isolates plugin styles
  • css -- lighter weight, but plugin styles may conflict with the host. Required if using Radix UI portals (modals with inputs)

Using Vertesia UI Components

The @vertesia/ui package provides ready-to-use components. Import from subpaths:

// Core components and hooks
import { Button, Card, Input, Spinner, VModal, VTabs, useFetch, useToast } from '@vertesia/ui/core';

// Router
import { useNavigate, useParams, NavLink, NestedRouterProvider } from '@vertesia/ui/router';

// Session and auth
import { useUserSession } from '@vertesia/ui/session';

// Layout
import { FullHeightLayout } from '@vertesia/ui/layout';

Fetching Data

Use the useFetch hook with the Vertesia client:

import { useFetch, Spinner } from '@vertesia/ui/core';
import { useUserSession } from '@vertesia/ui/session';

function MyPage() {
    const { client } = useUserSession();

    const { data, error } = useFetch(
        () => client.store.collections.list(),
        []
    );

    if (error) return 
Failed to load
; if (!data) return ; return
{data.map(item => ...)}
; }

Using the Vertesia Client

const { client } = useUserSession();

// Collections and objects
const collections = await client.store.collections.list();
await client.store.objects.create(
    { content: file, name: file.name },
    { collection_id: collectionId }
);

// Launch an agent
await client.runs.create({
    interaction: 'app:my_interaction',
    data: { /* payload */ },
    tags: ['my-tag'],
});

Styling

Use Tailwind CSS with Vertesia's semantic color classes:

Next Steps

The generated project includes a comprehensive README with detailed guides for:

  • Creating resources -- tools, skills, interactions, content types, templates
  • Tool server configuration -- registering collections, settings schema, org restrictions
  • Build system -- dual Rollup/Vite architecture, import hooks
  • Debugging with the platform -- Cloudflare tunnel for local testing with real agents
  • Theme customization -- overriding CSS custom properties in index.css

Was this page helpful?