What Is the Agent-Native API? A Unified Interface for UI, Server, and AI Agents

The agent-native API is a type-safe, unified action system that lets front-end components, back-end servers, and AI agents invoke the same operations through a single defineAction abstraction registered with Zod schemas.

The agent-native API (available in the BuilderIO/agent-native repository) eliminates the traditional divide between client-side React hooks and server-side API endpoints. By centralizing application logic into reusable actions, the framework ensures that an LLM-driven agent can execute the exact same code paths as your UI components, maintaining consistency across the entire stack.

Core Concepts of the Agent-Native API

Actions and defineAction

The foundation of the API is the defineAction helper exported from @agent-native/core. An action is a reusable operation that declares:

  • A description for the LLM agent to understand its purpose
  • A Zod schema that validates input arguments at runtime
  • An http flag determining whether it runs client-side or on the Nitro server
  • A run implementation containing the actual business logic

All actions reside in template-specific actions/ folders (e.g., templates/videos/actions/) and are automatically registered through a Vite plugin during development.

Execution Contexts

When http: true is set, the action is exposed at /api/action/<name> and executes on the server. When http: false (or omitted), the action runs in-process, allowing AI agents to invoke logic directly without network overhead.

Application State Helpers

The API provides readAppState and writeAppState utilities (from @agent-native/core/application-state) for managing shared navigation and user settings. These helpers persist data to SQL via Drizzle and are safe to call from any action or React component.

Client-Side Hooks

React components consume actions through useActionQuery and useActionMutation (located in packages/core/src/client/). These hooks wrap fetch calls to provide loading states, error handling, and TypeScript autocompletion without raw HTTP requests.

How the Agent-Native API Works

  1. Define an Action – Export default defineAction({ … }) from a file in the actions/ folder, specifying the Zod input schema and run function.

  2. Vite Plugin Scans – The action-types-plugin (defined in packages/core/src/vite/action-types-plugin.ts) scans the source tree, extracts TypeScript signatures, and generates type definitions under node_modules/.vite so both server and client share identical types.

  3. Expose via HTTP (Optional) – Actions marked with http: true become reachable at /api/action/<name>; otherwise they remain in-process only.

  4. Consume in UI – Components import the generated hook wrappers. The hook handles serialization, fetch logic, and caching while preserving type safety.

  5. Agent Invocation – The LLM uses the generated JSON schemas to select and invoke actions via the same run function, ensuring the AI never bypasses framework validation.

Agent-Native API Code Examples

Defining an Action with Schema Validation

In templates/videos/actions/update-composition.ts, an action updates database records with strict input validation:

import { defineAction } from "@agent-native/core";
import { z } from "zod";

export default defineAction({
  description: "Update a composition’s metadata",
  schema: z.object({
    compositionId: z.string(),
    title: z.string().optional(),
    description: z.string().optional(),
  }),
  http: true,                     // reachable via /api/action/update-composition
  run: async ({ compositionId, title, description }) => {
    // Example pseudo-code that updates the DB (actual DB layer omitted)
    await db.compositions.update(compositionId, { title, description });
    return { success: true };
  },
});

Calling Actions from React Components

Components use useActionMutation to invoke the action with full TypeScript support:

import { useActionMutation } from "@agent-native/core";
import updateComposition from "templates/videos/actions/update-composition";

export function CompositionEditor({ compId }: { compId: string }) {
  const { mutate, isLoading, error } = useActionMutation(updateComposition);

  const save = async (updates: { title?: string; description?: string }) => {
    await mutate({ compositionId: compId, ...updates });
  };

  return (
    <>
      {/* UI elements that call save() */}
      {isLoading && <p>Saving…</p>}
      {error && <p className="error">{error.message}</p>}
    </>
  );
}

Direct Agent Invocation

On the server side, an LLM agent can bypass HTTP and call the action directly:

// In an LLM-driven agent script (server side)
import updateComposition from "templates/videos/actions/update-composition";

await updateComposition.run({
  compositionId: "c123",
  title: "New Title",
});

Managing Shared Application State

Access global navigation or settings from any context using the state helpers:

import { readAppState, writeAppState } from "@agent-native/core/application-state";

export async function getCurrentView() {
  const navigation = await readAppState("navigation");
  return navigation?.view ?? "unknown";
}

Implementation Details and Key Files

The agent-native API surface is constructed from several critical source files in the BuilderIO/agent-native repository:

Summary

  • The agent-native API unifies front-end, back-end, and AI agent execution through a single defineAction abstraction.
  • Actions use Zod schemas for runtime validation and TypeScript generation.
  • The http flag determines whether an action executes on the Nitro server or in-process.
  • Vite plugin generation ensures type safety across the entire stack without manual synchronization.
  • useActionQuery and useActionMutation provide React hooks that eliminate raw fetch calls.
  • Application state helpers (readAppState, writeAppState) offer a typed interface to shared SQL data accessible by both UI and agents.

Frequently Asked Questions

What is the difference between http: true and http: false actions?

When http: true is set in the action definition, the operation is exposed at /api/action/<name> and executes within the Nitro server environment, making it suitable for database mutations or secrets access. When http: false or omitted, the action runs in-process only, allowing AI agents to invoke logic directly without network latency or HTTP overhead.

How does the agent-native API ensure type safety across the stack?

The action-types-plugin (located in packages/core/src/vite/action-types-plugin.ts) scans all actions/ directories during development, extracts TypeScript signatures from the Zod schemas, and generates type definitions in node_modules/.vite. This ensures that React hooks, server routes, and agent scripts all reference identical interfaces, preventing runtime mismatches.

Can the agent-native API integrate with external third-party services?

Yes. The framework includes generic wrapper actions such as provider-api-request and provider-api-docs (found in templates/**/actions/provider-api-*.ts) that allow AI agents to call external APIs through controlled action boundaries. These wrappers handle authentication and rate limiting while exposing a consistent interface to the rest of the application.

Where is application state stored when using readAppState and writeAppState?

Application state is persisted in SQL via Drizzle ORM. The helpers defined in packages/core/src/shared/application-state.ts provide a typed abstraction over the database, ensuring that navigation data, user settings, and other shared state remain consistent whether accessed from a React component in the browser or an LLM agent on the server.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →