# Migrating from v1 to v2

Migrate from v1 to v2 for explicit routing, Hono-native routers, and standard Vite config.

Upgrading from v1 to v2? v2 replaces the old generated entry flow with an explicit `app.ts`, supports Hono-native routers, and moves build config into standard `vite.config.ts`. This guide focuses on the changes the current SDK actually requires and what the migration tool will rewrite for you.

## What's Changed in v2

v2 introduces six fundamental architectural changes:

### 1. Agents are Declarative

**v1**: Agents were auto-discovered from `src/agent/*/agent.ts` files at runtime.

**v2**: Import agents explicitly into `createApp()`. This keeps the registered agents visible in one place and ensures they are included for runtime registration and agent-to-agent calls:

```typescript
// app.ts
import { createApp } from '@agentuity/runtime';
import agents from './src/agent';

export default await createApp({
  agents,
});
```

Type safety for `ctx.invoke()` comes from direct imports. Listing agents in `createApp()` controls what the app registers and bundles.

### 2. No More setup/shutdown Hooks

**v1**: Lifecycle hooks in `createApp()`:

```typescript
createApp({
  setup: async (ctx) => { /* initialize */ },
  shutdown: async (ctx) => { /* cleanup */ }
});
```

**v2**: Use standard patterns:
- **Initialization**: Module-level code (runs when file loads)
- **Cleanup**: `registerShutdownHook()` or Bun process hooks

### 3. Explicit Router for Typed Mounts

**v1**: File-based auto-discovery — routes in `src/api/*.ts` were automatically mounted.

**v2**: If you want an exported router type for `hc<ApiRouter>()`, create a root router in `src/api/index.ts` and pass it to `createApp()`:

```typescript
// app.ts
import { createApp } from '@agentuity/runtime';
import api from './src/api/index';
import agents from './src/agent';

export default await createApp({
  router: { path: '/api', router: api },
  agents,
});
```

Compose route modules into a single exported router type when you want to import that type from a frontend or another app.

### 4. Use a Router Shape That Preserves Types

**v1**: `createRouter()` was a wrapper around Hono:

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

const router = createRouter();
router.get('/hello', async (c) => c.json({ msg: 'hi' }));
```

**v2**: Both `createRouter()` and `new Hono<Env>()` work. The key change is to keep the root router in a chained expression when you want to export its type for Hono RPC:

```typescript
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';

const router = new Hono<Env>()
  .get('/hello', async (c) => c.json({ msg: 'hi' }));
```

> [!WARNING]
> **Chained Methods Required**
> Use chained methods (`.get().post()`) instead of mutating style (`router.get()`). Only chained methods preserve types for `hc<ApiRouter>()`.

### 5. Legacy Transport Helpers Removed

**v1**: Older frontend code often relied on Agentuity-specific transport helpers and generated client types.

**v2**: Replace those legacy client patterns with Hono's native RPC client or your preferred data fetching library. If you're migrating older frontend code, look for imports from `@agentuity/react` that construct API clients or wrap route calls:

### Hono Client

```typescript
import { hc } from 'hono/client';
import type { ApiRouter } from '../api';

const client = hc<ApiRouter>('/api');

// Direct usage
const res = await client.hello.$get();
const data = await res.json();
```
### TanStack Query

```typescript
import { useQuery } from '@tanstack/react-query';
import { hc } from 'hono/client';
import type { ApiRouter } from '../api';

const client = hc<ApiRouter>('/api');

function useHello() {
  return useQuery({
    queryKey: ['hello'],
    queryFn: async () => {
      const res = await client.hello.$get();
      return res.json();
    },
  });
}
```
> [!NOTE]
> **Choose Your Stack**
> v2 doesn't prescribe a data fetching approach. Use whatever works for your app:
> - **TanStack Query** — caching, background updates, optimistic updates
> - **SWR** — stale-while-revalidate pattern
> - **RTK Query** — if you're already using Redux Toolkit
> - **Hono client directly** — simple cases without extra dependencies

### 6. Standard vite.config.ts

**v1**: Vite config lived inside `agentuity.config.ts`:

```typescript
// agentuity.config.ts
export default {
  workbench: { route: '/workbench' },
  // Vite plugins were added here too
};
```

**v2**: Use standard `vite.config.ts` and move runtime settings to `createApp()`:

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()], // Add plugins for your frontend framework
});
```

```typescript
// app.ts
import { createApp } from '@agentuity/runtime';

export default await createApp({
  analytics: true, // or { trackClicks: false, ... }
});
```

> [!WARNING]
> **Add Your Frontend Plugin**
> v2 doesn't include a default Vite plugin. You must add the plugin for your frontend framework:
> - **React**: `@vitejs/plugin-react`
> - **Vue**: `@vitejs/plugin-vue`
> - **Svelte**: `@sveltejs/vite-plugin-svelte`
> - **Solid**: `vite-plugin-solid`

> [!TIP]
> **Why These Changes?**
> These changes make v2 more explicit and predictable:
> - **Type safety**: Hono's RPC client (`hc<ApiRouter>()`) gets full type inference
> - **Control**: You decide what's registered and in what order
> - **Simplicity**: No hidden magic, standard Hono/Bun patterns work everywhere

---

## Usage

```bash
npx @agentuity/migrate [project-dir] [options]
```

Run in your project root (or pass a path). The tool checks that your **git worktree is clean** before touching anything, so you can always `git diff` to review changes or `git checkout .` to roll back.

## Options

| Flag | Description |
|---|---|
| `--yes`, `-y` | Skip interactive confirmation |
| `--dry-run` | Print the migration report without modifying files |
| `--help`, `-h` | Show help |

## What it migrates

### Auto-fixable (fully automated)

| Finding | Action |
|---|---|
| v1-generated files under `src/generated/` | Deleted. Run `agentuity build` afterward so the current v2 build recreates any generated files it still needs |
| `bootstrapRuntimeEnv()` call in `app.ts` | Removed (createApp handles it) |
| v1 `createRouter()` + mutating `.get()/.post()` route files | Rewritten to `new Hono<Env>()` chained style |
| Missing `src/api/index.ts` barrel | Generated from discovered route files |
| Missing `src/agent/index.ts` barrel | Generated from discovered agent files |

### Guided (applied with your review)

| Finding | What happens |
|---|---|
| `setup` in `createApp()` | Migration comment added — move init to module level |
| `shutdown` in `createApp()` | Guidance to move cleanup into `registerShutdownHook()` or Bun process hooks |
| No `router`/`agents` in `createApp()` | Guidance shown — wire up the generated barrels |
| `agentuity.config.ts` has Vite keys | Guidance to create `vite.config.ts` with plugins/define/render |
| `agentuity.config.ts` has runtime settings | Remove — keep them in `createApp()` |
| `agentuity.config.ts` empty | Can be deleted |

### Manual (instructions only, no auto-transform)

| Finding | Guidance |
|---|---|
| Frontend files using removed transport helpers or generated client registry types | Replace with `hc<ApiRouter>()` from `hono/client` or your preferred data fetching library |

---

## Step-by-Step Migration

### Step 1: Run the Migration Tool

```bash
npx @agentuity/migrate
```

This will analyze your project and present a migration report. Use `--dry-run` first to preview changes without modifying files.

### Step 2: Review Auto-fixes

The tool will automatically:
- Delete old v1-generated files under `src/generated/`
- Remove `bootstrapRuntimeEnv()` calls (handled by `createApp()` now)
- Rewrite route files from mutating style to chained Hono style

After the migration finishes, run `agentuity build` so the current v2 build can recreate any generated files it still uses.

**Before (v1 mutating style):**
```typescript
import { createRouter } from '@agentuity/runtime';

const router = createRouter();

router.get('/hello', async (c) => {
  return c.json({ message: 'Hello' });
});

router.post('/echo', async (c) => {
  const body = await c.req.json();
  return c.json(body);
});

export default router;
```

**After (v2 chained style):**
```typescript
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';

const router = new Hono<Env>()
  .get('/hello', async (c) => {
    return c.json({ message: 'Hello' });
  })
  .post('/echo', async (c) => {
    const body = await c.req.json();
    return c.json(body);
  });

export default router;
```

> [!TIP]
> **Enables Hono RPC Client**
> The chained style allows you to use `hc<ApiRouter>()` from `hono/client` for fully typed API calls from your frontend:
>
> ```typescript
> import { hc } from 'hono/client';
> import type { ApiRouter } from './api';
>
> const client = hc<ApiRouter>('/api');
> const res = await client.hello.$get(); // Fully typed!
> ```

### Step 3: Handle Guided Migrations

Review and apply the guided migrations:

#### Setup/Shutdown Lifecycle

> [!NOTE]
> **Use Runtime and Bun Shutdown Hooks**
> v2 no longer expects the old app-level `setup`/`shutdown` flow from v1. Move startup work to modules or agent-level setup, and move cleanup into runtime or Bun shutdown hooks:
> - **Initialization**: Run at module level (executes when the file loads)
> - **Cleanup**: Use `registerShutdownHook()` or Bun's process hooks

**Before (v1):**
```typescript
// app.ts
import { createApp } from '@agentuity/runtime';

export default createApp({
  setup: async (ctx) => {
    // Initialize database, connections, etc.
    ctx.app.db = await connectDB();
  },
  shutdown: async (ctx) => {
    // Cleanup
    await ctx.app.db.close();
  }
});
```

**After (v2):**
```typescript
// db.ts - Initialize at module level
export const db = await connectDB();

// app.ts
import { createApp, registerShutdownHook } from '@agentuity/runtime';
import { db } from './db';

registerShutdownHook(async () => {
  await db.close();
});

export default await createApp({
  // No app-level setup/shutdown hooks
});
```

#### Configuration Consolidation

Move all configuration from `agentuity.config.ts` to either:
- `createApp()` in `app.ts` for runtime config (analytics, cors, compression)
- `vite.config.ts` for build config (plugins, define, render)

**Before (v1):**
```typescript
// agentuity.config.ts
export default {
  workbench: { route: '/workbench' },
  // plugins and other vite config
};
```

**After (v2):**
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  define: { 'process.env': {} }
});

// app.ts
import { createApp } from '@agentuity/runtime';

export default await createApp({
  analytics: true
});
```

### Step 4: Update API Client

If your frontend still uses a v1-style client, remove the old Agentuity transport layer and switch to Hono's RPC client directly:

**After (v2):**
```typescript
import { hc } from 'hono/client';
import type { ApiRouter } from '../api';

const client = hc<ApiRouter>('/api');
const result = await client.hello.$get();
```

### Step 5: Wire Up Barrels

The migration tool generates barrel files:

**`src/api/index.ts`:**
```typescript
import helloRouter from './hello/route';
import echoRouter from './echo/route';
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';

const api = new Hono<Env>()
  .route('/hello', helloRouter)
  .route('/echo', echoRouter);

export default api;
export type ApiRouter = typeof api;
```

**`src/agent/index.ts`:**
```typescript
import helloAgent from './hello/agent';
import echoAgent from './echo/agent';

export default [helloAgent, echoAgent];
```

Wire these into your `app.ts`:

```typescript title="app.ts"
import { createApp } from '@agentuity/runtime';
import api from './src/api/index';
import agents from './src/agent';

export default await createApp({
  router: { path: '/api', router: api },
  agents
});
```

### Step 6: Update Cron Routes

v2 changes the `cron()` signature and introduces platform-managed scheduling.

#### Updated cron() Signature

The 2-argument form `cron(schedule, handler)` is deprecated. Use the 3-argument form with an explicit `auth` option:

**Before (v1):**
```typescript
import { cron } from '@agentuity/runtime';

router.post('/daily-cleanup', cron('0 0 * * *', (c) => {
  c.var.logger.info('Running daily cleanup');
  return { status: 'done' };
}));
```

**After (v2):**
```typescript
import { cron } from '@agentuity/runtime';

router.post('/daily-cleanup', cron('0 0 * * *', { auth: true }, (c) => {
  c.var.logger.info('Running daily cleanup');
  return { status: 'done' };
}));
```

The deprecated form still works but defaults to `auth: false`. Set `auth: true` to require signed requests (recommended for deployed apps). See [Scheduling Cron Jobs](/routes/cron) for the full cron route API.

#### Platform-Managed Schedules

v2 also adds `@agentuity/schedule` for platform-managed scheduling with delivery tracking. See [Schedules](/services/schedules) for the complete API:

```typescript
import { ScheduleClient } from '@agentuity/schedule';

const client = new ScheduleClient();

await client.create({
  name: 'Hourly Sync',
  expression: '0 * * * *',
  destinations: [{ type: 'url', config: { url: 'https://example.com/sync' } }],
});
```

> [!NOTE]
> **Two Scheduling Approaches**
> - **Cron routes** (`cron()` from `@agentuity/runtime`): in-process route handlers that run on a schedule with route services on `c.var.*`
> - **Platform schedules** (`ScheduleClient` from `@agentuity/schedule`): managed by Agentuity with delivery tracking and multi-destination support
>
> These coexist and serve different use cases.

---

## Troubleshooting

#### Issue 1: "Cannot find module '@agentuity/react' client exports"

**Cause**: v2 removed the old transport helpers from `@agentuity/react`.

**Solution**: Replace with `hc()` from `hono/client`:
```typescript
import { hc } from 'hono/client';
import type { ApiRouter } from '../api';

const client = hc<ApiRouter>('/api');
```

---

#### Issue 2: Exporting a Router Type for `hc<...>()`

**Cause**: Hono RPC works best when your root router is composed in a single chained expression and exported from `src/api/index.ts`.

**Solution**: Export a single root router type. Both `createRouter()` and `new Hono<Env>()` work:
```typescript
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';

const router = new Hono<Env>();
```

---

#### Issue 3: "ctx.app is empty" or "ctx.app state not available"

**Cause**: v1 apps often populated shared dependencies through `ctx.app`. New v2 code should prefer module-level dependencies or explicit services instead of relying on that old pattern.

**Solution**: Initialize shared dependencies in modules and import them where needed:
```typescript
// Before: setup() populated ctx.app
// createApp({ setup: async (ctx) => { ctx.app.db = await connectDB(); } })

// After: initialize at module level and import directly
// db.ts
export const db = await connectDB();

// agent handler
import { db } from '../db';
// use db directly instead of ctx.app.db
```

---

### Getting Help

If you encounter issues not covered in this guide:

1. **Check the Documentation**: Visit the [SDK Reference](/reference/sdk-reference) for detailed API docs on agents, routes, storage, and context
2. **Review Examples**: Browse the [Cookbook](/cookbook) for working patterns like chat with history, cron with storage, and webhook handlers
3. **Community Support**: Join our [Discord community](https://discord.gg/agentuity) for help
4. **Report Issues**: Open an issue on [GitHub](https://github.com/agentuity/sdk) if you find bugs