The Angular of Gen AI Applications
Build production-ready AI agents with the best developer experience in the industry.
RunMesh is the first comprehensive, batteries-included framework for building Gen AI applications. Like Angular revolutionized web development with structure and best practices, RunMesh does the same for AI engineering.
Building AI agents today means dealing with:
- ❌ Endless boilerplate code for every project
- ❌ Juggling multiple providers, SDKs, and APIs
- ❌ No type safety, no validation, no standards
- ❌ Poor developer experience and debugging
- ❌ Difficulty testing, deploying, and maintaining
A complete framework with everything you need:
- ✅ Batteries Included: Tools, memory, streaming, structured outputs, observability
- ✅ Multi-Provider: OpenRouter (200+ models), OpenAI, Anthropic, or bring your own
- ✅ Type-Safe: End-to-end TypeScript with Zod validation
- ✅ Framework Agnostic: Works with Next.js, Express, Hono, Cloudflare Workers, Deno
- ✅ Frontend Ready: React hooks, Vue composables (coming soon), Svelte stores (coming soon)
- ✅ Production Ready: Testing utilities, logging, error handling, deployment templates
- ✅ Developer First: Best-in-class DX with CLI scaffolding and hot reload
# Like create-next-app, but for AI agents
npx create-runmesh@latest my-ai-app
cd my-ai-app
npm install
npm run devnpm install @runmesh/agent @runmesh/core @runmesh/tools zod
# or
pnpm add @runmesh/agent @runmesh/core @runmesh/tools zodimport { createAgent } from "@runmesh/agent";
import { createOpenRouterConfig, createFromProvider } from "@runmesh/core";
import { tool, ToolRegistry } from "@runmesh/tools";
import { z } from "zod";
// Use 200+ models via OpenRouter (Claude, GPT, Gemini, Llama...)
const client = createFromProvider(
createOpenRouterConfig(
process.env.OPENROUTER_API_KEY!,
"claude-3.5-sonnet" // or "gpt-4o", "gemini-pro", etc.
)
);
const tools = new ToolRegistry();
tools.register(
tool({
name: "get_weather",
description: "Get current weather for a city",
schema: z.object({
city: z.string().describe("City name")
}),
handler: async ({ city }) => {
// Call your weather API here
return { city, temp: 72, condition: "sunny" };
}
})
);
const agent = createAgent({
name: "weather-assistant",
client,
model: "anthropic/claude-3.5-sonnet",
systemPrompt: "You are a helpful weather assistant.",
tools
});
const result = await agent.run("What's the weather in Paris?");
console.log(result.response.choices[0]?.message?.content);import { useStreamingAgent } from "@runmesh/react";
function ChatInterface() {
const { messages, sendMessage, isStreaming } = useStreamingAgent({
apiUrl: "/api/agent"
});
return (
<div className="chat-container">
{messages.map((msg) => (
<div key={msg.timestamp} className={`message ${msg.role}`}>
<strong>{msg.role}:</strong> {msg.content}
</div>
))}
<ChatInput
onSend={sendMessage}
disabled={isStreaming}
placeholder={isStreaming ? "AI is thinking..." : "Type a message..."}
/>
</div>
);
}// app/api/agent/route.ts
import { createAgent } from "@runmesh/agent";
import { createOpenRouterConfig, createFromProvider } from "@runmesh/core";
const client = createFromProvider(createOpenRouterConfig(process.env.OPENROUTER_API_KEY!));
export async function POST(req: Request) {
const { prompt } = await req.json();
const agent = createAgent({
name: "api-agent",
client,
model: "anthropic/claude-3.5-sonnet",
systemPrompt: "You are a helpful AI assistant."
});
const result = await agent.run(prompt);
return Response.json({
content: result.response.choices[0]?.message?.content
});
}Access 200+ models through one unified API:
// OpenRouter - Access everything (Recommended)
const or = createFromProvider(createOpenRouterConfig(key, "anthropic/claude-3.5-sonnet"));
// OpenAI
const openai = createOpenAI({
apiKey,
defaultModel: "gpt-4o"
});
// Anthropic
const anthropic = createFromProvider(createAnthropicConfig(key, "claude-3-5-sonnet-20241022"));
// Custom endpoint
const custom = createCustomConfig(key, "https://your-api.com/v1", "model-name");Define tools with full TypeScript support:
const tools = new ToolRegistry();
tools.register(
tool({
name: "search_database",
description: "Search the product database",
schema: z.object({
query: z.string(),
limit: z.number().default(10),
filters: z
.object({
category: z.string().optional(),
minPrice: z.number().optional()
})
.optional()
}),
handler: async ({ query, limit, filters }) => {
// All parameters are fully typed!
const results = await db.search(query, { limit, ...filters });
return results;
}
})
);Built-in memory management for conversational agents:
import { InMemoryAdapter } from "@runmesh/memory";
const agent = createAgent({
name: "chatbot",
client,
memory: new InMemoryAdapter(),
systemPrompt: "You remember user preferences and past conversations."
});
// Memory is automatically managed across conversations
await agent.run("My name is Alice");
await agent.run("What's my name?"); // "Your name is Alice"Extract structured data with Zod schemas:
import { generateStructuredOutput } from "@runmesh/core";
const analysisSchema = z.object({
summary: z.string(),
sentiment: z.enum(["positive", "negative", "neutral"]),
topics: z.array(z.string()),
confidence: z.number().min(0).max(1)
});
const result = await generateStructuredOutput({
client,
request: {
messages: [{ role: "user", content: "Analyze this product review: ..." }]
},
schema: analysisSchema,
maxRetries: 3
});
// result.value is fully typed!
const { summary, sentiment, topics, confidence } = result.value;Orchestrate complex workflows with the Planner:
import { Planner } from "@runmesh/agent";
const planner = new Planner(executor);
const result = await planner.execute({
objective: "Research and write a comprehensive report on AI trends",
steps: [
"Research current AI trends and gather data",
"Analyze the data and identify key patterns",
"Write a detailed report with findings",
"Review and refine the report"
],
continueOnError: false,
onStepComplete: (step) => {
console.log(`✅ Completed: ${step.description}`);
},
onStepError: (step, error) => {
console.error(`❌ Failed: ${step.description}`, error);
}
});
console.log(`Success: ${result.success}`);
result.steps.forEach((step) => {
console.log(`${step.id}: ${step.status} - ${step.description}`);
});Real-time streaming for better UX:
const stream = await agent.stream("Write a long story...");
for await (const event of stream) {
if (event.type === "token") {
process.stdout.write(event.content);
} else if (event.type === "tool_call") {
console.log(`\n[Tool: ${event.name}]`);
} else if (event.type === "final") {
console.log("\n\nDone!");
}
}RunMesh is organized as a monorepo with focused packages:
Check out our examples directory for complete, runnable examples:
- Simple Chatbot - Basic conversational agent
- Tool-Using Agent - Agent with custom tools
- Multi-Agent System - Multiple agents working together
- Next.js App - Full-stack chat application
- API Server - REST API with RunMesh
- Structured Extraction - Data extraction example
RunMesh includes comprehensive testing utilities:
import { describe, it, expect } from "vitest";
import { createAgent } from "@runmesh/agent";
import { createMockClient } from "@runmesh/core/testing";
describe("MyAgent", () => {
it("should respond correctly", async () => {
const mockClient = createMockClient({
responses: [{ content: "Hello! How can I help?" }]
});
const agent = createAgent({
name: "test-agent",
client: mockClient,
model: "gpt-4o"
});
const result = await agent.run("Hi");
expect(result.response.choices[0]?.message?.content).toBe("Hello! How can I help?");
});
});RunMesh works everywhere JavaScript runs:
- Vercel - Deploy with one command
- Railway - Container deployment
- Cloudflare Workers - Edge runtime
- AWS Lambda - Serverless
- Docker - Containerized deployment
- Node.js - Traditional server
See our deployment guides for detailed instructions.
We welcome contributions! See CONTRIBUTING.md for guidelines.
git clone https://github.com/iluxu/RunMesh.git
cd RunMesh
pnpm install
pnpm test
pnpm buildRunMesh is licensed under the Business Source License 1.1.
Free for:
- Personal projects
- Internal company use
- Production deployments of your own applications
Commercial license required for:
- Hosting RunMesh as a service
- Selling RunMesh-based products
After 4 years, RunMesh will automatically convert to Apache 2.0.
For commercial licensing, open an issue or contact us.
- Discord - Chat with the community
- GitHub Discussions - Ask questions, share ideas
- Twitter - Follow for updates
- Blog - Tutorials and announcements
RunMesh is built on the shoulders of giants:
Built with ❤️ by the RunMesh Team