# Project Structure

Understand how Agentuity projects are organized

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

> [!TIP]
> **Just Add a Folder**
> Creating a new agent is as simple as adding a folder to `src/agent/` with an `agent.ts` file and registering it in `src/agent/index.ts`.

## 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.

> [!NOTE]
> **Utility Files**
> You can add helper files (like `types.ts`, `helpers.ts`, `utils.ts`) alongside your agents and routes.

## Agents and Routes

Agents and routes are separate concerns in Agentuity:

| Concept | Location | Purpose |
|---------|----------|---------|
| **Agents** | `src/agent/` | Core logic, schemas, validation |
| **Routes** | `src/api/` | HTTP endpoints, streams, WebSockets, and cron handlers |

Agents contain your core logic with schema validation and lifecycle hooks. Routes define HTTP endpoints and handlers for streaming, WebSockets, and cron. This separation keeps concerns clear: agents don't know how they're called, and routes handle the protocol details.

### app.ts

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

```typescript
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

```typescript
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:

```typescript
import chat from './chat/agent';

export default [chat];
```

### src/api/index.ts

Routes import agents directly and call them:

```typescript
import { createRouter } from '@agentuity/runtime';
import chat from '@agent/chat/agent';

const router = createRouter();

router.post('/chat', chat.validator(), async (c) => {
  const data = c.req.valid('json');
  return c.json(await chat.run(data));
});

export type ApiRouter = typeof router;

export default router;
```

`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

| | Agents | Direct Routes (no agent) |
|---|---|---|
| **Location** | `src/agent/` | `src/api/` |
| **Schema validation** | Built-in with `agent.validator()` | Manual |
| **Events & Post-response Hooks** | Yes | No |
| **Storage access** | Full | Full |
| **Best for** | Validated workflows, LLM processing | Health 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`.

```tsx
// 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>;
}
```

> [!NOTE]
> **Deployment Scenarios**
> You can also deploy your frontend elsewhere (e.g., Vercel, Netlify) and call your Agentuity API routes using the Hono `hc()` client with a configured base URL.

## Next Steps

- [App Configuration](/get-started/app-configuration): Configure `app.ts` and `agentuity.json`
- [Creating Agents](/agents/creating-agents): Deep dive into agent creation
- [Routes](/routes): Learn about HTTP and other triggers