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
httpflag determining whether it runs client-side or on the Nitro server - A
runimplementation 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
-
Define an Action – Export
default defineAction({ … })from a file in theactions/folder, specifying the Zod input schema and run function. -
Vite Plugin Scans – The
action-types-plugin(defined inpackages/core/src/vite/action-types-plugin.ts) scans the source tree, extracts TypeScript signatures, and generates type definitions undernode_modules/.viteso both server and client share identical types. -
Expose via HTTP (Optional) – Actions marked with
http: truebecome reachable at/api/action/<name>; otherwise they remain in-process only. -
Consume in UI – Components import the generated hook wrappers. The hook handles serialization, fetch logic, and caching while preserving type safety.
-
Agent Invocation – The LLM uses the generated JSON schemas to select and invoke actions via the same
runfunction, 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:
-
templates/videos/actions/view-screen.ts– Demonstrates the standard action pattern, including reading navigation state viareadAppStateand returning JSON responses. -
packages/core/src/vite/action-types-plugin.ts– The Vite plugin that scans action directories, generates TypeScript definitions, and wires actions into the runtime at build time. -
packages/core/src/client/use-action-mutation.ts(generated) – Provides theuseActionMutationhook that React components import to interact with server actions. -
packages/core/src/shared/application-state.ts– ExportsreadAppStateandwriteAppState, implementing the SQL-backed shared state layer using Drizzle. -
templates/slides/actions/provider-api-request.ts– Implements the Provider API wrapper that allows agents to call third-party endpoints through controlled action boundaries. -
packages/core/src/index.ts– The public API entry point that re-exportsdefineAction, state utilities, and client hooks.
Summary
- The agent-native API unifies front-end, back-end, and AI agent execution through a single
defineActionabstraction. - Actions use Zod schemas for runtime validation and TypeScript generation.
- The
httpflag 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.
useActionQueryanduseActionMutationprovide 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →