---
title: Quickstart
description: Create a new Loom app in one command, or add Loom to an existing Next.js app.
---

## Create a new app

```bash
npx useloom@latest create my-app
```

It asks for a model provider (Anthropic, OpenAI, or Google), creates a Next.js app with one agent, a chat page, and the route that serves it, and installs dependencies. Then:

```bash
cd my-app
cp .env.example .env.local   # add your API key
npm run dev
```

Skip the prompts with `--provider openai --yes`; add `--no-install` or `--no-git` to skip those steps.

## Add Loom to an existing app

The rest of this page sets up the same thing by hand.

### Install

```bash
npm i useloom ai @ai-sdk/react @ai-sdk/anthropic zod
```

Loom does not pick a model provider for you. Install the AI SDK provider you want to use.

### Create an agent

Create a folder under `agents/`. The folder name becomes the agent's name.

```md agents/support/instructions.md
You are a support agent for Acme. Answer questions about orders.
Be brief. If you cannot find an order, say so.
```

```ts agents/support/agent.ts
import { defineAgent } from "useloom";
import { anthropic } from "@ai-sdk/anthropic";

export default defineAgent({
  model: anthropic("claude-sonnet-5-5"),
});
```

### Add a tool

Each file in `tools/` is one tool. The file name is the tool name.

```ts agents/support/tools/lookup-order.ts
import { tool } from "useloom";
import { z } from "zod";

export default tool({
  description: "Look up an order by its id",
  input: z.object({ id: z.string() }),
  run: async ({ id }) => {
    return { id, status: "shipped" };
  },
});
```

### Serve your agents

Wrap your Next.js config with `withLoom`. It turns `agents/` into a registry at `.loom/agents.ts`, keeps it current while `next dev` runs, and writes it before `next build`:

```ts next.config.ts
import { withLoom } from "useloom/next/plugin";

export default withLoom({
  // your Next.js config
});
```

Then add one route that serves every agent:

```ts app/api/agents/[name]/route.ts
import { createRouteHandler } from "useloom/next";
import { agents } from "@/.loom/agents";

export const { GET, POST } = createRouteHandler(agents);
```

Add `.loom/` to your `.gitignore`; it is regenerated every time.

Not using Next.js? Run `npx loom dev` beside your dev server, and `npx loom gen` before your build.

### Chat from the client

```tsx app/support/page.tsx
"use client";
import { useAgent } from "useloom/react";

export default function Support() {
  const { messages, sendMessage, newThread, isLoadingHistory } = useAgent("support");
  // render messages, call sendMessage({ text }) on submit, newThread() to start over
}
```

`useAgent` returns the AI SDK's `useChat` helpers, pointed at `/api/agents/support`, plus:

| | |
| --- | --- |
| `threadId` | The current thread. Remembered per agent in `localStorage`, so a refresh resumes it. |
| `newThread()` | Starts a new, empty thread. |
| `isLoadingHistory` | True while a saved thread loads. |
| `pendingApprovals` | Tool calls waiting for the user. Answer with `approve(id)` or `deny(id, reason)`. See [Approvals](/docs/agents#approvals). |
| `usage` | Token totals for the thread. |

Every assistant message also carries `metadata`: the model, token usage, finish reason, duration, and start time. Tool calls arrive as message parts with their input, output, and state.

Pass `{ threadId }` to choose the thread yourself, or `{ persist: false }` to start fresh on every page load. To keep threads across server restarts, give the agent a [store](/docs/data).
