一键导入
agent-native-framework
Build agent-native applications with shared actions, SQL-backed state, tools, skills, and UI surfaces that work together.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Build agent-native applications with shared actions, SQL-backed state, tools, skills, and UI surfaces that work together.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
A comprehensive Chinese tutorial system for building AI Agents from zero to enterprise-level deployment, covering LangChain, LangGraph, Coze, Dify, RAG, and MCP.
Use Agent-as-a-Router (ACRouter) to intelligently route coding tasks to optimal models under performance-cost tradeoffs
Use Agent Chief to filter and manage AI agent notifications, alerts, and events with local-first LLM-based attention management
Control iOS, Android, TV, and desktop devices for AI-driven mobile app testing and verification
Install and manage 1,935+ AI agent skills for Claude Code, Cursor, Gemini CLI, Codex, Antigravity, and other coding assistants
Build, deploy, and iterate Claude Managed Agents from idea to production using Claude Code
| name | agent-native-framework |
| description | Build agent-native applications with shared actions, SQL-backed state, tools, skills, and UI surfaces that work together. |
| triggers | ["how do I build an agent-native app","create an agent native application with actions","set up agent-native framework with database","define actions that work with UI and agents","add agent skills to my coding assistant","build agents that act inside real apps","integrate agent runtime with SQL state","create shared actions for agents and UI"] |
Skill by ara.so — AI Agent Skills collection.
Agent-Native is an open-source framework for building robust agents that act inside real apps, not just chat next to them. It provides primitives for product-grade agentic software: shared actions, SQL-backed state, identity, tools, skills, jobs, observability, and UI surfaces.
npx @agent-native/core@latest create my-app
cd my-app
pnpm install
pnpm dev
The create command offers three starting points:
Use flags to skip the prompt:
npx @agent-native/core@latest create my-app --template mail
npx @agent-native/core@latest create my-app --headless
npx @agent-native/core@latest create my-app --standalone
Install visual planning and PR recap skills:
npx @agent-native/core@latest skills add visual-plan
This adds /visual-plan and /visual-recap slash commands to Claude Code, Cursor, Codex, Pi, OpenCode, GitHub Copilot, and similar agents.
Actions are the fundamental building block. Define work once, use it everywhere: UI, agent, HTTP API, MCP, A2A, and CLI.
// actions/reply-to-email.ts
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
import { db } from '~/db';
import { replies } from '~/db/schema';
export default defineAction({
schema: z.object({
emailId: z.string(),
body: z.string(),
}),
run: async ({ emailId, body }) => {
await db.insert(replies).values({ emailId, body });
},
});
From UI:
import { useAction } from '@agent-native/react';
import replyToEmail from '~/actions/reply-to-email';
function ReplyButton({ emailId }: { emailId: string }) {
const { execute, loading } = useAction(replyToEmail);
return (
<button
onClick={() => execute({ emailId, body: 'Thanks for reaching out!' })}
disabled={loading}
>
Send Reply
</button>
);
}
From Agent:
// The agent automatically gets access to all defined actions
// and can call them based on user intent
From CLI:
pnpm agent-native action reply-to-email --emailId "123" --body "Hello"
From HTTP API:
curl -X POST http://localhost:3000/api/actions/reply-to-email \
-H "Content-Type: application/json" \
-d '{"emailId": "123", "body": "Hello"}'
// agent/config.ts
import { defineAgent } from '@agent-native/core';
export default defineAgent({
name: 'my-assistant',
model: 'gpt-4',
systemPrompt: `You are a helpful assistant that helps users manage their emails.
You have access to actions like reply-to-email, archive-email, and search-emails.`,
tools: [
// Actions are automatically exposed as tools
],
memory: {
// SQL-backed conversation memory
enabled: true,
},
});
import { defineAgent, defineTool } from '@agent-native/core';
import { z } from 'zod';
const searchWeb = defineTool({
name: 'search-web',
description: 'Search the web for information',
schema: z.object({
query: z.string(),
}),
execute: async ({ query }) => {
// Integration with search API
const response = await fetch(
`https://api.search.com/search?q=${encodeURIComponent(query)}`,
{
headers: { 'Authorization': `Bearer ${process.env.SEARCH_API_KEY}` }
}
);
return response.json();
},
});
export default defineAgent({
name: 'research-assistant',
model: 'gpt-4-turbo',
tools: [searchWeb],
});
Agent-Native uses Drizzle ORM with any SQL database (PostgreSQL, MySQL, SQLite).
// db/schema.ts
import { pgTable, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core';
export const emails = pgTable('emails', {
id: serial('id').primaryKey(),
subject: text('subject').notNull(),
body: text('body').notNull(),
from: varchar('from', { length: 255 }).notNull(),
to: varchar('to', { length: 255 }).notNull(),
createdAt: timestamp('created_at').defaultNow(),
});
export const replies = pgTable('replies', {
id: serial('id').primaryKey(),
emailId: serial('email_id').references(() => emails.id),
body: text('body').notNull(),
createdAt: timestamp('created_at').defaultNow(),
});
// db/index.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
throw new Error('DATABASE_URL is not set');
}
const client = postgres(connectionString);
export const db = drizzle(client, { schema });
# .env
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
OPENAI_API_KEY=your-key-here
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
import { db } from '~/db';
import { emails } from '~/db/schema';
import { eq } from 'drizzle-orm';
export default defineAction({
name: 'get-email',
schema: z.object({
id: z.string(),
}),
run: async ({ id }) => {
const email = await db
.select()
.from(emails)
.where(eq(emails.id, parseInt(id)))
.limit(1);
return email[0] || null;
},
});
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
import { db } from '~/db';
import { emails } from '~/db/schema';
export default defineAction({
name: 'send-email',
schema: z.object({
to: z.string().email(),
subject: z.string(),
body: z.string(),
}),
run: async ({ to, subject, body }) => {
// Store in database
const [email] = await db
.insert(emails)
.values({ to, subject, body, from: 'me@example.com' })
.returning();
// Send via email service
await fetch('https://api.emailservice.com/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.EMAIL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ to, subject, body }),
});
return email;
},
});
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
export default defineAction({
name: 'process-payment',
schema: z.object({
amount: z.number().positive(),
currency: z.enum(['USD', 'EUR', 'GBP']),
customerId: z.string(),
}),
run: async ({ amount, currency, customerId }) => {
try {
const response = await fetch('https://api.payment.com/charge', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PAYMENT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount, currency, customer: customerId }),
});
if (!response.ok) {
throw new Error(`Payment failed: ${response.statusText}`);
}
return response.json();
} catch (error) {
console.error('Payment error:', error);
throw error;
}
},
});
# Install a specific skill
npx @agent-native/core@latest skills add visual-plan
# List available skills
npx @agent-native/core@latest skills list
# Remove a skill
npx @agent-native/core@latest skills remove visual-plan
After installing visual-plan, use these slash commands in your coding agent:
/visual-plan: Generate a structured plan with diagrams, wireframes, and file-by-file implementation maps before coding/visual-recap: Generate a visual recap of changes with a shareable review link after PR or git diff// skills/custom-skill.ts
import { defineSkill } from '@agent-native/core';
export default defineSkill({
name: 'custom-analyzer',
description: 'Analyzes code patterns and suggests improvements',
commands: [
{
name: 'analyze',
description: 'Analyze current file for patterns',
execute: async (context) => {
const currentFile = context.getCurrentFile();
// Analysis logic here
return {
suggestions: ['Use const instead of let', 'Extract this function'],
};
},
},
],
});
// app/root.tsx
import { AgentProvider } from '@agent-native/react';
import { Outlet } from '@remix-run/react';
export default function Root() {
return (
<AgentProvider>
<Outlet />
</AgentProvider>
);
}
import { useAgent, useAction } from '@agent-native/react';
import sendEmail from '~/actions/send-email';
function EmailComposer() {
const { chat, messages, isLoading } = useAgent();
const { execute: send } = useAction(sendEmail);
const handleSend = async () => {
await send({
to: 'user@example.com',
subject: 'Hello',
body: 'Message body',
});
};
const askAgent = async (prompt: string) => {
await chat(prompt);
};
return (
<div>
<button onClick={handleSend}>Send Email</button>
<button onClick={() => askAgent('Draft a follow-up email')}>
Ask Agent to Draft
</button>
<div>
{messages.map((msg, i) => (
<div key={i}>{msg.content}</div>
))}
</div>
</div>
);
}
import { useRealtimeState } from '@agent-native/react';
import { emails } from '~/db/schema';
function EmailList() {
// Automatically syncs with database and agent changes
const { data: emailList, mutate } = useRealtimeState(emails);
return (
<ul>
{emailList?.map(email => (
<li key={email.id}>{email.subject}</li>
))}
</ul>
);
}
// jobs/process-attachments.ts
import { defineJob } from '@agent-native/core';
import { z } from 'zod';
export default defineJob({
name: 'process-attachments',
schedule: 'every 5 minutes', // or cron: '*/5 * * * *'
schema: z.object({
emailId: z.string(),
}),
run: async ({ emailId }) => {
// Process attachments for email
console.log(`Processing attachments for email ${emailId}`);
},
});
import { defineAction, scheduleJob } from '@agent-native/core';
import { z } from 'zod';
import processAttachments from '~/jobs/process-attachments';
export default defineAction({
name: 'receive-email',
schema: z.object({
emailId: z.string(),
}),
run: async ({ emailId }) => {
// Schedule background job
await scheduleJob(processAttachments, { emailId });
},
});
import { defineAction, log } from '@agent-native/core';
export default defineAction({
name: 'complex-action',
schema: z.object({ data: z.string() }),
run: async ({ data }) => {
log.info('Starting complex action', { data });
try {
// Work here
log.debug('Processing step 1');
log.debug('Processing step 2');
return { success: true };
} catch (error) {
log.error('Action failed', { error, data });
throw error;
}
},
});
import { defineAgent, trace } from '@agent-native/core';
export default defineAgent({
name: 'traced-agent',
onMessage: async (message, context) => {
const span = trace.startSpan('agent-message');
try {
// Agent logic
span.setAttributes({ messageLength: message.length });
return await context.complete(message);
} finally {
span.end();
}
},
});
Agent-Native actions automatically expose as MCP tools:
// Automatically available via MCP server
// No additional configuration needed
import { defineAgent, callAgent } from '@agent-native/core';
export default defineAgent({
name: 'coordinator',
onMessage: async (message, context) => {
// Call another agent
const result = await callAgent('specialist-agent', {
task: 'analyze',
data: message,
});
return `Coordinated result: ${result}`;
},
});
# Production environment variables
DATABASE_URL=postgresql://prod-user:password@prod-host:5432/prod-db
OPENAI_API_KEY=sk-prod-key
NODE_ENV=production
PORT=3000
# Build the application
pnpm build
# Start production server
pnpm start
Agent-Native works with Nitro-compatible hosting providers:
Problem: Agent can't find defined action.
Solution: Ensure action is exported as default and file is in actions/ directory:
// actions/my-action.ts
export default defineAction({ /* ... */ });
Problem: DATABASE_URL is not set error.
Solution: Check .env file exists and is loaded:
# Verify environment variable
echo $DATABASE_URL
# Create .env if missing
cp .env.example .env
Problem: Agent doesn't call actions or respond to prompts.
Solution:
OPENAI_API_KEY or relevant model provider keyProblem: TypeScript errors when using actions.
Solution: Regenerate types after schema changes:
pnpm generate
Problem: UI doesn't reflect agent changes.
Solution: Ensure useRealtimeState is used and WebSocket connection is active:
const { data, connected } = useRealtimeState(table);
console.log('Connected:', connected); // Should be true
import { defineAgent } from '@agent-native/core';
import searchEmails from '~/actions/search-emails';
import replyToEmail from '~/actions/reply-to-email';
export default defineAgent({
name: 'email-assistant',
systemPrompt: `You help manage emails. Follow these steps:
1. Search for relevant emails using search-emails
2. Read the content and understand context
3. Draft appropriate replies using reply-to-email`,
tools: [searchEmails, replyToEmail],
});
// Action modifies state
export const updateDocument = defineAction({
schema: z.object({ id: z.string(), content: z.string() }),
run: async ({ id, content }) => {
return await db.update(documents)
.set({ content })
.where(eq(documents.id, id))
.returning();
},
});
// UI component observes same state
function DocumentEditor({ id }: { id: string }) {
const { data: doc } = useRealtimeState(documents, eq(documents.id, id));
const { execute: update } = useAction(updateDocument);
// Both user edits and agent edits show in real-time
return <Editor value={doc?.content} onChange={(val) => update({ id, content: val })} />;
}
import { defineAction } from '@agent-native/core';
import { z } from 'zod';
export default defineAction({
name: 'delete-email',
schema: z.object({ id: z.string() }),
auth: true, // Requires authentication
run: async ({ id }, context) => {
// Check user owns this email
if (!context.user) {
throw new Error('Unauthorized');
}
const email = await db.query.emails.findFirst({
where: eq(emails.id, id),
});
if (email?.userId !== context.user.id) {
throw new Error('Forbidden');
}
await db.delete(emails).where(eq(emails.id, id));
},
});