diff --git a/content/docs/agents/custom-code-agent/concepts.mdx b/content/docs/agents/custom-code-agent/concepts.mdx
index db084cc26..bf353578a 100644
--- a/content/docs/agents/custom-code-agent/concepts.mdx
+++ b/content/docs/agents/custom-code-agent/concepts.mdx
@@ -128,7 +128,7 @@ The same handler code works on every connected provider; adding a provider does
} href="/agents/custom-code-agent/quickstart" title="Quickstart">
Create an agent, connect Slack, and get a reply in-thread.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Walk through a full support-bot handler file.
diff --git a/content/docs/agents/custom-code-agent/build-your-first-agent.mdx b/content/docs/agents/custom-code-agent/connect-your-first-agent.mdx
similarity index 67%
rename from content/docs/agents/custom-code-agent/build-your-first-agent.mdx
rename to content/docs/agents/custom-code-agent/connect-your-first-agent.mdx
index 92c9b0d8a..f133353c1 100644
--- a/content/docs/agents/custom-code-agent/build-your-first-agent.mdx
+++ b/content/docs/agents/custom-code-agent/connect-your-first-agent.mdx
@@ -1,22 +1,22 @@
---
-title: "Build your first Agent"
-pageTitle: 'Tutorial: Build your first Agent'
-description: 'Build a Pipelinr support agent with handlers, cards, metadata, an LLM, and conversation resolution.'
+title: "Connect your first agent"
+pageTitle: 'Tutorial: Connect your first agent'
+description: 'Build a Pipeliner support agent with handlers, cards, metadata, an LLM, and conversation resolution.'
icon: Sparkles
---
import { Steps, Step } from 'fumadocs-ui/components/steps';
import { Brain, ThumbsUp, Mail, LayoutGrid, Rocket } from 'lucide-react';
-Once you've scaffolded an agent, the next question is usually: *What do I actually put in this file?*
+This is the fastest path from nothing to a working agent. You create the agent in Novu, scaffold a bridge app, and write the handler code that powers a small support bot, all in one sitting.
-This walkthrough builds a small support bot for a fake product called Pipelinr. You add one piece at a time in `support-agent.tsx` until the bot greets users, routes by topic, answers with an LLM, and resolves the thread when the user is done.
+The bot is for a fake product called Pipeliner. You add one piece at a time in `support-agent.tsx` until the bot greets users, routes by topic, answers with an LLM, and resolves the thread when the user is done.
-For API reference, see [Handle events](/agents/custom-code-agent/setup-your-agent/handle-events), [Reply](/agents/custom-code-agent/setup-your-agent/reply), and [Signals](/agents/custom-code-agent/setup-your-agent/signals).
+This page keeps each setup step to the minimum you need to get going. For the full reference on any step, follow the linked pages under [Set up your agent](/agents/custom-code-agent/setup-your-agent/overview).
## What you're building
-In this tutorial, you build a Pipelinr support bot that:
+In this tutorial, you build a Pipeliner support bot that:
- Greets the user and asks whether their issue is a **Billing** question, a **Technical** issue, or **Something else**
- Stores the user's choice and answers follow-up questions with an LLM
@@ -24,6 +24,62 @@ In this tutorial, you build a Pipelinr support bot that:
That flow covers `onMessage`, `onAction`, metadata, LLM replies, and `ctx.resolve()`.
+## Before you start
+
+You need:
+
+- A [Novu account](https://dashboard.novu.co).
+- Node.js 18+ installed.
+- A chat provider you can connect. This tutorial uses Slack.
+
+## Set up the project
+
+These three steps get you from an empty folder to a running agent. Each one links to a more detailed page if you want the full walkthrough.
+
+
+
+
+### Create the agent and connect a provider
+
+In the Novu dashboard, open **Agents** and click **Create agent**. Set the **Identifier** to `support-agent`, since that value must match the agent id you use in code.
+
+On the guided setup page, open **Select provider**, choose **Slack**, and follow the prompts to create and install the Slack app. When it finishes, you get a welcome message from the agent in Slack.
+
+For the full provider flow (Slack tokens, install, permissions), see the [Quickstart](/agents/custom-code-agent/quickstart) and [Create an agent](/agents/custom-code-agent/setup-your-agent/create-an-agent).
+
+
+
+
+### Scaffold the bridge app
+
+The bridge app is the project that receives events from Novu and runs your handler code. Copy the pre-filled command from the agent setup page, or run:
+
+```bash
+npx novu@latest init -t agent \
+ --agent-identifier support-agent \
+ --secret-key \
+ --api-url
+```
+
+Run it in the directory where you want the project. The CLI generates a Next.js app with a starter agent. For details, see [Scaffold your project](/agents/custom-code-agent/setup-your-agent/scaffold-your-project).
+
+
+
+
+### Run it locally
+
+On the agent detail page, set the bridge to **Local**. Then, from the project directory, start the app:
+
+```bash
+npm run dev:novu
+```
+
+This starts your app, opens a dev tunnel, and registers the bridge URL with Novu. When it connects, you get another message from your agent in Slack. Leave this running, it hot-reloads as you edit the handler in the next section.
+
+
+
+
+
## Where the code goes
The scaffold creates a Next.js bridge app. All tutorial code goes in `app/novu/agents/support-agent.tsx`:
@@ -36,18 +92,18 @@ app/
support-agent.tsx # agent handlers you edit in this tutorial
```
-The scaffold also adds `app/api/novu/route.ts`, which exposes your agents over HTTP. You do not need to change that file for this tutorial.
+The scaffold also adds `app/api/novu/route.ts`, which exposes your agents over HTTP. You do not need to change that file for this tutorial. Make sure `index.ts` re-exports your agent so the route picks it up; the scaffold wires this up for the starter agent already.
Everything below happens inside `support-agent.tsx`.
## Build the agent
-Follow the steps below to add handlers, cards, metadata, an LLM, and conversation resolution to `support-agent.tsx`.
+Follow the steps below to add handlers, cards, metadata, an LLM, and conversation resolution to `support-agent.tsx`. For the API reference behind each step, see [Handle events](/agents/custom-code-agent/setup-your-agent/handle-events), [Reply](/agents/custom-code-agent/setup-your-agent/reply), and [Signals](/agents/custom-code-agent/setup-your-agent/signals).
-### Step 1: Define the agent shell
+### Define the agent shell
Start with the bare minimum: an `agent()` call with an id and an `onMessage` handler. The agent id (`support-agent`) must match the identifier you set in the Novu dashboard.
@@ -71,7 +127,7 @@ At this point the agent echoes messages back. In the next step, replace that beh
-### Step 2: Handle the first message
+### Handle the first message
Replace the echo handler with a welcome card. On the first message, the bot introduces itself and asks the user to pick a topic.
@@ -87,7 +143,7 @@ export const supportAgent = agent('support-agent', {
if (isFirstMessage) {
return (
-
+ What can I help you with today?
@@ -112,7 +168,7 @@ For all card components, see [Interactive cards](/agents/custom-code-agent/setup
-### Step 3: Use metadata for context
+### Use metadata for context
When the user clicks a button, `onAction` fires instead of `onMessage`. Add an `onAction` handler that stores the user's topic choice in `ctx.metadata` so the next turn can read it.
@@ -134,7 +190,7 @@ Read it back with `ctx.metadata.get('topic')` on the next message. To alert on-c
-### Step 4: Answer follow-ups with an LLM
+### Answer follow-ups with an LLM
After the welcome card, plug in a model. This example uses the [Vercel AI SDK](https://sdk.vercel.ai/) with OpenAI.
@@ -158,7 +214,7 @@ const topic = ctx.metadata.get('topic') ?? 'unknown';
const { text } = await generateText({
model: openai('gpt-4o-mini'),
- system: `You are a Pipelinr support agent. The user's topic is: ${topic}. Keep answers short and link to docs when relevant.`,
+ system: `You are a Pipeliner support agent. The user's topic is: ${topic}. Keep answers short and link to docs when relevant.`,
messages: ctx.history.map((h) => ({
role: h.role,
content: h.content,
@@ -174,7 +230,7 @@ return text;
-### Step 5: Resolve the conversation
+### Resolve the conversation
When the user confirms the issue is fixed, call `ctx.resolve()`. Add this check inside `onMessage` before the LLM branch:
@@ -193,6 +249,17 @@ The optional summary appears in the dashboard. If the user messages again, the c
+## Try it out
+
+With `npm run dev:novu` still running, message your agent in Slack to walk the full flow:
+
+1. Send any message. The bot replies with the welcome card and three topic buttons.
+2. Click **Billing question**. The bot confirms the topic and asks for details.
+3. Ask a follow-up question. The LLM answers using the stored topic and conversation history.
+4. Reply with **thanks**. The bot resolves the conversation and closes the thread.
+
+Open the [conversation in the dashboard](/agents/conversations) to see the messages, metadata, and the resolution summary recorded for the thread.
+
## Complete agent
The following file combines all five steps:
@@ -211,7 +278,7 @@ export const supportAgent = agent('support-agent', {
if (isFirstMessage) {
return (
-
+ What can I help you with today?
@@ -230,7 +297,7 @@ export const supportAgent = agent('support-agent', {
const topic = ctx.metadata.get('topic') ?? 'unknown';
const { text } = await generateText({
model: openai('gpt-4o-mini'),
- system: `You are a Pipelinr support agent. The user's topic is: ${topic}. Keep answers short and link to docs when relevant.`,
+ system: `You are a Pipeliner support agent. The user's topic is: ${topic}. Keep answers short and link to docs when relevant.`,
messages: ctx.history.map((h) => ({
role: h.role,
content: h.content,
diff --git a/content/docs/agents/custom-code-agent/meta.json b/content/docs/agents/custom-code-agent/meta.json
index 1e458844b..91d4850d0 100644
--- a/content/docs/agents/custom-code-agent/meta.json
+++ b/content/docs/agents/custom-code-agent/meta.json
@@ -4,8 +4,8 @@
"pages": [
"quickstart",
"concepts",
+ "connect-your-first-agent",
"setup-your-agent",
- "build-your-first-agent",
"going-to-production"
]
}
diff --git a/content/docs/agents/custom-code-agent/quickstart.mdx b/content/docs/agents/custom-code-agent/quickstart.mdx
index cef7f8f00..23f3e90a8 100644
--- a/content/docs/agents/custom-code-agent/quickstart.mdx
+++ b/content/docs/agents/custom-code-agent/quickstart.mdx
@@ -137,7 +137,7 @@ Edit files in `app/novu/agents/` to customize behavior. See [Handle events](/age
} href="/agents/custom-code-agent/setup-your-agent/signals" title="Signals">
Metadata, workflow triggers, and conversation resolution.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Full support-bot walkthrough with an LLM.
diff --git a/content/docs/agents/custom-code-agent/setup-your-agent/handle-events.mdx b/content/docs/agents/custom-code-agent/setup-your-agent/handle-events.mdx
index 77697fc15..2ef430e26 100644
--- a/content/docs/agents/custom-code-agent/setup-your-agent/handle-events.mdx
+++ b/content/docs/agents/custom-code-agent/setup-your-agent/handle-events.mdx
@@ -162,7 +162,7 @@ export const myAgent = agent('my-agent', {
} href="/agents/custom-code-agent/setup-your-agent/edit-sent-messages" title="Edit sent messages">
Update a message in place after sending it with `ReplyHandle`.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Walk through a full support-bot handler file.
diff --git a/content/docs/agents/custom-code-agent/setup-your-agent/overview.mdx b/content/docs/agents/custom-code-agent/setup-your-agent/overview.mdx
index ca8983347..b81dbf4fe 100644
--- a/content/docs/agents/custom-code-agent/setup-your-agent/overview.mdx
+++ b/content/docs/agents/custom-code-agent/setup-your-agent/overview.mdx
@@ -48,7 +48,7 @@ For step-by-step inbound processing, see [Mental model](/agents/get-started/ment
} href="/agents/custom-code-agent/setup-your-agent/scaffold-your-project" title="Scaffold your project">
Generate a bridge application with the Novu CLI.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Build a support bot step by step.
} href="/agents/conversations" title="Conversation observability">
diff --git a/content/docs/agents/custom-code-agent/setup-your-agent/reply.mdx b/content/docs/agents/custom-code-agent/setup-your-agent/reply.mdx
index 5c82de725..ad3149208 100644
--- a/content/docs/agents/custom-code-agent/setup-your-agent/reply.mdx
+++ b/content/docs/agents/custom-code-agent/setup-your-agent/reply.mdx
@@ -110,7 +110,7 @@ await ctx.reply(Card({ title: 'Order #1234', children: [
### JSX API
-Configure `tsconfig.json` with `"jsxImportSource": "@novu/framework"`, then return JSX from a handler or pass it to `ctx.reply()`. For a full JSX card example with `Card`, `CardText`, `Actions`, and `Button`, see [Build your first agent](/agents/custom-code-agent/build-your-first-agent).
+Configure `tsconfig.json` with `"jsxImportSource": "@novu/framework"`, then return JSX from a handler or pass it to `ctx.reply()`. For a full JSX card example with `Card`, `CardText`, `Actions`, and `Button`, see [Connect your first agent](/agents/custom-code-agent/connect-your-first-agent).
When a user clicks a button or selects a dropdown value, `onAction` fires with `actionId` and `value`. See [Handle events](/agents/custom-code-agent/setup-your-agent/handle-events#onaction).
@@ -138,7 +138,7 @@ The following table lists the card components you can use in replies:
} href="/agents/custom-code-agent/setup-your-agent/signals" title="Signals">
Metadata, workflow triggers, and conversation resolution.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Walk through a full support-bot handler file.
diff --git a/content/docs/agents/custom-code-agent/setup-your-agent/scaffold-your-project.mdx b/content/docs/agents/custom-code-agent/setup-your-agent/scaffold-your-project.mdx
index 0d067e162..09cb1f296 100644
--- a/content/docs/agents/custom-code-agent/setup-your-agent/scaffold-your-project.mdx
+++ b/content/docs/agents/custom-code-agent/setup-your-agent/scaffold-your-project.mdx
@@ -61,7 +61,7 @@ npx novu@latest dev --port --no-studio
} href="/agents/custom-code-agent/setup-your-agent/handle-events" title="Handle events">
Event handlers and the context object your agent receives on every turn.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Walk through a full support-bot handler file.
} href="/agents/custom-code-agent/going-to-production" title="Going to production">
diff --git a/content/docs/agents/custom-code-agent/setup-your-agent/signals.mdx b/content/docs/agents/custom-code-agent/setup-your-agent/signals.mdx
index a0b074247..177d08ea8 100644
--- a/content/docs/agents/custom-code-agent/setup-your-agent/signals.mdx
+++ b/content/docs/agents/custom-code-agent/setup-your-agent/signals.mdx
@@ -103,7 +103,7 @@ export const myAgent = agent('my-agent', {
} href="/agents/custom-code-agent/setup-your-agent/handle-events" title="Handle events">
Event handlers and the context object your agent receives on every turn.
- } href="/agents/custom-code-agent/build-your-first-agent" title="Build your first agent">
+ } href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent">
Walk through a full support-bot handler file.
\ No newline at end of file
diff --git a/src/middleware.ts b/src/middleware.ts
index 88da1d9a7..94c3e45b2 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -172,6 +172,10 @@ export default async function middleware(request: NextRequest, event: NextFetchE
'/platform/workflow/workflows.mdx': '/platform/workflow',
'/docs/platform/workflow/layouts':
'/platform/workflow/add-notification-content/channels-template-editors#email-layouts',
+
+ // Agents
+ '/agents/custom-code-agent/build-your-first-agent':
+ '/agents/custom-code-agent/connect-your-first-agent',
};
if (pathname in redirectMap) {