Best Practices for Using Agent-Native: Building Agent-First Applications
Agent-Native is an open-source framework that enables you to build agent-first applications where AI agents and user interfaces share the same data, actions, and runtime through reusable TypeScript actions and a unified SQL database.
The BuilderIO/agent-native repository provides a complete architecture for creating collaborative applications where AI agents act as first-class teammates rather than sidecar features. By following these best practices for using Agent-Native, you ensure parity between human-driven UI interactions and agent-driven automation while maintaining type safety and a single source of truth across your entire stack.
Define Work as Reusable Actions
Treat every piece of business logic as a reusable action declared once with a Zod schema and a run function. This pattern guarantees that the same function executes whether called from the UI, the agent, the CLI, or an external client.
In src/actions/send-email.ts, define the action using defineAction from @agent-native/core:
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
import { db, replies } from '@/server/db';
export default defineAction({
schema: z.object({
emailId: z.string(),
body: z.string(),
}),
// The same function runs from the UI, the agent, or the CLI
run: async ({ emailId, body }) => {
await db.insert(replies).values({ emailId, body });
},
});
This approach, demonstrated in the repository's main README (lines 8-18), ensures that your business logic remains the single source of truth across all entry points.
Centralize State in a Single SQL Database
Keep all application state in a single SQL database accessed through Drizzle-backed tables. Both the UI and the agent interact with this state through the same action surface, providing instant, real-time synchronization.
According to the "Everything syncs" section in the README (lines 30-33), this architecture makes collaborative editing trivial and eliminates data consistency issues between the frontend and AI runtime.
Leverage the Built-In Skills System
Skills are plug-in modules that extend the agent runtime with capabilities like visual planning and automated recaps. Install them via the CLI and access them through slash commands in any chat-enabled UI.
Add a skill using the following command:
npx @agent-native/core@latest skills add visual-plan
After installation, type /visual-plan in your interface to generate structured plans with diagrams and file-by-file implementation maps. The skills system is documented in packages/skills/README.md and referenced in the README (lines 30-31), providing out-of-the-box functionality without additional code.
Treat Actions as First-Class API Endpoints
Avoid writing raw REST handlers or custom Nitro routes. Instead, expose all functionality through defineAction and consume them using the generated type-safe helpers useActionQuery and useActionMutation.
From a React component in src/components/SendEmailForm.tsx:
import { useActionMutation } from '@agent-native/core';
import sendEmail from '@/actions/send-email';
export default function SendEmailForm() {
const { mutate, isLoading } = useActionMutation(sendEmail);
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
mutate({
emailId: form.email.value,
body: form.body.value,
});
};
return (
<form onSubmit={onSubmit}>
<input name="email" placeholder="Email ID" required />
<textarea name="body" placeholder="Message" required />
<button type="submit" disabled={isLoading}>Send</button>
</form>
);
}
As specified in the Architecture Contract (AGENTS.md), this pattern keeps your codebase DRY, ensures TypeScript safety, and makes the agent automatically aware of all capabilities.
Follow UI Component Standards
Build all UI components using shadcn/ui primitives and Tabler icons to guarantee visual consistency and accessibility across templates. The AGENTS.md "Frontend And UX" section mandates these standards to ensure that new features integrate seamlessly with existing interfaces.
Maintain Type-Safe Code Quality
Write TypeScript exclusively for all new source files (.ts and .tsx). Run Prettier and linting on every change to maintain the formatting standards defined in the project's .prettierrc and avoid CI failures. This type-first philosophy improves developer ergonomics and catches errors early.
Apply the Four-Area Checklist
When adding new features, verify updates across four critical areas: UI, actions, skills, and application state. This checklist, detailed in the adding-a-feature skill documentation (linked from AGENTS.md), prevents "agent-only" or "UI-only" regressions and keeps the system in lock-step.
Summary
- Define reusable actions with
defineActionto create a single source of truth for business logic accessible by UI, agent, and CLI. - Centralize state in Drizzle-backed SQL tables to enable real-time sync between the interface and AI agent.
- Install skills via
npx @agent-native/core@latest skills addto extend agent capabilities without custom code. - Consume actions through
useActionMutationanduseActionQueryrather than writing raw REST endpoints. - Use shadcn/ui components and Tabler icons for consistent, accessible design.
- Write TypeScript exclusively and enforce Prettier formatting to maintain code quality.
- Apply the four-area checklist (UI, actions, skills, state) for every feature to prevent architectural drift.
Frequently Asked Questions
What makes Agent-Native different from traditional full-stack frameworks?
Agent-Native treats AI agents as first-class citizens rather than add-ons. Unlike traditional frameworks where backend logic and frontend state often diverge, Agent-Native enforces a shared action surface where defineAction creates business logic that both the UI and agent consume simultaneously. This eliminates the need to synchronize separate implementations for human and AI interactions.
How do I share state between the UI and the AI agent?
Agent-Native uses a single SQL database (accessed via Drizzle) that both the UI and agent interact with through the same action layer. When an action updates a record via the run function, both interfaces reflect the change immediately because they query the same underlying tables. This architecture is described in the "Everything syncs" section of the README (lines 30-33).
Can I add custom REST endpoints to an Agent-Native app?
While possible, the framework discourages raw REST handlers in favor of extending the action surface. Before adding a custom Nitro route in packages/frame/src/server.ts, search for an existing action to extend. This preference, documented in the Architecture Contract (AGENTS.md), keeps security checks centralized and ensures the agent remains aware of all capabilities.
What is the recommended way to extend agent capabilities?
Extend capabilities through the skills system rather than modifying core runtime code. Install official skills like visual-plan or visual-recap using the CLI command npx @agent-native/core@latest skills add <skill>. These plug-in modules register automatically with the runtime and expose slash commands in the chat interface, as implemented in packages/skills/src/index.ts.
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 →