Project Structure — Agentuity Documentation

Project Structure

Understand how Agentuity projects are organized

Agentuity projects use explicit wiring: you define agents, routes, and configuration in code.

Directory Layout

my-project/
├── agentuity.json        # Project configuration
├── vite.config.ts        # Build configuration (Vite plugins, entry point)
├── app.ts                # App entry point (wires agents + router)
├── .env                  # Environment variables
├── package.json          # Dependencies
└── src/
    ├── agent/            # Agent code
    │   ├── index.ts      # Agent registry (exports array of agents)
    │   └── chat/
    │       └── agent.ts  # Agent logic
    ├── api/              # HTTP routes
    │   └── index.ts      # Router, imports agents
    └── web/              # Frontend code (scaffolded by default)
        ├── index.html    # HTML entry point
        ├── frontend.tsx  # React entry point
        └── App.tsx       # Main component

Agent names come from the first argument to createAgent(). Each agent has one file: agent.ts with your logic and schema.

Agents and Routes

Agents and routes are separate concerns in Agentuity:

ConceptLocationPurpose
Agentssrc/agent/Core logic, schemas, validation
Routessrc/api/HTTP endpoints, triggers (cron, WebSocket, SSE)

Agents contain your core logic with schema validation and lifecycle hooks. Routes define how agents get invoked (HTTP, cron, webhooks, etc.). This separation keeps concerns clear: agents don't know how they're called, and routes handle all transport.

app.ts

app.ts is the entry point that wires agents and routes together via createApp():

import { createApp } from '@agentuity/runtime';
import agents from './src/agent';
import api from './src/api';
 
export default await createApp({
  router: { path: '/api', router: api },
  agents,
});

agent.ts

import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';
 
const agent = createAgent('chat', {
  schema: {
    input: s.object({ message: s.string() }),
    output: s.object({ response: s.string() }),
  },
  handler: async (ctx, input) => {
    return { response: `Echo: ${input.message}` };
  },
});
 
export default agent;

src/agent/index.ts

The agent registry imports all agents and exports them as an array:

import chat from './chat/agent';
 
export default [chat];

src/api/index.ts

Routes import agents directly and call them:

import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
import chat from '@agent/chat/agent';
 
const api = new Hono<Env>()
  .post('/chat', chat.validator(), async (c) => {
    const data = c.req.valid('json');
    return c.json(await chat.run(data));
  });
 
export type ApiRouter = typeof api;
 
export default api;

chat.validator() validates the request body against the agent's input schema and provides type-safe access via c.req.valid('json').

When to Use Agents vs Direct Routes

AgentsDirect Routes (no agent)
Locationsrc/agent/src/api/
Schema validationBuilt-in with agent.validator()Manual
Events & EvalsYesNo
Storage accessFullFull
Best forValidated workflows, LLM processingHealth checks, webhooks, simple endpoints

Use simple routes (without calling an agent) for lightweight endpoints like health checks. For structured processing with validation, create an agent and call it from your route.

Frontend (src/web/)

Place frontend code in src/web/ to deploy alongside your agents. The CLI bundles and serves it automatically.

React is supported out of the box. Use Hono's hc() client for type-safe API calls. For browser utilities, prefer @agentuity/frontend and @agentuity/auth/react; the older @agentuity/react package remains available as a compatibility layer.

Point hc() at the same /api mount path you configured in app.ts, then import your router type from src/api/index.ts.

// src/web/App.tsx
import { hc } from 'hono/client';
import type { ApiRouter } from '../api';
 
const client = hc<ApiRouter>('/api');
 
function App() {
  const handleClick = async () => {
    const res = await client.chat.$post({ json: { message: 'Hello' } });
    const data = await res.json();
    console.log(data.response);
  };
 
  return <button onClick={handleClick}>Say Hello</button>;
}

Next Steps