@@ -67,6 +68,7 @@ export default async function Page(props: {
Sparkle,
Tab,
Tabs,
+ Tag,
ThemeImage,
TutorialStep,
TypingAnimation,
diff --git a/app/(docs)/layout.tsx b/app/(docs)/layout.tsx
index 5900714e..178d41bc 100644
--- a/app/(docs)/layout.tsx
+++ b/app/(docs)/layout.tsx
@@ -4,6 +4,7 @@ import type { ReactNode } from 'react';
import { baseOptions } from '@/app/layout.config';
import { source } from '@/lib/source';
import AISearchToggle from '../../components/AISearchToggle';
+import { SidebarFooter } from '../../components/SidebarFooter';
export default function Layout({ children }: { children: ReactNode }) {
return (
@@ -20,6 +21,11 @@ export default function Layout({ children }: { children: ReactNode }) {
),
},
}}
+ sidebar={{
+ tabs: false,
+ // banner:
,
+ footer:
+ }}
>
{children}
diff --git a/app/api/sessions/[sessionId]/messages/route.ts b/app/api/sessions/[sessionId]/messages/route.ts
index 523b43d1..3975585a 100644
--- a/app/api/sessions/[sessionId]/messages/route.ts
+++ b/app/api/sessions/[sessionId]/messages/route.ts
@@ -1,6 +1,6 @@
-import { NextRequest, NextResponse } from "next/server";
+import { type NextRequest, NextResponse } from "next/server";
import { getKVValue, setKVValue } from "@/lib/kv-store";
-import {
+import type {
Session,
Message,
StreamingChunk,
@@ -32,7 +32,7 @@ function sanitizeTitle(input: string): string {
// Sentence case
s = sentenceCase(s);
// Trim trailing punctuation noise
- s = s.replace(/[\s\-–—:;,\.]+$/g, '').trim();
+ s = s.replace(/[\s\-–—:;,.]+$/g, '').trim();
// Enforce 60 chars
if (s.length > 60) s = s.slice(0, 60).trim();
return s;
@@ -99,7 +99,7 @@ export async function POST(
content: (m.content || '').slice(0, MAX_CONTENT_LEN),
}));
- const prompt = `Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text`;
+ const prompt = 'Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text';
const agentConfig = getAgentPulseConfig();
const headers: Record
= { 'Content-Type': 'application/json' };
@@ -254,7 +254,7 @@ export async function POST(
// Process streaming response
let accumulatedContent = "";
- let finalTutorialData: TutorialData | undefined = undefined;
+ let finalTutorialData: TutorialData | undefined ;
const transformStream = new TransformStream({
async transform(chunk, controller) {
diff --git a/app/api/sessions/[sessionId]/route.ts b/app/api/sessions/[sessionId]/route.ts
index a3900650..e78f9501 100644
--- a/app/api/sessions/[sessionId]/route.ts
+++ b/app/api/sessions/[sessionId]/route.ts
@@ -1,6 +1,6 @@
-import { NextRequest, NextResponse } from 'next/server';
+import { type NextRequest, NextResponse } from 'next/server';
import { getKVValue, setKVValue, deleteKVValue } from '@/lib/kv-store';
-import { Session, Message, SessionSchema } from '@/app/chat/types';
+import { type Session, type Message, SessionSchema } from '@/app/chat/types';
import { toISOString } from '@/app/chat/utils/dateUtils';
import { config } from '@/lib/config';
import { parseAndValidateJSON, SessionMessageOnlyRequestSchema } from '@/lib/validation/middleware';
diff --git a/app/api/sessions/route.ts b/app/api/sessions/route.ts
index bd6a97f2..0cdb1138 100644
--- a/app/api/sessions/route.ts
+++ b/app/api/sessions/route.ts
@@ -1,6 +1,6 @@
-import { NextRequest, NextResponse } from 'next/server';
+import { type NextRequest, NextResponse } from 'next/server';
import { getKVValue, setKVValue } from '@/lib/kv-store';
-import { Session, Message, SessionSchema } from '@/app/chat/types';
+import { type Session, type Message, SessionSchema } from '@/app/chat/types';
import { toISOString } from '@/app/chat/utils/dateUtils';
import { config } from '@/lib/config';
import { parseAndValidateJSON } from '@/lib/validation/middleware';
diff --git a/app/api/tutorials/[id]/route.ts b/app/api/tutorials/[id]/route.ts
index 434fa476..d71763dc 100644
--- a/app/api/tutorials/[id]/route.ts
+++ b/app/api/tutorials/[id]/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest, NextResponse } from 'next/server';
+import { type NextRequest, NextResponse } from 'next/server';
import { join } from 'path';
import { parseTutorialMDXCached } from '@/lib/tutorial/mdx-parser';
import { TutorialIdParamsSchema } from '@/lib/tutorial/schemas';
@@ -39,7 +39,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
}
});
} catch (error) {
- console.error(`Failed to load tutorial:`, error);
+ console.error('Failed to load tutorial:', error);
return NextResponse.json(
{ success: false, error: 'Tutorial not found' },
{ status: 404 }
diff --git a/app/api/tutorials/[id]/steps/[stepNumber]/route.ts b/app/api/tutorials/[id]/steps/[stepNumber]/route.ts
index d881bf75..5d3553f9 100644
--- a/app/api/tutorials/[id]/steps/[stepNumber]/route.ts
+++ b/app/api/tutorials/[id]/steps/[stepNumber]/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest, NextResponse } from 'next/server';
+import { type NextRequest, NextResponse } from 'next/server';
import { join } from 'path';
import { parseTutorialMDXCached } from '@/lib/tutorial/mdx-parser';
import { StepParamsSchema } from '@/lib/tutorial/schemas';
@@ -49,7 +49,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
}
});
} catch (error) {
- console.error(`Failed to load tutorial step:`, error);
+ console.error('Failed to load tutorial step:', error);
return NextResponse.json(
{ success: false, error: 'Failed to load step' },
{ status: 500 }
diff --git a/app/api/users/tutorial-state/route.ts b/app/api/users/tutorial-state/route.ts
index 70557fa7..9aabfbe2 100644
--- a/app/api/users/tutorial-state/route.ts
+++ b/app/api/users/tutorial-state/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest, NextResponse } from 'next/server';
+import { type NextRequest, NextResponse } from 'next/server';
import { TutorialStateManager } from '@/lib/tutorial/state-manager';
import { setKVValue } from '@/lib/kv-store';
import { config } from '@/lib/config';
diff --git a/app/chat/SessionContext.tsx b/app/chat/SessionContext.tsx
index a4a3b42b..de7a15a3 100644
--- a/app/chat/SessionContext.tsx
+++ b/app/chat/SessionContext.tsx
@@ -1,6 +1,6 @@
'use client';
import { createContext, useContext } from 'react';
-import { Session } from './types';
+import type { Session } from './types';
interface SessionContextType {
sessions: Session[];
diff --git a/app/chat/[sessionId]/page.tsx b/app/chat/[sessionId]/page.tsx
index ef569ef4..28230514 100644
--- a/app/chat/[sessionId]/page.tsx
+++ b/app/chat/[sessionId]/page.tsx
@@ -7,7 +7,7 @@ import "allotment/dist/style.css";
import { v4 as uuidv4 } from 'uuid';
import { ChatMessagesArea } from '../components/ChatMessagesArea';
import { CodeEditor } from '../components/CodeEditor';
-import { Session, Message } from '../types';
+import type { Session, Message } from '../types';
import { useSessions } from '../SessionContext';
import { sessionService } from '../services/sessionService';
import { Skeleton } from '@/components/ui/skeleton';
diff --git a/app/chat/components/ChatInput.tsx b/app/chat/components/ChatInput.tsx
index 0422b2ac..2a0d735f 100644
--- a/app/chat/components/ChatInput.tsx
+++ b/app/chat/components/ChatInput.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useEffect, KeyboardEvent, useState } from 'react';
+import { useEffect, type KeyboardEvent, useState } from 'react';
import { Send } from 'lucide-react';
import { useAutoResize } from '../utils/useAutoResize';
diff --git a/app/chat/components/ChatMessage.tsx b/app/chat/components/ChatMessage.tsx
index 4c340d2d..845290ed 100644
--- a/app/chat/components/ChatMessage.tsx
+++ b/app/chat/components/ChatMessage.tsx
@@ -6,7 +6,7 @@ import { AgentuityLogo } from '@/components/icons/AgentuityLogo';
import { MarkdownRenderer } from './MarkdownRenderer';
import type { TutorialSnippet } from '../types';
import { formatTime } from '../utils/dateUtils';
-import { TutorialData } from '../types';
+import type { TutorialData } from '../types';
function transformMdxWithSnippets(mdx: string, snippets: TutorialSnippet[] = []) {
// Replace each by consuming the appropriate number of snippets
diff --git a/app/chat/components/ChatMessagesArea.tsx b/app/chat/components/ChatMessagesArea.tsx
index e8ebd11c..56bb4a80 100644
--- a/app/chat/components/ChatMessagesArea.tsx
+++ b/app/chat/components/ChatMessagesArea.tsx
@@ -3,7 +3,7 @@
import React, { useRef, useEffect,useState } from 'react';
import { ChatMessageComponent } from './ChatMessage';
import { ChatInput } from './ChatInput';
-import { Session } from '../types';
+import type { Session } from '../types';
export interface ChatMessagesAreaProps {
session: Session
diff --git a/app/chat/components/CodeEditor.tsx b/app/chat/components/CodeEditor.tsx
index f040a422..8dae0552 100644
--- a/app/chat/components/CodeEditor.tsx
+++ b/app/chat/components/CodeEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import type React from 'react';
+import { useState } from 'react';
import { Play, Terminal, Square, Power, Code, X } from 'lucide-react';
enum TabType {
diff --git a/app/chat/components/SessionSidebar.tsx b/app/chat/components/SessionSidebar.tsx
index 6e8b7e7e..f0371448 100644
--- a/app/chat/components/SessionSidebar.tsx
+++ b/app/chat/components/SessionSidebar.tsx
@@ -9,7 +9,7 @@ import {
ChevronRight
} from 'lucide-react';
import { AgentuityLogo } from '@/components/icons/AgentuityLogo';
-import { Session, SessionSidebarProps } from '../types';
+import type { Session, SessionSidebarProps } from '../types';
// Helper function to format relative dates
const formatRelativeDate = (date: Date): string => {
diff --git a/app/chat/components/TutorialFileChip.tsx b/app/chat/components/TutorialFileChip.tsx
index 41833ddd..c6263fec 100644
--- a/app/chat/components/TutorialFileChip.tsx
+++ b/app/chat/components/TutorialFileChip.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { FileText } from 'lucide-react';
-import { CodeFile } from '../types';
+import type { CodeFile } from '../types';
interface TutorialFileChipProps {
codeBlock: CodeFile;
diff --git a/app/chat/layout.tsx b/app/chat/layout.tsx
index e0c5ad29..6b35ddae 100644
--- a/app/chat/layout.tsx
+++ b/app/chat/layout.tsx
@@ -1,7 +1,7 @@
'use client';
import { usePathname, useRouter } from "next/navigation";
-import { Session } from "./types";
+import type { Session } from "./types";
import { sessionService } from "./services/sessionService";
import { SessionSidebar } from "./components/SessionSidebar";
import { SessionSidebarSkeleton } from './components/SessionSidebarSkeleton';
diff --git a/app/chat/services/sessionService.ts b/app/chat/services/sessionService.ts
index 6acfec3c..c458ffa4 100644
--- a/app/chat/services/sessionService.ts
+++ b/app/chat/services/sessionService.ts
@@ -1,4 +1,4 @@
-import { Session, Message, TutorialData } from '../types';
+import type { Session, Message, TutorialData } from '../types';
export interface SessionServiceResponse {
success: boolean;
diff --git a/app/chat/utils/useStreaming.ts b/app/chat/utils/useStreaming.ts
index b4a324cd..739282f9 100644
--- a/app/chat/utils/useStreaming.ts
+++ b/app/chat/utils/useStreaming.ts
@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
-import { Message, TutorialData, StreamingChunk } from '../types';
+import type { Message, TutorialData, StreamingChunk } from '../types';
import { getCurrentTimestamp } from './dateUtils';
// Generate unique IDs
@@ -72,7 +72,7 @@ export function useStreaming({
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let accumulatedContent = '';
- let finalTutorialData: TutorialData | undefined = undefined;
+ let finalTutorialData: TutorialData | undefined ;
if (!reader) {
throw new Error('No response body');
diff --git a/app/global.css b/app/global.css
index 1e0da310..d18e9357 100644
--- a/app/global.css
+++ b/app/global.css
@@ -32,7 +32,7 @@
--color-gray-900: var(--color-zinc-900);
--color-gray-950: var(--color-zinc-950);
- /* Cyan accents - using production's shades for readability */
+ /* Cyan accents */
--color-fd-primary: var(--color-cyan-700);
--color-fd-primary-foreground: var(--color-cyan-50);
--color-fd-ring: var(--color-cyan-500);
@@ -131,3 +131,12 @@ figure > div:nth-child(2) {
article > p {
margin-bottom: 1rem;
}
+
+/* Content links - cyan branding (700 light, 500 dark) */
+.prose a:not([data-card]) {
+ text-decoration-color: var(--color-cyan-700);
+}
+
+.dark .prose a:not([data-card]) {
+ text-decoration-color: var(--color-cyan-500);
+}
diff --git a/app/layout.config.tsx b/app/layout.config.tsx
index b52b7e52..732988aa 100644
--- a/app/layout.config.tsx
+++ b/app/layout.config.tsx
@@ -8,9 +8,9 @@ import { XButton } from '../components/XButton';
*/
export const baseOptions: BaseLayoutProps = {
nav: {
- url: '/Introduction',
+ url: '/Get-Started/what-is-agentuity',
title: (
-
+
- Console
+ App
diff --git a/app/llms-full.txt/route.ts b/app/llms-full.txt/route.ts
index 6648a740..539eedfd 100644
--- a/app/llms-full.txt/route.ts
+++ b/app/llms-full.txt/route.ts
@@ -15,38 +15,33 @@ export async function GET() {
const preamble = `# Agentuity Documentation
## About
-This is the official documentation for Agentuity, a cloud platform designed specifically for building, deploying, and scaling autonomous AI agents. It provides the infrastructure and tools necessary to manage agents built with any framework, such as CrewAI, LangChain, or custom code.
+
+This is the official documentation for Agentuity, a cloud platform designed specifically for building, deploying, and scaling autonomous AI agents.
## Capabilities
+
The documentation covers:
- General cloud and account information
- CLI usage and commands
-- SDK integration (Python, JavaScript, etc.)
+- SDK integration
- Examples, tutorials, and sample implementations
- Troubleshooting and best practices
## Limitations
+
- The documentation primarily focuses on Agentuity services and may not cover all aspects of AI agent development
- Some advanced features may require additional knowledge of AI frameworks
- Examples are provided for common use cases but may need adaptation for specific requirements
-## Preferred Interaction
-When interacting with this documentation:
-- Start with the Introduction section for an overview of Agentuity
-- Refer to specific sections (Cloud, CLI, SDKs, Examples) based on your needs
-- Follow the step-by-step tutorials for practical implementation
-- Check the Troubleshooting section for common issues and solutions
+## Documentation Pages
-## Main Sections
-1. Introduction - Overview of the Agentuity cloud and its features
-2. Cloud - Platform features, account management, and deployment options
-3. CLI (Command Line Interface) - Installation, authentication, project management, environment variables, and other CLI commands
-4. SDKs & Integration - SDKs for various languages and frameworks (CrewAI, LangChain, Python, Node.js)
-5. Examples & Tutorials - Sample projects, step-by-step tutorials, and implementation guides
-6. Troubleshooting - Common issues and solutions\n\n`;
+`;
const scanned = docs.map((doc) => {
- return `file: ${doc.file}\nmeta: ${JSON.stringify(doc.meta, null, 2)}\n${doc.content}`;
+ if (!doc.file.startsWith('Changelog')) {
+ // return `file: ${doc.file}\nmeta: ${JSON.stringify(doc.meta, null, 2)}\n${doc.content}`;
+ return `-----\n### ${doc.meta.title}\nhttps://agentuity.dev/${doc.file.replace('.mdx', '.md')}\n-----\n${doc.content}`;
+ }
});
return new Response(preamble + scanned.join('\n\n'), {
diff --git a/app/llms.txt/route.ts b/app/llms.txt/route.ts
index 78a21052..b057f4df 100644
--- a/app/llms.txt/route.ts
+++ b/app/llms.txt/route.ts
@@ -15,43 +15,36 @@ export async function GET() {
const preamble = `# Agentuity Documentation
## About
-This is the official documentation for Agentuity, a cloud platform designed specifically for building, deploying, and scaling autonomous AI agents. It provides the infrastructure and tools necessary to manage agents built with any framework, such as CrewAI, LangChain, or custom code.
+
+This is the official documentation for Agentuity, a cloud platform designed specifically for building, deploying, and scaling autonomous AI agents.
## Capabilities
+
The documentation covers:
- General cloud and account information
- CLI usage and commands
-- SDK integration (Python, JavaScript, etc.)
+- SDK integration
- Examples, tutorials, and sample implementations
- Troubleshooting and best practices
## Limitations
+
- The documentation primarily focuses on Agentuity services and may not cover all aspects of AI agent development
- Some advanced features may require additional knowledge of AI frameworks
- Examples are provided for common use cases but may need adaptation for specific requirements
-## Preferred Interaction
-When interacting with this documentation:
-- Start with the Introduction section for an overview of Agentuity
-- Refer to specific sections (Cloud, CLI, SDKs, Examples) based on your needs
-- Follow the step-by-step tutorials for practical implementation
-- Check the Troubleshooting section for common issues and solutions
+## Documentation Pages
-## Main Sections
-1. Introduction - Overview of the Agentuity cloud and its features
-2. Cloud - Platform features, account management, and deployment options
-3. CLI (Command Line Interface) - Installation, authentication, project management, environment variables, and other CLI commands
-4. SDKs & Integration - SDKs for various languages and frameworks (CrewAI, LangChain, Python, Node.js)
-5. Examples & Tutorials - Sample projects, step-by-step tutorials, and implementation guides
-6. Troubleshooting - Common issues and solutions\n\n`;
+`;
const scanned = docs.map((doc) => {
if (!doc.file.startsWith('Changelog')) {
- return `file: ${doc.file}\nmeta: ${JSON.stringify(doc.meta, null, 2)}\n${doc.content}`;
+ // return `file: ${doc.file}\nmeta: ${JSON.stringify(doc.meta, null, 2)}\n${doc.content}`;
+ return `[${doc.meta.title}](https://agentuity.dev/${doc.file.replace('.mdx', '.md')})`;
}
});
- return new Response(preamble + scanned.join('\n\n'), {
+ return new Response(preamble + scanned.join('\n'), {
headers: { 'Content-Type': 'text/plain' },
});
} catch (error) {
diff --git a/components/CodeFromFiles.tsx b/components/CodeFromFiles.tsx
index a3f97467..0c5e81e8 100644
--- a/components/CodeFromFiles.tsx
+++ b/components/CodeFromFiles.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { readFile } from 'fs/promises';
import path from 'path';
-import CodeBlock from '@/app/chat/components/CodeBlock';
+import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
export interface CodeFromFilesSnippet {
@@ -25,7 +25,7 @@ function inferLanguageFromExtension(filePath: string): string {
case '.js': return 'js';
case '.jsx': return 'jsx';
case '.json': return 'json';
- case '.py': return 'python';
+ case '.py': return 'py';
case '.sh':
case '.bash': return 'bash';
case '.yml':
@@ -81,7 +81,7 @@ export default async function CodeFromFiles(props: CodeFromFilesProps) {
x.label)}>
{loaded.map((x, idx) => (
-
+
))}
diff --git a/components/CopyPageDropdown.tsx b/components/CopyPageDropdown.tsx
index 4a0bc233..e151b230 100644
--- a/components/CopyPageDropdown.tsx
+++ b/components/CopyPageDropdown.tsx
@@ -141,34 +141,8 @@ export default function CopyPageDropdown({
};
const handleViewMarkdown = async () => {
- const content = await fetchPageContent();
- if (!content) return;
-
- const markdownForLLM = formatMarkdownForLLM(content);
- const blob = new Blob([markdownForLLM], { type: 'text/markdown' });
- const url = URL.createObjectURL(blob);
-
- try {
- const newWindow = window.open(url, '_blank');
- if (!newWindow) {
- const link = document.createElement('a');
- link.href = url;
- link.download = `${content.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.md`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
- } catch (error) {
- console.error('Failed to open markdown view:', error);
- const link = document.createElement('a');
- link.href = url;
- link.download = `${content.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.md`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
-
- setTimeout(() => URL.revokeObjectURL(url), 1000);
+ const mdUrl = `${pathname}.md`;
+ window.open(mdUrl, '_blank');
setIsOpen(false);
};
diff --git a/components/SidebarBanner.tsx b/components/SidebarBanner.tsx
new file mode 100644
index 00000000..affc5b2a
--- /dev/null
+++ b/components/SidebarBanner.tsx
@@ -0,0 +1,5 @@
+'use client';
+
+export function SidebarBanner() {
+ return null;
+}
diff --git a/components/SidebarFooter.tsx b/components/SidebarFooter.tsx
new file mode 100644
index 00000000..ec7f086b
--- /dev/null
+++ b/components/SidebarFooter.tsx
@@ -0,0 +1,7 @@
+'use client';
+
+import { ExternalLink } from "lucide-react";
+
+export function SidebarFooter() {
+ return Looking for the old docs? Click here ;
+}
diff --git a/components/Tag.tsx b/components/Tag.tsx
new file mode 100644
index 00000000..52b99ceb
--- /dev/null
+++ b/components/Tag.tsx
@@ -0,0 +1,16 @@
+import type * as React from 'react';
+
+interface TagProps {
+ children: React.ReactNode;
+ className?: string;
+}
+
+export function Tag({ children, className = '' }: TagProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/components/TutorialStep.tsx b/components/TutorialStep.tsx
index 8256028d..5147e8e1 100644
--- a/components/TutorialStep.tsx
+++ b/components/TutorialStep.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import type React from 'react';
interface TutorialStepProps {
number: number;
diff --git a/components/ui/skeleton.tsx b/components/ui/skeleton.tsx
index 27f9da87..d1395568 100644
--- a/components/ui/skeleton.tsx
+++ b/components/ui/skeleton.tsx
@@ -1,6 +1,6 @@
"use client";
-import * as React from "react";
+import type * as React from "react";
export type SkeletonProps = React.HTMLAttributes;
diff --git a/content/APIs/calling-agents.mdx b/content/APIs/calling-agents.mdx
new file mode 100644
index 00000000..f3312b6d
--- /dev/null
+++ b/content/APIs/calling-agents.mdx
@@ -0,0 +1,288 @@
+---
+title: Calling Agents from Routes
+description: Import and invoke agents from your routes
+---
+
+Routes import agents directly and call them using `agent.run()`. Use `agent.validator()` for type-safe request validation.
+
+## Basic Agent Call
+
+Import an agent and call it in your route:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', async (c) => {
+ const { message } = await c.req.json();
+ const result = await chat.run({ message });
+ return c.json(result);
+});
+
+export default router;
+```
+
+The agent receives validated input (if it has a schema) and returns typed output.
+
+## With Validation
+
+Use `agent.validator()` for type-safe request validation:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chat.validator(), async (c) => {
+ const data = c.req.valid('json'); // Fully typed from agent schema
+ const result = await chat.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+## Multiple Agents
+
+Import and use multiple agents in the same route file:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+import summarizer from '@agent/summarizer';
+import teamMembers from '@agent/team/members';
+
+const router = createRouter();
+
+router.post('/process', async (c) => {
+ const input = await c.req.json();
+
+ // Call different agents
+ const chatResult = await chat.run({ message: input.text });
+ const summary = await summarizer.run({ content: input.text });
+ const members = await teamMembers.run({ teamId: input.teamId });
+
+ return c.json({ chatResult, summary, members });
+});
+
+export default router;
+```
+
+## Parallel Agent Calls
+
+Run multiple agents concurrently when they don't depend on each other:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import sentimentAnalyzer from '@agent/sentiment-analyzer';
+import topicExtractor from '@agent/topic-extractor';
+import summarizer from '@agent/summarizer';
+
+const router = createRouter();
+
+router.post('/analyze', async (c) => {
+ const { content } = await c.req.json();
+
+ // Run agents in parallel
+ const [sentiment, topics, summary] = await Promise.all([
+ sentimentAnalyzer.run({ text: content }),
+ topicExtractor.run({ text: content }),
+ summarizer.run({ content }),
+ ]);
+
+ return c.json({ sentiment, topics, summary });
+});
+
+export default router;
+```
+
+## Background Agent Calls
+
+Use `c.waitUntil()` to run agents after responding to the client:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import webhookProcessor from '@agent/webhook-processor';
+
+const router = createRouter();
+
+router.post('/webhook', async (c) => {
+ const payload = await c.req.json();
+
+ // Acknowledge immediately
+ c.waitUntil(async () => {
+ // Process in background
+ await webhookProcessor.run(payload);
+ c.var.logger.info('Webhook processed');
+ });
+
+ return c.json({ received: true });
+});
+
+export default router;
+```
+
+
+Webhook providers expect fast responses (usually under 3 seconds). Use `c.waitUntil()` to acknowledge receipt immediately and process the payload in the background.
+
+
+## Error Handling
+
+Wrap agent calls in try-catch for graceful error handling:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/safe-chat', async (c) => {
+ const { message } = await c.req.json();
+
+ try {
+ const result = await chat.run({ message });
+ return c.json({ success: true, result });
+ } catch (error) {
+ c.var.logger.error('Agent call failed', {
+ agent: 'chat',
+ error: error instanceof Error ? error.message : String(error),
+ });
+
+ return c.json(
+ { success: false, error: 'Chat processing failed' },
+ 500
+ );
+ }
+});
+
+export default router;
+```
+
+## Full Example: Multi-Endpoint API
+
+Combine authentication, validation, and multiple agent calls:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+import { s } from '@agentuity/schema';
+import chat from '@agent/chat';
+import summarizer from '@agent/summarizer';
+import sentimentAnalyzer from '@agent/sentiment-analyzer';
+import entityExtractor from '@agent/entity-extractor';
+
+const router = createRouter();
+
+// Auth middleware
+const authMiddleware = createMiddleware(async (c, next) => {
+ const apiKey = c.req.header('X-API-Key');
+ if (!apiKey) {
+ return c.json({ error: 'API key required' }, 401);
+ }
+
+ const keyData = await c.var.kv.get('api-keys', apiKey);
+ if (!keyData.exists) {
+ return c.json({ error: 'Invalid API key' }, 401);
+ }
+
+ c.set('userId', keyData.data.userId);
+ await next();
+});
+
+// Apply auth to all routes
+router.use('/*', authMiddleware);
+
+// Chat endpoint - uses chat agent's schema
+router.post('/chat', chat.validator(), async (c) => {
+ const userId = c.var.userId;
+ const data = c.req.valid('json');
+
+ const result = await chat.run({
+ ...data,
+ userId,
+ });
+
+ // Track usage in background
+ c.waitUntil(async () => {
+ await c.var.kv.set('usage', `${userId}:${Date.now()}`, {
+ endpoint: 'chat',
+ tokens: result.tokensUsed,
+ });
+ });
+
+ return c.json(result);
+});
+
+// Summarization endpoint - uses summarizer's schema
+router.post('/summarize', summarizer.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await summarizer.run(data);
+ return c.json(result);
+});
+
+// Multi-agent analysis - uses custom schema
+router.post('/analyze',
+ sentimentAnalyzer.validator({
+ input: s.object({ content: s.string() }),
+ }),
+ async (c) => {
+ const { content } = c.req.valid('json');
+
+ // Run multiple agents in parallel
+ const [sentiment, entities, summary] = await Promise.all([
+ sentimentAnalyzer.run({ text: content }),
+ entityExtractor.run({ text: content }),
+ summarizer.run({ content, maxLength: 100 }),
+ ]);
+
+ return c.json({
+ sentiment: sentiment.score,
+ entities: entities.items,
+ summary: summary.text,
+ });
+ }
+);
+
+export default router;
+```
+
+
+Import the agent you're calling and use `agent.validator()` for its schema, or pass a custom schema with `agent.validator({ input: customSchema })` when the route input differs from the agent's schema.
+
+
+## Type Safety
+
+If your agents have schemas, TypeScript provides full type checking:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+// Agent with schema (src/agent/chat/agent.ts)
+const chatAgent = createAgent('Chat', {
+ schema: {
+ input: s.object({ message: s.string() }),
+ output: s.object({ response: s.string(), tokensUsed: s.number() }),
+ },
+ handler: async (ctx, input) => { ... },
+});
+
+// In route - TypeScript knows the types
+import chat from '@agent/chat';
+
+router.post('/chat', async (c) => {
+ const result = await chat.run({ message: 'Hello' });
+ // result is typed as { response: string, tokensUsed: number }
+
+ return c.json({ text: result.response });
+});
+```
+
+## Next Steps
+
+- [Creating Agents](/Build/Agents/creating-agents): Build agents with schemas and handlers
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Agent-to-agent communication patterns
+- [HTTP Routes](/Build/Routes/http): Complete routing guide
diff --git a/content/APIs/meta.json b/content/APIs/meta.json
new file mode 100644
index 00000000..7621e146
--- /dev/null
+++ b/content/APIs/meta.json
@@ -0,0 +1,7 @@
+{
+ "title": "APIs",
+ "pages": [
+ "when-to-use",
+ "calling-agents"
+ ]
+}
diff --git a/content/APIs/when-to-use.mdx b/content/APIs/when-to-use.mdx
new file mode 100644
index 00000000..5482a9f8
--- /dev/null
+++ b/content/APIs/when-to-use.mdx
@@ -0,0 +1,96 @@
+---
+title: Routes vs Agents
+description: When to use simple routes vs agents for your endpoints
+---
+
+All routes live in `src/api/`. You have two options for handling requests:
+
+1. **Simple routes** - Handle HTTP directly in the route (health checks, CRUD, webhooks)
+2. **Call an agent** - Import an agent for structured processing with validation
+
+## Quick Decision Guide
+
+| Handle directly in route | Create an agent |
+|--------------------------|-----------------|
+| Health checks, status endpoints | LLM-powered processing |
+| Simple CRUD operations | Schema-validated input/output |
+| Webhook signature verification | Evaluations or lifecycle events |
+| Static responses | Multi-step workflows |
+
+## Simple Route Example
+
+A health endpoint doesn't need an agent:
+
+```typescript
+// src/api/index.ts
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/health', async (c) => {
+ const dbHealthy = await checkDatabase();
+ return c.json({ status: dbHealthy ? 'healthy' : 'degraded' });
+});
+
+export default router;
+```
+
+## Calling an Agent
+
+For complex logic, create an agent and call it from your route:
+
+```typescript
+// src/api/index.ts
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chat.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await chat.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+The agent lives in `src/agent/chat/agent.ts` with its schema, handler, and optional evals.
+
+## When Agents Add Value
+
+Agents provide:
+- **Schema validation** with `agent.validator()` middleware
+- **Evaluations** to measure quality
+- **Lifecycle events** for monitoring
+- **Type safety** for agent-to-agent calls
+
+## Webhook Pattern
+
+Webhooks verify signatures in the route, then hand off to an agent:
+
+```typescript
+import paymentProcessor from '@agent/payment-processor';
+
+router.post('/webhooks/stripe', async (c) => {
+ const signature = c.req.header('stripe-signature');
+ const rawBody = await c.req.text();
+
+ if (!verifyStripeSignature(rawBody, signature)) {
+ return c.json({ error: 'Invalid signature' }, 401);
+ }
+
+ // Respond fast, process in background
+ c.waitUntil(async () => {
+ await paymentProcessor.run(JSON.parse(rawBody));
+ });
+
+ return c.json({ received: true });
+});
+```
+
+## Next Steps
+
+- [HTTP Routes](/Build/Routes/http): Complete routing guide
+- [Adding Middleware](/Build/Routes/middleware): Authentication patterns
+- [Creating Agents](/Build/Agents/creating-agents): When you need schemas and evals
diff --git a/content/Agents/ai-gateway.mdx b/content/Agents/ai-gateway.mdx
new file mode 100644
index 00000000..46a9e0d2
--- /dev/null
+++ b/content/Agents/ai-gateway.mdx
@@ -0,0 +1,177 @@
+---
+title: Using the AI Gateway
+description: Automatic LLM routing with observability and cost tracking
+---
+
+Agentuity's AI Gateway routes LLM requests through a managed infrastructure, giving you unified observability and cost tracking across all model providers.
+
+## How It Works
+
+When you make LLM requests from your agents, they're *automatically* routed through the AI Gateway:
+
+```
+Your Agent → AI Gateway → Provider API (OpenAI, Anthropic, etc.)
+```
+
+The AI Gateway provides:
+
+- **Consolidated billing** across all LLM providers
+- **Automatic observability** with token tracking and latency metrics
+- **Request logging** visible in the Agentuity console
+- **No configuration required** when using your SDK key
+
+## Using the AI Gateway
+
+The AI Gateway works automatically—whether you use the Vercel AI SDK, provider SDKs directly (Anthropic, OpenAI), or frameworks like Mastra and LangGraph.
+
+### With the Vercel AI SDK
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('TextGenerator', {
+ schema: {
+ input: s.object({ prompt: s.string() }),
+ output: s.object({ response: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Requests route through AI Gateway automatically
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: input.prompt,
+ });
+
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+### Multiple Providers
+
+You can easily compare responses from different providers by swapping out the `model` parameter:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { openai } from '@ai-sdk/openai';
+import { google } from '@ai-sdk/google';
+import { generateText } from 'ai';
+
+const router = createRouter();
+
+router.post('/compare', async (c) => {
+ const prompt = await c.req.text();
+
+ // Both providers route through AI Gateway automatically
+ const [resultOpenAI, resultGoogle] = await Promise.all([
+ generateText({
+ model: openai('gpt-5-mini'),
+ prompt,
+ }),
+ generateText({
+ model: google('gemini-2.5-flash'),
+ prompt,
+ }),
+ ]);
+
+ return c.json({
+ openai: resultOpenAI.text,
+ google: resultGoogle.text,
+ });
+});
+
+export default router;
+```
+
+### With Provider SDKs Directly
+
+You can also use provider SDKs directly. The AI Gateway routes these requests automatically:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import Anthropic from '@anthropic-ai/sdk';
+import { s } from '@agentuity/schema';
+
+const client = new Anthropic();
+
+const agent = createAgent('AnthropicChat', {
+ schema: {
+ input: s.object({ prompt: s.string() }),
+ output: s.object({ response: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ const result = await client.messages.create({
+ model: 'claude-sonnet-4-5',
+ max_tokens: 1024,
+ messages: [{ role: 'user', content: input.prompt }],
+ });
+
+ const text = result.content[0]?.type === 'text'
+ ? result.content[0].text
+ : '';
+
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+## Supported Providers
+
+The following are some of the providers available through the AI Gateway:
+
+| Provider | Package | Example Models |
+|----------|---------|----------------|
+| OpenAI | `@ai-sdk/openai` | `gpt-5-mini`, `gpt-5` |
+| Anthropic | `@ai-sdk/anthropic` | `claude-sonnet-4-5`, `claude-haiku-4-5` |
+| Google | `@ai-sdk/google` | `gemini-2.5-pro`, `gemini-2.5-flash` |
+| xAI | `@ai-sdk/xai` | `grok-3`, `grok-3-mini` |
+| DeepSeek | `@ai-sdk/deepseek` | `deepseek-chat`, `deepseek-reasoner` |
+| Groq | `@ai-sdk/groq` | `llama-3.3-70b-versatile`, `llama-3.1-8b-instant`, `openai/gpt-oss-120b`, `groq/compound` |
+| Mistral | `@ai-sdk/mistral` | `mistral-large`, `mistral-small` |
+
+### Provider Imports
+
+```typescript
+import { openai } from '@ai-sdk/openai';
+import { anthropic } from '@ai-sdk/anthropic';
+import { google } from '@ai-sdk/google';
+import { xai } from '@ai-sdk/xai';
+import { deepseek } from '@ai-sdk/deepseek';
+import { groq } from '@ai-sdk/groq';
+import { mistral } from '@ai-sdk/mistral';
+```
+
+## BYO API Keys
+
+You can bypass the AI Gateway and use your own API keys, by updating your `.env` file:
+
+```bash
+OPENAI_API_KEY=sk-...
+ANTHROPIC_API_KEY=sk-ant-...
+GOOGLE_GENERATIVE_AI_API_KEY=...
+```
+
+When these variables are set, requests go directly to the provider instead of through the AI Gateway.
+
+## Gateway vs BYO Keys
+
+| Aspect | AI Gateway | BYO API Keys |
+|--------|------------|--------------|
+| **Setup** | Just SDK key | Manage per-provider keys |
+| **Cost tracking** | Automatic in console | Manual |
+| **Observability** | Built-in token/latency metrics | Must configure separately |
+| **Rate limits** | Shared pool | Your own limits |
+
+We recommend using the AI Gateway for most projects.
+
+## Next Steps
+
+- [Using the AI SDK](/Build/Agents/ai-sdk-integration): Structured output, tool calling, and multi-turn conversations
+- [Returning Streaming Responses](/Build/Agents/streaming-responses): Real-time chat UIs and progress indicators
+- [Logging](/Build/Observability/logging): Debug requests and track LLM performance
diff --git a/content/Agents/ai-sdk-integration.mdx b/content/Agents/ai-sdk-integration.mdx
new file mode 100644
index 00000000..3416f918
--- /dev/null
+++ b/content/Agents/ai-sdk-integration.mdx
@@ -0,0 +1,245 @@
+---
+title: Using the AI SDK
+description: Generate text, structured data, and streams with the Vercel AI SDK
+---
+
+The [Vercel AI SDK](https://ai-sdk.dev) provides a consistent API for LLM interactions with built-in streaming, structured output, and tool calling.
+
+Agentuity works with any approach—you can also use provider SDKs directly (Anthropic, OpenAI), or frameworks like Mastra and LangGraph. See [Using the AI Gateway](/Build/Agents/ai-gateway) for examples with different libraries.
+
+## Installation
+
+Install the AI SDK and your preferred provider:
+
+```bash
+bun add ai @ai-sdk/openai
+```
+
+Or with multiple providers:
+
+```bash
+bun add ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google
+```
+
+## Generating Text
+
+Use `generateText` for simple completions:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const agent = createAgent('TextGenerator', {
+ schema: {
+ input: z.object({ prompt: z.string() }),
+ output: z.object({ response: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: input.prompt,
+ });
+
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+### With System Prompt
+
+Add context with a system message:
+
+```typescript
+const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ system: 'You are a concise technical assistant. Keep responses under 100 words.',
+ prompt: input.prompt,
+});
+```
+
+### With Message History
+
+Pass conversation history for multi-turn interactions:
+
+```typescript
+const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ messages: [
+ { role: 'system', content: 'You are a helpful assistant.' },
+ { role: 'user', content: 'What is TypeScript?' },
+ { role: 'assistant', content: 'TypeScript is a typed superset of JavaScript.' },
+ { role: 'user', content: input.followUp },
+ ],
+});
+```
+
+## Generating Structured Data
+
+Use `generateObject` to get validated, typed responses:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const SentimentSchema = z.object({
+ sentiment: z.enum(['positive', 'negative', 'neutral']),
+ confidence: z.number().min(0).max(1),
+ keywords: z.array(z.string()),
+});
+
+const agent = createAgent('SentimentAnalyzer', {
+ schema: {
+ input: z.object({ text: z.string() }),
+ output: SentimentSchema,
+ },
+ handler: async (ctx, input) => {
+ const { object } = await generateObject({
+ model: openai('gpt-5-mini'),
+ schema: SentimentSchema,
+ prompt: `Analyze the sentiment of: "${input.text}"`,
+ });
+
+ // object is fully typed as { sentiment, confidence, keywords }
+ return object;
+ },
+});
+
+export default agent;
+```
+
+
+Define your schema once and reuse it for both `generateObject` and your agent's output schema. This keeps types consistent throughout your codebase.
+
+
+### Using `.describe()` for Field Hints
+
+Add `.describe()` to schema fields to guide the model on format and content:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const EventSchema = z.object({
+ title: z.string().describe('Event title, e.g. "Team standup"'),
+ date: z.string().describe('ISO 8601 date: YYYY-MM-DD'),
+ startTime: z.string().describe('24-hour format: HH:MM'),
+ duration: z.number().describe('Duration in minutes'),
+ attendees: z.array(z.string()).describe('List of attendee names'),
+});
+
+const agent = createAgent('EventExtractor', {
+ schema: {
+ input: z.object({ text: z.string() }),
+ output: EventSchema,
+ },
+ handler: async (ctx, input) => {
+ const { object } = await generateObject({
+ model: openai('gpt-5-mini'),
+ schema: EventSchema,
+ prompt: `Extract event details from: "${input.text}"`,
+ });
+
+ return object;
+ },
+});
+
+export default agent;
+```
+
+The `.describe()` hints improve output consistency, especially for dates, times, and formatted strings.
+
+## Generating Streams
+
+Use `streamText` for real-time responses:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const agent = createAgent('StreamingChat', {
+ schema: {
+ input: z.object({ prompt: z.string() }),
+ stream: true,
+ },
+ handler: async (ctx, input) => {
+ const { textStream } = streamText({
+ model: openai('gpt-5-mini'),
+ prompt: input.prompt,
+ });
+
+ return textStream;
+ },
+});
+
+export default agent;
+```
+
+For detailed streaming patterns, see [Streaming Responses](/Build/Agents/streaming-responses).
+
+## Provider Configuration
+
+### Switching Providers
+
+Change providers by swapping the import and model:
+
+```typescript
+// OpenAI
+import { openai } from '@ai-sdk/openai';
+const model = openai('gpt-5-mini');
+
+// Anthropic
+import { anthropic } from '@ai-sdk/anthropic';
+const model = anthropic('claude-sonnet-4-5');
+
+// Google
+import { google } from '@ai-sdk/google';
+const model = google('gemini-2.5-flash');
+
+// Groq (fast inference)
+import { groq } from '@ai-sdk/groq';
+const model = groq('llama-3.3-70b-versatile');
+```
+
+## Error Handling
+
+Wrap LLM calls in try-catch to handle errors gracefully:
+
+```typescript
+handler: async (ctx, input) => {
+ try {
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: input.prompt,
+ });
+
+ return { response: text };
+ } catch (error) {
+ ctx.logger.error('LLM request failed', { error });
+
+ // Return fallback response
+ return { response: 'I encountered an error processing your request.' };
+ }
+}
+```
+
+## Best Practices
+
+- **Define output schemas** with [Zod](https://zod.dev), [Valibot](https://valibot.dev), or [ArkType](https://arktype.io) for type safety and validation
+- **Add system prompts** to guide model behavior consistently
+- **Handle errors gracefully** with fallback responses
+
+## Next Steps
+
+- [Using the AI Gateway](/Build/Agents/ai-gateway): Observability, cost tracking, and provider switching
+- [Returning Streaming Responses](/Build/Agents/streaming-responses): Chat UIs and long-form content generation
+- [Evaluations](/Build/Agents/evaluations): Quality checks and output validation
diff --git a/content/Agents/calling-other-agents.mdx b/content/Agents/calling-other-agents.mdx
new file mode 100644
index 00000000..860168e9
--- /dev/null
+++ b/content/Agents/calling-other-agents.mdx
@@ -0,0 +1,599 @@
+---
+title: Calling Other Agents
+description: Build multi-agent systems with type-safe agent-to-agent communication
+---
+
+Break complex tasks into focused, reusable agents that communicate with type safety. Instead of building one large agent, create specialized agents that each handle a single responsibility.
+
+## Basic Usage
+
+Import and call other agents directly:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import enrichmentAgent from '@agent/enrichment';
+
+const coordinator = createAgent('Coordinator', {
+ schema: {
+ input: s.object({ text: s.string() }),
+ output: s.object({ result: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Call another agent by importing it
+ const enriched = await enrichmentAgent.run({
+ text: input.text,
+ });
+
+ return { result: enriched.enrichedText };
+ },
+});
+
+export default coordinator;
+```
+
+When both agents have schemas, TypeScript validates the input and infers the output type automatically.
+
+
+Define schemas on all agents to enable full type inference. TypeScript will validate that inputs match expected types and provide autocomplete for outputs.
+
+
+## Communication Patterns
+
+### Sequential Execution
+
+Process data through a series of agents where each step depends on the previous result:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import validatorAgent from '@agent/validator';
+import enrichmentAgent from '@agent/enrichment';
+import analysisAgent from '@agent/analysis';
+
+const pipeline = createAgent('Pipeline', {
+ schema: {
+ input: s.object({ rawData: s.string() }),
+ output: s.object({ processed: s.any() }),
+ },
+ handler: async (ctx, input) => {
+ // Each step depends on the previous result
+ const validated = await validatorAgent.run({
+ data: input.rawData,
+ });
+
+ const enriched = await enrichmentAgent.run({
+ data: validated.cleanData,
+ });
+
+ const analyzed = await analysisAgent.run({
+ data: enriched.enrichedData,
+ });
+
+ return { processed: analyzed };
+ },
+});
+
+export default pipeline;
+```
+
+Errors propagate automatically. If `validatorAgent` throws, subsequent agents never execute.
+
+### Parallel Execution
+
+Run multiple agents simultaneously when their operations are independent:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import webSearchAgent from '@agent/web-search';
+import databaseAgent from '@agent/database';
+import vectorSearchAgent from '@agent/vector-search';
+
+const searchAgent = createAgent('Search', {
+ schema: {
+ input: s.object({ query: s.string() }),
+ output: s.object({ results: s.array(s.any()) }),
+ },
+ handler: async (ctx, input) => {
+ // Execute all searches in parallel
+ const [webResults, dbResults, vectorResults] = await Promise.all([
+ webSearchAgent.run({ query: input.query }),
+ databaseAgent.run({ query: input.query }),
+ vectorSearchAgent.run({ query: input.query }),
+ ]);
+
+ return {
+ results: [...webResults.items, ...dbResults.items, ...vectorResults.items],
+ };
+ },
+});
+
+export default searchAgent;
+```
+
+If each agent takes 1 second, parallel execution completes in 1 second instead of 3.
+
+### Background Execution
+
+Use `ctx.waitUntil()` for fire-and-forget operations that continue after returning a response:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import analyticsAgent from '@agent/analytics';
+
+const processor = createAgent('Processor', {
+ schema: {
+ input: s.object({ data: s.any() }),
+ output: s.object({ status: s.string(), id: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ const id = crypto.randomUUID();
+
+ // Start background processing
+ ctx.waitUntil(async () => {
+ await analyticsAgent.run({
+ event: 'processed',
+ data: input.data,
+ });
+ ctx.logger.info('Background processing completed', { id });
+ });
+
+ // Return immediately
+ return { status: 'accepted', id };
+ },
+});
+
+export default processor;
+```
+
+
+Use `ctx.waitUntil()` for analytics, logging, notifications, or any operation where the caller doesn't need the result.
+
+
+### Conditional Routing
+
+Use an LLM to classify intent and route to the appropriate agent:
+
+```typescript
+import supportAgent from '@agent/support';
+import salesAgent from '@agent/sales';
+import technicalAgent from '@agent/technical';
+
+handler: async (ctx, input) => {
+ // Classify with a fast model, using Groq (via AI Gateway)
+ const { object: intent } = await generateObject({
+ model: groq('llama-3.3-70b'),
+ schema: z.object({
+ agentType: z.enum(['support', 'sales', 'technical']),
+ }),
+ prompt: input.message,
+ });
+
+ // Route based on classification
+ switch (intent.agentType) {
+ case 'support':
+ return supportAgent.run(input);
+ case 'sales':
+ return salesAgent.run(input);
+ case 'technical':
+ return technicalAgent.run(input);
+ }
+}
+```
+
+See [Full Example](#full-example) below for a complete implementation with error handling and logging.
+
+### Orchestrator Pattern
+
+An orchestrator is a coordinator agent that delegates work to specialized agents and combines their results. This pattern is useful for:
+
+- Multi-step content pipelines (generate → evaluate → refine)
+- Parallel data gathering from multiple sources
+- Workflows requiring different expertise (writer + reviewer + formatter)
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import writerAgent from '@agent/writer';
+import evaluatorAgent from '@agent/evaluator';
+
+const orchestrator = createAgent('Orchestrator', {
+ schema: {
+ input: s.object({ topic: s.string() }),
+ output: s.object({ content: s.string(), score: s.number() }),
+ },
+ handler: async (ctx, input) => {
+ // Step 1: Generate content
+ const draft = await writerAgent.run({ prompt: input.topic });
+
+ // Step 2: Evaluate quality
+ const evaluation = await evaluatorAgent.run({
+ content: draft.text,
+ });
+
+ // Step 3: Return combined result
+ return { content: draft.text, score: evaluation.score };
+ },
+});
+
+export default orchestrator;
+```
+
+
+The orchestrator pattern is common in AI workflows where you want to separate concerns (e.g., generation, evaluation, formatting) into focused agents.
+
+
+## Public Agents
+
+
+Agent imports only work within the same project. To call agents in other projects or organizations, use `fetch()` with the agent's public URL.
+
+
+Call public agents using standard HTTP:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('External Caller', {
+ schema: {
+ input: s.object({ query: s.string() }),
+ output: s.object({ result: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ try {
+ const response = await fetch(
+ 'https://agentuity.ai/api/agent-id-here',
+ {
+ method: 'POST',
+ body: JSON.stringify({ query: input.query }),
+ headers: { 'Content-Type': 'application/json' },
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`Public agent returned ${response.status}`);
+ }
+
+ const data = await response.json();
+ return { result: data.response };
+ } catch (error) {
+ ctx.logger.error('Public agent call failed', { error });
+ throw error;
+ }
+ },
+});
+
+export default agent;
+```
+
+## Error Handling
+
+### Cascading Failures
+
+By default, errors propagate through the call chain:
+
+```typescript
+import validatorAgent from '@agent/validator';
+import processorAgent from '@agent/processor';
+
+const pipeline = createAgent('Pipeline', {
+ handler: async (ctx, input) => {
+ // If validatorAgent throws, execution stops here
+ const validated = await validatorAgent.run(input);
+
+ // This never executes if validation fails
+ const processed = await processorAgent.run(validated);
+
+ return processed;
+ },
+});
+```
+
+This is the recommended pattern for critical operations where later steps cannot proceed without earlier results.
+
+### Graceful Degradation
+
+For optional operations, catch errors and continue:
+
+```typescript
+import enrichmentAgent from '@agent/enrichment';
+import processorAgent from '@agent/processor';
+
+const resilientProcessor = createAgent('Resilient Processor', {
+ handler: async (ctx, input) => {
+ let enrichedData = input.data;
+
+ // Try to enrich, but continue if it fails
+ try {
+ const enrichment = await enrichmentAgent.run({
+ data: input.data,
+ });
+ enrichedData = enrichment.data;
+ } catch (error) {
+ ctx.logger.warn('Enrichment failed, using original data', {
+ error: error instanceof Error ? error.message : String(error),
+ });
+ }
+
+ // Process with enriched data (or original if enrichment failed)
+ return await processorAgent.run({ data: enrichedData });
+ },
+});
+```
+
+### Retry Pattern
+
+Implement retry logic for unreliable operations:
+
+```typescript
+import externalServiceAgent from '@agent/external-service';
+
+async function callWithRetry(
+ fn: () => Promise,
+ maxRetries: number = 3,
+ delayMs: number = 1000
+): Promise {
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
+ try {
+ return await fn();
+ } catch (error) {
+ if (attempt === maxRetries) throw error;
+
+ // Exponential backoff
+ const delay = delayMs * Math.pow(2, attempt - 1);
+ await new Promise((resolve) => setTimeout(resolve, delay));
+ }
+ }
+ throw new Error('Retry failed');
+}
+
+const retryHandler = createAgent('Retry Handler', {
+ handler: async (ctx, input) => {
+ const result = await callWithRetry(() =>
+ externalServiceAgent.run(input)
+ );
+ return result;
+ },
+});
+```
+
+### Partial Failure Handling
+
+Handle mixed success/failure results with `Promise.allSettled()`:
+
+```typescript
+import processingAgent from '@agent/processing';
+
+const batchProcessor = createAgent('Batch Processor', {
+ handler: async (ctx, input) => {
+ const results = await Promise.allSettled(
+ input.items.map((item) => processingAgent.run({ item }))
+ );
+
+ const successful = results
+ .filter((r) => r.status === 'fulfilled')
+ .map((r) => r.value);
+
+ const failed = results
+ .filter((r) => r.status === 'rejected')
+ .map((r) => r.reason);
+
+ if (failed.length > 0) {
+ ctx.logger.warn('Some operations failed', { failedCount: failed.length });
+ }
+
+ return { successful, failedCount: failed.length };
+ },
+});
+```
+
+## Best Practices
+
+### Keep Agents Focused
+
+Each agent should have a single, well-defined responsibility:
+
+```typescript
+// Good: focused agents
+const validatorAgent = createAgent('Validator', { /* validates data */ });
+const enrichmentAgent = createAgent('Enrichment', { /* enriches data */ });
+const analysisAgent = createAgent('Analysis', { /* analyzes data */ });
+
+// Bad: monolithic agent
+const megaAgent = createAgent('MegaAgent', {
+ handler: async (ctx, input) => {
+ // Validates, enriches, analyzes all in one place
+ },
+});
+```
+
+Focused agents are easier to test, reuse, and maintain.
+
+### Use Schemas for Type Safety
+
+Define schemas on all agents for type-safe communication. See [Creating Agents](/Build/Agents/creating-agents) to learn more about using schemas.
+
+```typescript
+import sourceAgent from '@agent/source';
+
+// Source agent with output schema
+const source = createAgent('Source', {
+ schema: {
+ output: z.object({
+ data: z.string(),
+ metadata: z.object({ timestamp: z.string() }),
+ }),
+ },
+ handler: async (ctx, input) => {
+ return {
+ data: 'result',
+ metadata: { timestamp: new Date().toISOString() },
+ };
+ },
+});
+
+// Consumer agent - TypeScript validates the connection
+const consumer = createAgent('Consumer', {
+ handler: async (ctx, input) => {
+ const result = await source.run({});
+ // TypeScript knows result.data and result.metadata.timestamp exist
+ return { processed: result.data };
+ },
+});
+```
+
+### Leverage Shared Context
+
+Agent calls share the same session context:
+
+```typescript
+import processingAgent from '@agent/processing';
+
+const coordinator = createAgent('Coordinator', {
+ handler: async (ctx, input) => {
+ // Store data in thread state (async)
+ await ctx.thread.state.set('userId', input.userId);
+
+ // Called agents can access the same thread state
+ const result = await processingAgent.run(input);
+
+ // All agents share sessionId
+ ctx.logger.info('Processing complete', { sessionId: ctx.sessionId });
+
+ return result;
+ },
+});
+```
+
+Use this for tracking context, sharing auth data, and maintaining conversation state.
+
+## Full Example
+
+A customer support router that combines multiple patterns: conditional routing, graceful degradation, and background analytics.
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateObject } from 'ai';
+import { groq } from '@ai-sdk/groq';
+import { z } from 'zod';
+import supportAgent from '@agent/support';
+import salesAgent from '@agent/sales';
+import billingAgent from '@agent/billing';
+import generalAgent from '@agent/general';
+import analyticsAgent from '@agent/analytics';
+
+const IntentSchema = z.object({
+ agentType: z.enum(['support', 'sales', 'billing', 'general']),
+ confidence: z.number().min(0).max(1),
+ reasoning: z.string(),
+});
+
+const router = createAgent('Customer Router', {
+ schema: {
+ input: z.object({ message: z.string() }),
+ output: z.object({
+ response: z.string(),
+ handledBy: z.string(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ let intent: z.infer;
+ let handledBy = 'general';
+
+ // Classify intent with graceful degradation
+ try {
+ const result = await generateObject({
+ model: groq('llama-3.3-70b'),
+ schema: IntentSchema,
+ system: 'Classify the customer message by intent.',
+ prompt: input.message,
+ temperature: 0,
+ });
+ intent = result.object;
+
+ ctx.logger.info('Intent classified', {
+ type: intent.agentType,
+ confidence: intent.confidence,
+ });
+ } catch (error) {
+ // Fallback to general agent if classification fails
+ ctx.logger.warn('Classification failed, using fallback', {
+ error: error instanceof Error ? error.message : String(error),
+ });
+ intent = { agentType: 'general', confidence: 0, reasoning: 'fallback' };
+ }
+
+ // Route to specialist agent
+ let response: string;
+ try {
+ switch (intent.agentType) {
+ case 'support':
+ const supportResult = await supportAgent.run({
+ message: input.message,
+ context: intent.reasoning,
+ });
+ response = supportResult.response;
+ handledBy = 'support';
+ break;
+
+ case 'sales':
+ const salesResult = await salesAgent.run({
+ message: input.message,
+ context: intent.reasoning,
+ });
+ response = salesResult.response;
+ handledBy = 'sales';
+ break;
+
+ case 'billing':
+ const billingResult = await billingAgent.run({
+ message: input.message,
+ context: intent.reasoning,
+ });
+ response = billingResult.response;
+ handledBy = 'billing';
+ break;
+
+ default:
+ const generalResult = await generalAgent.run({
+ message: input.message,
+ });
+ response = generalResult.response;
+ handledBy = 'general';
+ }
+ } catch (error) {
+ ctx.logger.error('Specialist agent failed', { error, intent });
+ response = 'I apologize, but I encountered an issue. Please try again.';
+ handledBy = 'error';
+ }
+
+ // Log analytics in background (doesn't block response)
+ ctx.waitUntil(async () => {
+ await analyticsAgent.run({
+ event: 'customer_interaction',
+ intent: intent.agentType,
+ confidence: intent.confidence,
+ handledBy,
+ sessionId: ctx.sessionId,
+ });
+ });
+
+ return { response, handledBy };
+ },
+});
+
+export default router;
+```
+
+This example combines several patterns:
+- Use an LLM to classify intent and route to specialist agents
+- Handle failures gracefully: fallback to general agent if classification fails, friendly error message if specialists fail
+- Log analytics in the background with `waitUntil()` so the response isn't delayed
+
+## Next Steps
+
+- [State Management](/Build/Agents/state-management): Share data across agent calls with thread and session state
+- [Evaluations](/Build/Agents/evaluations): Add quality checks to your agent workflows
diff --git a/content/Agents/creating-agents.mdx b/content/Agents/creating-agents.mdx
new file mode 100644
index 00000000..00f611ab
--- /dev/null
+++ b/content/Agents/creating-agents.mdx
@@ -0,0 +1,369 @@
+---
+title: Creating Agents
+description: Build agents with createAgent(), schemas, and handlers
+---
+
+Each agent encapsulates a handler function, input/output validation, and metadata in a single unit that can be invoked from routes, other agents, or scheduled tasks.
+
+## Basic Agent
+
+Create an agent with `createAgent()`, providing a name and handler function:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+
+const agent = createAgent('Greeter', {
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing request', { input });
+ return { message: 'Hello from agent!' };
+ },
+});
+
+export default agent;
+```
+
+The handler receives two parameters:
+- `ctx` - The agent context with logging, storage, and state management
+- `input` - The data passed to the agent (validated if schema is defined)
+
+
+In agents, access services directly on `ctx`: `ctx.logger`, `ctx.kv`, `ctx.thread`, etc.
+
+In routes, use [Hono's context](https://hono.dev/docs/api/context): `c.var.logger` or `c.get('logger')`, `c.var.kv`, `c.var.thread`, etc.
+
+
+## Adding LLM Capabilities
+
+Most agents use an LLM for inference. Here's an agent using the [AI SDK](https://ai-sdk.dev):
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('Assistant', {
+ schema: {
+ input: s.object({ prompt: s.string() }),
+ output: s.object({ response: s.string() }),
+ },
+ handler: async (ctx, { prompt }) => {
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt,
+ });
+
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+You can also use provider SDKs directly:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import OpenAI from 'openai';
+
+const client = new OpenAI();
+
+const agent = createAgent('Assistant', {
+ description: 'An agent using OpenAI SDK directly',
+ schema: {
+ input: s.object({ prompt: s.string() }),
+ output: s.string(),
+ },
+ handler: async (ctx, { prompt }) => {
+ const completion = await client.chat.completions.create({
+ model: 'gpt-5-mini',
+ messages: [{ role: 'user', content: prompt }],
+ });
+
+ return completion.choices[0]?.message?.content ?? '';
+ },
+});
+
+export default agent;
+```
+
+Or use Groq for fast inference with open-source models:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+import Groq from 'groq-sdk';
+
+const client = new Groq();
+
+const agent = createAgent('Assistant', {
+ description: 'An agent using Groq SDK with open-source models',
+ schema: {
+ input: s.object({ prompt: s.string() }),
+ output: s.string(),
+ },
+ handler: async (ctx, { prompt }) => {
+ const completion = await client.chat.completions.create({
+ model: 'llama-3.3-70b-versatile',
+ messages: [{ role: 'user', content: prompt }],
+ });
+
+ return completion.choices[0]?.message?.content ?? '';
+ },
+});
+
+export default agent;
+```
+
+For streaming, structured output, and more patterns, see [Using the AI SDK](/Build/Agents/ai-sdk-integration).
+
+## Adding Schema Validation
+
+Define input and output schemas for type safety and runtime validation. Agentuity includes a lightweight built-in schema library:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('Contact Form', {
+ schema: {
+ input: s.object({
+ email: s.string(),
+ message: s.string(),
+ }),
+ output: s.object({
+ success: s.boolean(),
+ id: s.string(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // input is typed as { email: string, message: string }
+ ctx.logger.info('Received message', { from: input.email });
+
+ return {
+ success: true,
+ id: crypto.randomUUID(),
+ };
+ },
+});
+
+export default agent;
+```
+
+You can also use [Zod](https://zod.dev) for more advanced validation:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('Contact Form', {
+ schema: {
+ input: z.object({
+ email: z.string().email(),
+ message: z.string().min(1),
+ }),
+ output: z.object({
+ success: z.boolean(),
+ id: z.string(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Received message', { from: input.email });
+
+ return {
+ success: true,
+ id: crypto.randomUUID(),
+ };
+ },
+});
+
+export default agent;
+```
+
+**Validation behavior:**
+- Input is validated before the handler runs
+- Output is validated before returning to the caller
+- Invalid data throws an error with details about what failed
+
+
+- **`@agentuity/schema`** — Lightweight, built-in, zero dependencies
+- **[Zod](https://zod.dev)** — Popular, feature-rich, great ecosystem
+- **[Valibot](https://valibot.dev)** — Tiny bundle size, tree-shakeable
+- **[ArkType](https://arktype.io)** — TypeScript-native syntax
+
+All implement [StandardSchema](https://github.com/standard-schema/standard-schema). See [Schema Libraries](/Build/Agents/schema-libraries) for detailed examples.
+
+
+### Type Inference
+
+TypeScript automatically infers types from your schemas:
+
+```typescript
+const agent = createAgent('Search', {
+ schema: {
+ input: z.object({
+ query: z.string(),
+ filters: z.object({
+ category: z.enum(['tech', 'business', 'sports']),
+ limit: z.number().default(10),
+ }),
+ }),
+ output: z.object({
+ results: z.array(z.string()),
+ total: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Full autocomplete for input.query, input.filters.category, etc.
+ const category = input.filters.category; // type: 'tech' | 'business' | 'sports'
+
+ return {
+ results: ['result1', 'result2'],
+ total: 2,
+ };
+ },
+});
+```
+
+### Common Zod Patterns
+
+```typescript
+z.object({
+ // Strings
+ name: z.string().min(1).max(100),
+ email: z.string().email(),
+ url: z.string().url().optional(),
+
+ // Numbers
+ age: z.number().min(0).max(120),
+ score: z.number().min(0).max(1),
+
+ // Enums and literals
+ status: z.enum(['active', 'pending', 'complete']),
+ type: z.literal('user'),
+
+ // Arrays and nested objects
+ tags: z.array(z.string()),
+ metadata: z.object({
+ createdAt: z.date(),
+ version: z.number(),
+ }).optional(),
+
+ // Defaults
+ limit: z.number().default(10),
+})
+```
+
+### Schema Descriptions for AI
+
+When using `generateObject()` from the AI SDK, add `.describe()` to help the LLM understand each field:
+
+```typescript
+z.object({
+ title: z.string().describe('Event title, concise, without names'),
+ startTime: z.string().describe('Start time in HH:MM format (e.g., 14:00)'),
+ priority: z.enum(['low', 'medium', 'high']).describe('Urgency level'),
+})
+```
+
+Call `.describe()` at the end of the chain: schema methods like `.min()` return new instances that don't inherit metadata.
+
+## Handler Context
+
+The handler context (`ctx`) provides access to Agentuity services:
+
+```typescript
+handler: async (ctx, input) => {
+ // Logging (Remember: always use ctx.logger, not console.log)
+ ctx.logger.info('Processing', { data: input });
+ ctx.logger.error('Something failed', { error });
+
+ // Identifiers
+ ctx.sessionId; // Unique per request (sess_...)
+ ctx.thread.id; // Conversation context (thrd_...)
+ ctx.current.name; // This agent's name
+ ctx.current.agentId; // Stable ID for namespacing state keys
+
+ // State management
+ ctx.state.set('key', value); // Request-scoped (sync, cleared after response)
+ await ctx.thread.state.set('key', value); // Thread-scoped (async, up to 1 hour)
+ ctx.session.state.set('key', value); // Session-scoped
+
+ // Storage
+ await ctx.kv.set('bucket', 'key', data);
+ await ctx.vector.search('namespace', { query: 'text' });
+
+ // Background tasks
+ ctx.waitUntil(async () => {
+ await ctx.kv.set('analytics', 'event', { timestamp: Date.now() });
+ });
+
+ return { result };
+}
+```
+
+For detailed state management patterns, see [Managing State](/Build/Agents/state-management).
+
+## Agent Name and Description
+
+Every agent requires a name (first argument) and can include an optional description:
+
+```typescript
+const agent = createAgent('Support Ticket Analyzer', {
+ description: 'Analyzes support tickets and extracts key information',
+ schema: { ... },
+ handler: async (ctx, input) => { ... },
+});
+```
+
+The name is used for identification in logs, Workbench, and the Agentuity console. The description helps document what the agent does.
+
+## Adding Test Prompts
+
+Export a `welcome` function to add test prompts for [Workbench](/Build/Agents/workbench):
+
+```typescript
+export const welcome = () => ({
+ welcome: 'Welcome to the **Support Ticket Analyzer** agent.',
+ prompts: [
+ {
+ data: JSON.stringify({ ticketId: 'TKT-1234', subject: 'Login issue' }),
+ contentType: 'application/json',
+ },
+ ],
+});
+
+export default agent;
+```
+
+See [Testing with Workbench](/Build/Agents/workbench) for full setup and configuration.
+
+## Best Practices
+
+- **Single responsibility**: Each agent should have one clear purpose
+- **Always define schemas**: Schemas provide type safety and serve as documentation
+- **Handle errors gracefully**: Wrap external calls in try-catch blocks
+- **Keep handlers focused**: Move complex logic to helper functions
+
+```typescript
+import processor from '@agent/processor';
+
+// Good: Clear, focused handler
+handler: async (ctx, input) => {
+ try {
+ const enriched = await enrichData(input.data);
+ const result = await processor.run(enriched);
+ return { success: true, result };
+ } catch (error) {
+ ctx.logger.error('Processing failed', { error });
+ return { success: false, error: 'Processing failed' };
+ }
+}
+```
+
+## Next Steps
+
+- [Using the AI SDK](/Build/Agents/ai-sdk-integration): Add LLM capabilities with generateText and streamText
+- [Managing State](/Build/Agents/state-management): Persist data across requests with thread and session state
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Build multi-agent workflows
diff --git a/content/Agents/evaluations.mdx b/content/Agents/evaluations.mdx
new file mode 100644
index 00000000..e95de8dd
--- /dev/null
+++ b/content/Agents/evaluations.mdx
@@ -0,0 +1,465 @@
+---
+title: Adding Evaluations
+description: Automatically test and validate agent outputs for quality and compliance
+---
+
+Evaluations (evals) are automated tests that run after your agent completes. They validate output quality, check compliance, and monitor performance without blocking agent responses.
+
+Evals come in two types: **binary** (pass/fail) for yes/no criteria, and **score** (0-1) for quality gradients.
+
+
+Evals run in the background after your agent responds. Results appear in the [App](https://app-v1.agentuity.com), not in your response.
+
+To show scores in your frontend, include them in your output schema. See [Inline Scoring for Frontend Display](#inline-scoring-for-frontend-display) below.
+
+
+## Where to Define Evals
+
+Evals must be defined in an `eval.ts` file in the same folder as your agent:
+
+```
+src/agent/qa-agent/
+├── agent.ts # Agent definition
+└── eval.ts # Evals with named exports
+```
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+// Named export required (not export default)
+export const adversarialEval = agent.createEval('adversarial', { // [!code highlight]
+ description: 'Checks against common adversarial prompts',
+ handler: async (ctx, input, output) => {
+ ctx.logger.info('Running adversarial check', { inputLength: input.question.length });
+
+ const { object } = await generateObject({
+ model: openai('gpt-5-nano'),
+ schema: z.object({
+ passed: z.boolean(),
+ reason: z.string(),
+ }),
+ prompt: `Check if this response handles adversarial input safely...`,
+ });
+
+ ctx.logger.info('Adversarial check complete', { passed: object.passed });
+ return { passed: object.passed, reason: object.reason };
+ },
+});
+```
+
+
+Evals must use named exports (`export const evalName = ...`). Default exports won't work.
+
+The runtime auto-discovers `eval.ts` files next to your agents, so you don't need any special imports in your routes.
+
+
+## Basic Example
+
+Create an `eval.ts` file next to your agent and attach evals using `createEval()`:
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+// Score eval: returns 0-1 quality score
+export const confidenceEval = agent.createEval('confidence-check', {
+ description: 'Scores output based on confidence level',
+ handler: async (ctx, input, output) => {
+ const passed = output.confidence >= 0.8;
+ return {
+ passed,
+ score: output.confidence,
+ metadata: { threshold: 0.8 },
+ };
+ },
+});
+```
+
+Evals run asynchronously after the response is sent, so they don't delay users.
+
+## Binary vs Score Evals
+
+### Binary (Pass/Fail)
+
+Use for yes/no criteria. LLM-based judgment works best for subjective assessments:
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+import OpenAI from 'openai';
+import { s } from '@agentuity/schema';
+
+const client = new OpenAI();
+
+const HelpfulnessSchema = s.object({
+ isHelpful: s.boolean(),
+ reason: s.string(),
+});
+
+export const helpfulnessEval = agent.createEval('is-helpful', {
+ description: 'Uses LLM to judge helpfulness',
+ handler: async (ctx, input, output) => {
+ const completion = await client.chat.completions.create({
+ model: 'gpt-5-nano',
+ response_format: {
+ type: 'json_schema',
+ json_schema: {
+ name: 'helpfulness_check',
+ schema: s.toJSONSchema(HelpfulnessSchema) as Record,
+ strict: true,
+ },
+ },
+ messages: [{
+ role: 'user',
+ content: `Evaluate if this response is helpful for the user's question.
+
+Question: ${input.question}
+Response: ${output.answer}
+
+Consider: Does it answer the question? Is it actionable?`,
+ }],
+ });
+
+ const result = JSON.parse(completion.choices[0]?.message?.content ?? '{}');
+ return { passed: result.isHelpful, reason: result.reason }; // [!code highlight]
+ },
+});
+```
+
+
+The example above uses `@agentuity/schema` with OpenAI's Chat Completions API for direct control. For simpler code, use AI SDK with Zod (shown in other examples). Both approaches work, so choose based on your needs.
+
+For type inference with `@agentuity/schema`:
+
+```typescript
+type MyType = s.infer; // { score: number; reason: string }
+```
+
+
+### Score (0-1)
+
+Use for quality gradients where you need nuance beyond pass/fail:
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+export const relevanceEval = agent.createEval('relevance-score', {
+ description: 'Scores how relevant the answer is to the question',
+ handler: async (ctx, input, output) => {
+ const { object } = await generateObject({
+ model: openai('gpt-5-nano'),
+ schema: z.object({
+ score: z.number().min(0).max(1),
+ reason: z.string(),
+ }),
+ prompt: `Score how relevant this answer is to the question (0-1).
+
+Question: ${input.question}
+Answer: ${output.answer}
+
+0 = completely off-topic, 1 = directly addresses the question.`,
+ });
+
+ return {
+ passed: object.score >= 0.7,
+ score: object.score,
+ reason: object.reason,
+ }; // [!code highlight]
+ },
+});
+```
+
+## LLM-as-Judge Pattern
+
+The LLM-as-judge pattern uses one model to evaluate another model's output. This is useful for subjective quality assessments that can't be checked programmatically. In this example, a small model judges whether a RAG agent's answer is grounded in the retrieved sources:
+
+```typescript title="src/agent/rag-agent/eval.ts"
+import ragAgent from './agent';
+import OpenAI from 'openai';
+import { s } from '@agentuity/schema';
+
+const client = new OpenAI();
+
+const GroundingSchema = s.object({
+ isGrounded: s.boolean(),
+ unsupportedClaims: s.array(s.string()),
+ score: s.number(),
+});
+
+export const hallucinationEval = ragAgent.createEval('hallucination-check', {
+ description: 'Detects claims not supported by sources',
+ handler: async (ctx, input, output) => {
+ const retrievedDocs = ctx.state.get('retrievedDocs') as string[];
+
+ const completion = await client.chat.completions.create({
+ model: 'gpt-5-nano',
+ response_format: {
+ type: 'json_schema',
+ json_schema: {
+ name: 'grounding_check',
+ schema: s.toJSONSchema(GroundingSchema) as Record,
+ strict: true,
+ },
+ },
+ messages: [{
+ role: 'user',
+ content: `Check if this answer is supported by the source documents.
+
+Question: ${input.question}
+Answer: ${output.answer}
+
+Sources:
+${retrievedDocs.join('\n\n')}
+
+Identify any claims not supported by the sources.`,
+ }],
+ });
+
+ const result = JSON.parse(completion.choices[0]?.message?.content ?? '{}');
+ return {
+ passed: result.isGrounded,
+ score: result.score,
+ reason: result.isGrounded ? 'Answer is grounded in sources' : 'Found unsupported claims',
+ metadata: {
+ isGrounded: result.isGrounded,
+ unsupportedClaims: result.unsupportedClaims,
+ },
+ };
+ },
+});
+```
+
+
+Data stored in `ctx.state` during agent execution persists to eval handlers. Use this to pass retrieved documents, intermediate results, or timing data.
+
+
+### Inline Scoring for Frontend Display
+
+When you need scores visible in your UI (not just the App), run LLM-as-judge inline in your handler and include the results in your output schema:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText, generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const ScoresSchema = z.object({
+ creativity: z.number().min(0).max(1),
+ engagement: z.number().min(0).max(1),
+ toneMatch: z.boolean(),
+});
+
+const agent = createAgent('Story Generator', {
+ schema: {
+ input: z.object({ prompt: z.string(), tone: z.string() }),
+ output: z.object({
+ story: z.string(),
+ scores: ScoresSchema,
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Generate the story
+ const { text: story } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: `Write a short ${input.tone} story about: ${input.prompt}`,
+ });
+
+ // Inline LLM-as-judge: scores returned with response
+ const { object: scores } = await generateObject({
+ model: openai('gpt-5-nano'),
+ schema: ScoresSchema,
+ prompt: `Score this ${input.tone} story (0-1 for scores, boolean for tone match):
+
+${story}
+
+- creativity: How original and imaginative?
+- engagement: How compelling to read?
+- toneMatch: Does it match the requested "${input.tone}" tone?`,
+ });
+
+ return { story, scores }; // Frontend receives scores directly
+ },
+});
+
+export default agent;
+```
+
+Your frontend can then display the scores alongside the response. This pattern is useful for model comparisons, content moderation dashboards, or any UI that needs to show quality metrics.
+
+## Multiple Evals
+
+When you have multiple evals, define them in a separate `eval.ts` file. All evals run in parallel after the agent completes. You can mix custom evals with preset evals:
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+import { pii, conciseness } from '@agentuity/evals';
+
+// Eval 1: Custom LLM-based relevance score
+export const relevanceEval = agent.createEval('relevance', {
+ description: 'Scores response relevance',
+ handler: async (ctx, input, output) => {
+ ctx.logger.info('Running relevance check');
+
+ const { object } = await generateObject({
+ model: openai('gpt-5-nano'),
+ schema: z.object({
+ score: z.number().min(0).max(1),
+ reason: z.string(),
+ }),
+ prompt: `Score relevance (0-1): Does "${output.answer}" answer "${input.question}"?`,
+ });
+
+ ctx.logger.info('Relevance check complete', { score: object.score });
+ return {
+ passed: object.score >= 0.7,
+ score: object.score,
+ reason: object.reason,
+ };
+ },
+});
+
+// Eval 2: Preset conciseness eval
+export const concisenessCheck = agent.createEval(conciseness()); // [!code highlight]
+
+// Eval 3: Preset PII detection (LLM-powered, more thorough than regex)
+export const piiCheck = agent.createEval(pii()); // [!code highlight]
+```
+
+Errors in one eval don't affect others. Each runs independently.
+
+## Error Handling
+
+Return `success: false` when an eval can't complete:
+
+```typescript title="src/agent/my-agent/eval.ts"
+import agent from './agent';
+
+export const externalValidationEval = agent.createEval('external-validation', {
+ description: 'Validates output via external API',
+ handler: async (ctx, input, output) => {
+ try {
+ const response = await fetch('https://api.example.com/validate', {
+ method: 'POST',
+ body: JSON.stringify({ text: output.answer }),
+ signal: AbortSignal.timeout(3000),
+ });
+
+ if (!response.ok) {
+ return { success: false, passed: false, error: `Service error: ${response.status}` };
+ }
+
+ const result = await response.json();
+ return { passed: result.isValid };
+ } catch (error) {
+ ctx.logger.error('Validation failed', { error });
+ return { success: false, passed: false, error: error.message };
+ }
+ },
+});
+```
+
+Eval errors are logged but don't affect agent responses.
+
+## Preset Evals
+
+The `@agentuity/evals` package provides reusable evaluations for common quality checks. These preset evals can be configured with custom thresholds (minimum score to pass) and models.
+
+### Available Presets
+
+| Preset | Type | Threshold | Description |
+|--------|------|-----------|-------------|
+| `politeness` | Score | 0.8 | Flags rude, dismissive, condescending, or hostile tone |
+| `safety` | Binary | — | Detects unsafe content (harassment, harmful content, illegal guidance) and ensures medical/legal/financial advice includes disclaimers |
+| `pii` | Binary | — | Scans for personal data: emails, phone numbers, SSNs, addresses, credit cards |
+| `conciseness` | Score | 0.7 | Penalizes filler phrases, redundant explanations, and responses disproportionate to request complexity |
+| `adversarial` | Binary | — | Detects prompt injection, jailbreaks, and manipulation attempts; auto-passes if no attack in request |
+| `ambiguity` | Score | 0.7 | Flags unclear references, vague statements, and undefined terms with multiple meanings |
+| `answerCompleteness` | Score | 0.7 | Checks that all questions are directly answered; penalizes tangential or vague responses |
+| `extraneousContent` | Score | 0.7 | Flags off-topic content, unsolicited advice, and meta-commentary ("I hope this helps!") |
+| `format` | Binary | — | Validates response matches requested format (JSON, lists, tables); auto-passes if no format specified |
+| `knowledgeRetention` | Score | 0.7 | Detects contradictions with prior conversation context; auto-passes with no history |
+| `roleAdherence` | Score | 0.7 | Ensures response stays in character; detects domain violations and persona breaks |
+| `selfReference` | Binary | — | Flags AI self-identification ("As an AI...") unless user asked about the model |
+
+### Using Preset Evals
+
+Import preset evals from `@agentuity/evals` and pass them to `agent.createEval()`:
+
+```typescript title="src/agent/chat/eval.ts"
+import agent from './agent';
+import { politeness, safety, pii } from '@agentuity/evals';
+
+// Use with default settings
+export const politenessCheck = agent.createEval(politeness()); // [!code highlight]
+
+// Override the name
+export const safetyCheck = agent.createEval(safety({
+ name: 'safety-strict',
+}));
+
+// PII detection with defaults
+export const piiCheck = agent.createEval(pii());
+```
+
+### Configuring Preset Evals
+
+Preset evals accept configuration options:
+
+```typescript
+import { politeness } from '@agentuity/evals';
+import { openai } from '@ai-sdk/openai';
+
+// Override model and threshold
+export const politenessCheck = agent.createEval(politeness({
+ name: 'politeness-strict',
+ model: openai('gpt-5-nano'),
+ threshold: 0.9, // Stricter passing threshold
+}));
+```
+
+All preset evals use a default model optimized for cost and speed. Override `model` when you need specific capabilities.
+
+### Schema Middleware
+
+Preset evals expect a standard input/output format:
+- **Input**: `{ request: string, context?: string }`
+- **Output**: `{ response: string }`
+
+When your agent uses different schemas, provide middleware to transform between them:
+
+```typescript title="src/agent/calculator/eval.ts"
+import agent from './agent';
+import { politeness } from '@agentuity/evals';
+import type { AgentInput, AgentOutput } from './agent';
+
+// Agent schema: { value: number } -> { result: number, doubled: boolean }
+// Eval expects: { request: string } -> { response: string }
+
+export const politenessCheck = agent.createEval(
+ politeness({
+ middleware: {
+ transformInput: (input) => ({
+ request: `Calculate double of ${input.value}`,
+ }),
+ transformOutput: (output) => ({
+ response: `Result: ${output.result}, Doubled: ${output.doubled}`,
+ }),
+ },
+ })
+);
+```
+
+Pass your agent's schema types as generics to get typed middleware transforms. Without generics, the transform functions receive `any`.
+
+## Next Steps
+
+- [Events & Lifecycle](/Build/Agents/events-lifecycle): Monitor agent execution with lifecycle hooks
+- [State Management](/Build/Agents/state-management): Share data between handlers and evals
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Build multi-agent workflows
diff --git a/content/Agents/events-lifecycle.mdx b/content/Agents/events-lifecycle.mdx
new file mode 100644
index 00000000..b1bbbf93
--- /dev/null
+++ b/content/Agents/events-lifecycle.mdx
@@ -0,0 +1,255 @@
+---
+title: Events & Lifecycle
+description: Lifecycle hooks for monitoring and extending agent behavior
+---
+
+Events provide lifecycle hooks for monitoring agent execution. Use them for logging, metrics, analytics, and error tracking.
+
+## Agent Events
+
+Track individual agent execution with `started`, `completed`, and `errored` events:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('TaskProcessor', {
+ schema: {
+ input: s.object({ task: s.string() }),
+ output: s.object({ result: s.string() }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing task', { task: input.task });
+ return { result: `Completed: ${input.task}` };
+ },
+});
+
+// Track execution timing
+agent.addEventListener('started', (event, agent, ctx) => {
+ ctx.state.set('startTime', Date.now());
+ ctx.logger.info('Agent started', { agent: agent.metadata.name });
+});
+
+agent.addEventListener('completed', (event, agent, ctx) => {
+ const startTime = ctx.state.get('startTime') as number;
+ const duration = Date.now() - startTime;
+
+ ctx.logger.info('Agent completed', {
+ agent: agent.metadata.name,
+ durationMs: duration,
+ });
+
+ // Warn on slow executions
+ if (duration > 1000) {
+ ctx.logger.warn('Slow execution detected', { duration, threshold: 1000 });
+ }
+});
+
+agent.addEventListener('errored', (event, agent, ctx, error) => {
+ const startTime = ctx.state.get('startTime') as number;
+ const duration = Date.now() - startTime;
+
+ ctx.logger.error('Agent failed', {
+ agent: agent.metadata.name,
+ error: error.message,
+ durationMs: duration,
+ });
+});
+
+export default agent;
+```
+
+Event listeners receive: event name, agent instance, context, and (for `errored`) the error object.
+
+## App-Level Events
+
+Monitor all agents globally by registering listeners in `app.ts`:
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const app = await createApp();
+
+// Track all agent executions
+app.addEventListener('agent.started', (event, agent, ctx) => {
+ ctx.logger.info('Agent execution started', {
+ agent: agent.metadata.name,
+ sessionId: ctx.sessionId,
+ });
+});
+
+app.addEventListener('agent.completed', (event, agent, ctx) => {
+ ctx.logger.info('Agent execution completed', {
+ agent: agent.metadata.name,
+ sessionId: ctx.sessionId,
+ });
+});
+
+app.addEventListener('agent.errored', (event, agent, ctx, error) => {
+ ctx.logger.error('Agent execution failed', {
+ agent: agent.metadata.name,
+ error: error.message,
+ sessionId: ctx.sessionId,
+ });
+});
+```
+
+### Available App Events
+
+| Event | Description |
+|-------|-------------|
+| `agent.started` | Any agent starts execution |
+| `agent.completed` | Any agent completes successfully |
+| `agent.errored` | Any agent throws an error |
+| `session.started` | New session begins |
+| `session.completed` | Session ends |
+| `thread.created` | New thread created |
+| `thread.destroyed` | Thread expired or destroyed |
+
+## App Lifecycle Hooks
+
+Use `setup` and `shutdown` hooks to initialize resources and manage typed app state:
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ setup: async () => {
+ // Initialize resources when the app starts
+ const dbClient = await connectToDatabase();
+
+ // Return typed app state - available in all agents via ctx.app
+ return {
+ db: dbClient,
+ startedAt: new Date(),
+ };
+ },
+ shutdown: async (state) => {
+ // Cleanup when the app shuts down
+ // state is typed from setup's return value
+ await state.db.close();
+ logger.info('App ran for:', Date.now() - state.startedAt.getTime(), 'ms');
+ },
+});
+```
+
+Access app state in any agent handler:
+
+```typescript
+const agent = createAgent('DataFetcher', {
+ handler: async (ctx, input) => {
+ // ctx.app is fully typed from setup's return value
+ const results = await ctx.app.db.query('SELECT * FROM users');
+ return { users: results };
+ },
+});
+```
+
+
+Common uses for app lifecycle hooks:
+- Database connection pools
+- Cache initialization
+- External service clients
+- Metrics/telemetry setup
+
+
+## Agent Lifecycle Hooks
+
+Individual agents can also define `setup` and `shutdown` functions for agent-specific initialization:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('CachedLookup', {
+ schema: {
+ input: z.object({ key: z.string() }),
+ output: z.object({ value: z.string() }),
+ },
+ // Called once when app starts - receives app state, returns agent config
+ setup: async (app) => {
+ const cache = new Map();
+ return { cache };
+ },
+ // Called when app shuts down - receives app state and agent config
+ shutdown: async (app, config) => {
+ config.cache.clear();
+ },
+ handler: async (ctx, input) => {
+ // ctx.config is typed from setup's return value
+ const cached = ctx.config.cache.get(input.key);
+ if (cached) {
+ return { value: cached };
+ }
+
+ // Fetch and cache
+ const value = await fetchValue(input.key);
+ ctx.config.cache.set(input.key, value);
+ return { value };
+ },
+});
+
+export default agent;
+```
+
+**Key differences from app lifecycle:**
+- `setup` receives `app` state (from `createApp`) and returns agent-specific config
+- Config is accessed via `ctx.config` (not `ctx.app`)
+- Each agent can have its own isolated resources
+
+
+- **App setup (`createApp`)**: Shared resources like database pools, Redis clients
+- **Agent setup**: Agent-specific caches, pre-loaded models, isolated connections
+
+
+## Shared State
+
+Event handlers share state via `ctx.state`:
+
+```typescript
+agent.addEventListener('started', (event, agent, ctx) => {
+ ctx.state.set('startTime', Date.now());
+ ctx.state.set('metadata', { userId: '123', source: 'api' });
+});
+
+agent.addEventListener('completed', (event, agent, ctx) => {
+ const startTime = ctx.state.get('startTime') as number;
+ const metadata = ctx.state.get('metadata') as Record;
+
+ ctx.logger.info('Execution complete', {
+ duration: Date.now() - startTime,
+ ...metadata,
+ });
+});
+```
+
+
+Use `ctx.waitUntil()` in event handlers for non-blocking operations like sending metrics to external services:
+
+```typescript
+agent.addEventListener('completed', (event, agent, ctx) => {
+ ctx.waitUntil(async () => {
+ await sendMetricsToExternalService({ agent: agent.metadata.name });
+ });
+});
+```
+
+
+## Events vs Evals
+
+| Aspect | Events | Evals |
+|--------|--------|-------|
+| **Purpose** | Monitoring, logging | Quality assessment |
+| **Timing** | During execution | After completion |
+| **Blocking** | Synchronous | Background (`waitUntil`) |
+| **Output** | Logs, metrics | Pass/fail, scores |
+
+Use events for observability. Use [evaluations](/Build/Agents/evaluations) for output quality checks.
+
+## Next Steps
+
+- [Evaluations](/Build/Agents/evaluations): Automated quality testing for agent outputs
+- [State Management](/Build/Agents/state-management): Thread and session state patterns
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Multi-agent coordination
+- [Logging](/Build/Observability/logging): Structured logging for debugging events
+- [Tracing](/Build/Observability/tracing): Track timing across event handlers
diff --git a/content/Agents/meta.json b/content/Agents/meta.json
new file mode 100644
index 00000000..060e68ba
--- /dev/null
+++ b/content/Agents/meta.json
@@ -0,0 +1,16 @@
+{
+ "title": "Agents",
+ "pages": [
+ "creating-agents",
+ "workbench",
+ "schema-libraries",
+ "ai-gateway",
+ "ai-sdk-integration",
+ "streaming-responses",
+ "state-management",
+ "calling-other-agents",
+ "standalone-execution",
+ "evaluations",
+ "events-lifecycle"
+ ]
+}
diff --git a/content/Agents/schema-libraries.mdx b/content/Agents/schema-libraries.mdx
new file mode 100644
index 00000000..7843ee37
--- /dev/null
+++ b/content/Agents/schema-libraries.mdx
@@ -0,0 +1,298 @@
+---
+title: Schema Libraries
+description: Choose from built-in, Zod, Valibot, or ArkType for validation
+---
+
+Agentuity uses the [StandardSchema](https://github.com/standard-schema/standard-schema) interface for validation, which means you can use any compatible library.
+
+## Choosing a Library
+
+| Library | Syntax | Best For |
+|---------|--------|----------|
+| `@agentuity/schema` | `s.object({ name: s.string() })` | Zero dependencies, basic validation |
+| [Zod](https://zod.dev) | `z.object({ name: z.string() })` | AI SDK integration (`.describe()` support) |
+| [Valibot](https://valibot.dev) | `v.object({ name: v.string() })` | Smallest bundle size |
+| [ArkType](https://arktype.io) | `type({ name: 'string' })` | TypeScript-native syntax, fast runtime |
+
+**Recommendation:** Start with `@agentuity/schema` for simple cases. Use other libraries depending on your needs. For example, Zod is recommended when working with `generateObject()` (its `.describe()` helps guide LLM output).
+
+## Using @agentuity/schema
+
+The built-in schema library provides simple validation with zero external dependencies.
+
+### Basic Schema
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('UserProcessor', {
+ schema: {
+ input: s.object({
+ email: s.string(),
+ age: s.number(),
+ role: s.string(),
+ }),
+ output: s.object({
+ success: s.boolean(),
+ userId: s.string(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing user', { email: input.email });
+ return {
+ success: true,
+ userId: crypto.randomUUID(),
+ };
+ },
+});
+
+export default agent;
+```
+
+### Common Patterns
+
+```typescript
+import { s } from '@agentuity/schema';
+
+// Primitives
+s.string() // Any string
+s.number() // Any number
+s.boolean() // Boolean
+s.null() // Null value
+s.undefined() // Undefined value
+s.any() // Any value (no validation)
+s.unknown() // Unknown value (safer any)
+
+// Objects and arrays
+s.object({ name: s.string() }) // Object shape
+s.array(s.string()) // Array of strings
+s.record(s.number()) // { [key: string]: number }
+
+// Optional and nullable
+s.optional(s.string()) // string | undefined
+s.nullable(s.string()) // string | null
+
+// Unions, literals, and enums
+s.union(s.string(), s.number()) // string | number
+s.literal('active') // Exact value
+s.enum(['admin', 'user', 'guest']) // One of these values
+
+// Type coercion (useful for form inputs, query params)
+s.coerce.string() // Convert to string via String(value)
+s.coerce.number() // Convert to number via Number(value)
+s.coerce.boolean() // Convert to boolean via Boolean(value)
+s.coerce.date() // Convert to Date via new Date(value)
+```
+
+### Type Inference
+
+Extract TypeScript types from schemas:
+
+```typescript
+import { s } from '@agentuity/schema';
+
+const User = s.object({
+ name: s.string(),
+ age: s.number(),
+ role: s.enum(['admin', 'user']),
+});
+
+// Extract the type
+type User = s.infer;
+// { name: string; age: number; role: 'admin' | 'user' }
+```
+
+
+Use `@agentuity/schema` for simple validation needs. For advanced features like email validation, string length constraints, or complex transformations, consider Zod or Valibot.
+
+
+## Using Valibot
+
+### Installation
+
+```bash
+bun add valibot
+```
+
+### Basic Schema
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import * as v from 'valibot';
+
+const InputSchema = v.object({
+ email: v.pipe(v.string(), v.email()),
+ age: v.pipe(v.number(), v.minValue(0), v.maxValue(120)),
+ role: v.picklist(['admin', 'user', 'guest']),
+});
+
+const OutputSchema = v.object({
+ success: v.boolean(),
+ userId: v.string(),
+});
+
+const agent = createAgent('UserProcessor', {
+ schema: {
+ input: InputSchema,
+ output: OutputSchema,
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing user', { email: input.email, role: input.role });
+ return {
+ success: true,
+ userId: crypto.randomUUID(),
+ };
+ },
+});
+
+export default agent;
+```
+
+### Common Patterns
+
+```typescript
+import * as v from 'valibot';
+
+// Strings
+v.string() // Any string
+v.pipe(v.string(), v.minLength(5)) // Minimum length
+v.pipe(v.string(), v.maxLength(100)) // Maximum length
+v.pipe(v.string(), v.email()) // Email format
+v.pipe(v.string(), v.url()) // URL format
+
+// Numbers
+v.number() // Any number
+v.pipe(v.number(), v.minValue(0)) // Minimum value
+v.pipe(v.number(), v.maxValue(100)) // Maximum value
+v.pipe(v.number(), v.integer()) // Integer only
+
+// Arrays and objects
+v.array(v.string()) // Array of strings
+v.object({ name: v.string() }) // Object shape
+
+// Optional and nullable
+v.optional(v.string()) // string | undefined
+v.nullable(v.string()) // string | null
+v.nullish(v.string()) // string | null | undefined
+
+// Enums
+v.picklist(['a', 'b', 'c']) // One of these values
+v.literal('exact') // Exact value
+
+// Defaults
+v.optional(v.string(), 'default') // With default value
+```
+
+## Using ArkType
+
+### Installation
+
+```bash
+bun add arktype
+```
+
+### Basic Schema
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { type } from 'arktype';
+
+const InputSchema = type({
+ email: 'string.email',
+ age: 'number>=0&<=120',
+ role: '"admin"|"user"|"guest"',
+});
+
+const OutputSchema = type({
+ success: 'boolean',
+ userId: 'string',
+});
+
+const agent = createAgent('UserProcessor', {
+ schema: {
+ input: InputSchema,
+ output: OutputSchema,
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing user', { email: input.email, role: input.role });
+ return {
+ success: true,
+ userId: crypto.randomUUID(),
+ };
+ },
+});
+
+export default agent;
+```
+
+### Common Patterns
+
+```typescript
+import { type } from 'arktype';
+
+// Strings
+type('string') // Any string
+type('string>5') // Minimum length (greater than 5 chars)
+type('string<100') // Maximum length
+type('string.email') // Email format
+type('string.url') // URL format
+
+// Numbers
+type('number') // Any number
+type('number>0') // Greater than 0
+type('number<=100') // Less than or equal to 100
+type('integer') // Integer only
+type('number>=0&<=120') // Range (0 to 120)
+
+// Arrays and objects
+type('string[]') // Array of strings
+type({ name: 'string' }) // Object shape
+
+// Optional and union
+type('string?') // string | undefined
+type('string|null') // string | null
+
+// Enums and literals
+type('"a"|"b"|"c"') // One of these values
+type('"exact"') // Exact value
+
+// Nested objects
+type({
+ user: {
+ name: 'string',
+ email: 'string.email',
+ },
+ tags: 'string[]?',
+})
+```
+
+## Migrating Between Libraries
+
+Schemas are interchangeable in `createAgent()`. The same agent structure works with any StandardSchema library:
+
+```typescript
+// With @agentuity/schema (built-in)
+import { s } from '@agentuity/schema';
+const schema = { input: s.object({ name: s.string() }) };
+
+// With Zod
+import { z } from 'zod';
+const schema = { input: z.object({ name: z.string() }) };
+
+// With Valibot
+import * as v from 'valibot';
+const schema = { input: v.object({ name: v.string() }) };
+
+// With ArkType
+import { type } from 'arktype';
+const schema = { input: type({ name: 'string' }) };
+
+// All work the same way in createAgent()
+createAgent('MyAgent', { schema, handler: async (ctx, input) => { ... } });
+```
+
+## Next Steps
+
+- [Creating Agents](/Build/Agents/creating-agents): Full guide to agent creation with Zod examples
+- [Using the AI SDK](/Build/Agents/ai-sdk-integration): Add LLM capabilities to your agents
diff --git a/content/Agents/standalone-execution.mdx b/content/Agents/standalone-execution.mdx
new file mode 100644
index 00000000..700ce73b
--- /dev/null
+++ b/content/Agents/standalone-execution.mdx
@@ -0,0 +1,111 @@
+---
+title: Running Agents Without HTTP
+description: Execute agents programmatically for cron jobs, bots, CLI tools, and background workers
+---
+
+Sometimes your agent logic needs to run without an incoming HTTP request. `createAgentContext()` gives standalone code the same infrastructure that HTTP handlers get automatically: tracing, sessions, and storage access.
+
+
+`createAgentContext()` requires Agentuity's runtime initialization and only works within the Agentuity runtime (Discord bots, CLI tools, queue workers deployed alongside your agents). It will throw an error if called from external frameworks like Next.js or Express. To access storage from external backends, see [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities).
+
+
+## Basic Usage
+
+```typescript
+import { createAgentContext } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const ctx = createAgentContext();
+const result = await ctx.invoke(() => chatAgent.run({ message: 'Hello' }));
+```
+
+The `invoke()` method executes your agent with full infrastructure support: tracing, session management, and access to all storage services.
+
+## Options
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `sessionId` | `string` | Custom session ID. Auto-generated from trace context if not provided |
+| `trigger` | `string` | Trigger type for telemetry: `'discord'`, `'cron'`, `'websocket'`, `'manual'` |
+| `thread` | `Thread` | Custom thread for conversation state |
+| `session` | `Session` | Custom session instance |
+| `parentContext` | `Context` | Parent OpenTelemetry context for distributed tracing |
+
+## External Cron Job Example
+
+For scheduled tasks managed outside of Agentuity:
+
+```typescript
+import { createApp, createAgentContext } from '@agentuity/runtime';
+import cron from 'node-cron';
+import cleanupAgent from '@agent/cleanup';
+
+await createApp();
+
+// Run cleanup every hour
+cron.schedule('0 * * * *', async () => {
+ const ctx = createAgentContext({ trigger: 'cron' });
+
+ await ctx.invoke(async () => {
+ await cleanupAgent.run({ task: 'expired-sessions' });
+ });
+});
+```
+
+
+For most scheduled tasks, use the [`cron()` middleware](/Build/Routes/cron) instead. It handles infrastructure automatically without needing `createAgentContext`. Use standalone execution only when you need external cron management.
+
+
+## Multiple Agents in Sequence
+
+Run multiple agents within a single `invoke()` call to share the same session and tracing context:
+
+```typescript
+const ctx = createAgentContext();
+
+const result = await ctx.invoke(async () => {
+ // First agent analyzes the input
+ const analysis = await analyzeAgent.run({ text: userInput });
+
+ // Second agent generates response based on analysis
+ const response = await respondAgent.run({
+ analysis: analysis.summary,
+ sentiment: analysis.sentiment,
+ });
+
+ return response;
+});
+```
+
+## Reusing Contexts
+
+Create a context once and reuse it for multiple invocations:
+
+```typescript
+const ctx = createAgentContext({ trigger: 'websocket' });
+
+// Each invoke() gets its own session and tracing span
+websocket.on('message', async (data) => {
+ const result = await ctx.invoke(() => messageAgent.run(data));
+ websocket.send(result);
+});
+```
+
+## What's Included
+
+
+Standalone contexts provide the same infrastructure as HTTP request handlers:
+
+- **Tracing**: OpenTelemetry spans with proper hierarchy
+- **Sessions**: Automatic save/restore via providers
+- **Threads**: Conversation state management
+- **Storage**: Full access to `kv`, `stream`, `vector`
+- **Background tasks**: `waitUntil` support for fire-and-forget work
+- **Session events**: Start/complete events for observability
+
+
+## Next Steps
+
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Agent-to-agent communication patterns
+- [Cron Routes](/Build/Routes/cron): Built-in scheduled task support
+- [State Management](/Build/Agents/state-management): Thread and session state
diff --git a/content/Agents/state-management.mdx b/content/Agents/state-management.mdx
new file mode 100644
index 00000000..1d0d020c
--- /dev/null
+++ b/content/Agents/state-management.mdx
@@ -0,0 +1,472 @@
+---
+title: Managing State
+description: Request and thread state for stateful agents
+---
+
+Agentuity provides two state scopes for managing data across requests:
+
+- **Request state** for temporary calculations within a single request
+- **Thread state** for conversation context that persists across requests
+
+
+Thread state uses async lazy-loading for performance. State is only fetched when first accessed, eliminating latency for requests that don't use thread state. All `ctx.thread.state` methods are async and require `await`.
+
+
+## State Scopes
+
+| Scope | Lifetime | Cleared When | Access | Example Use Case |
+|-------|----------|--------------|--------|----------|
+| Request | Single request | After response sent | `ctx.state` | Timing, temp calculations |
+| Thread | Up to 1 hour | Expiration or `destroy()` | `ctx.thread.state` | Conversation history |
+
+
+Threads "wrap" sessions. Think of a *thread* as a conversation and a *session* as one message in that conversation. Each request creates a new session, but sessions within the same conversation share a thread.
+
+
+
+Routes have the same state access via `c.var.thread` and `c.var.session`. Use `c.var.thread.state` for conversation context and `c.var.session.state` for request-scoped data. See [HTTP Routes](/Build/Routes/http#request-context) for route examples.
+
+
+### Quick Example
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('StateDemo', {
+ schema: {
+ input: s.object({ message: s.string() }),
+ output: s.object({
+ response: s.string(),
+ requestTime: s.number(),
+ messageCount: s.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // REQUEST STATE: Cleared after this response (sync)
+ ctx.state.set('startTime', Date.now());
+
+ // THREAD STATE: Persists across requests (async, up to 1 hour)
+ const messages = (await ctx.thread.state.get('messages')) || [];
+ messages.push(input.message);
+ await ctx.thread.state.set('messages', messages);
+
+ const requestTime = Date.now() - (ctx.state.get('startTime') as number);
+
+ return {
+ response: `Received: ${input.message}`,
+ requestTime,
+ messageCount: messages.length,
+ };
+ },
+});
+
+export default agent;
+```
+
+## Request State
+
+Request state (`ctx.state`) holds temporary data within a single request. It's cleared automatically after the response is sent.
+
+```typescript
+handler: async (ctx, input) => {
+ // Track timing
+ ctx.state.set('startTime', Date.now());
+
+ // Process request...
+ const result = await processData(input);
+
+ // Use the timing data
+ const duration = Date.now() - (ctx.state.get('startTime') as number);
+ ctx.logger.info('Request completed', { durationMs: duration });
+
+ return result;
+}
+```
+
+**Use cases:** Request timing, temporary calculations, passing data between event listeners.
+
+## Thread State
+
+Thread state (`ctx.thread.state`) persists across multiple requests within a conversation, expiring after 1 hour of inactivity. Thread identity is managed automatically via cookies (or the `x-thread-id` header for API clients).
+
+### Conversation Memory
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import * as v from 'valibot';
+
+interface Message {
+ role: 'user' | 'assistant';
+ content: string;
+}
+
+const agent = createAgent('ConversationMemory', {
+ schema: {
+ input: v.object({ message: v.string() }),
+ output: v.string(),
+ },
+ handler: async (ctx, input) => {
+ // Initialize on first request
+ if (!(await ctx.thread.state.has('messages'))) {
+ await ctx.thread.state.set('messages', []);
+ await ctx.thread.state.set('turnCount', 0);
+ }
+
+ const messages = await ctx.thread.state.get('messages') || [];
+ const turnCount = await ctx.thread.state.get('turnCount') || 0;
+
+ // Add user message
+ messages.push({ role: 'user', content: input.message });
+
+ // Generate response with conversation context
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ system: 'You are a helpful assistant. Reference previous messages when relevant.',
+ messages,
+ });
+
+ // Update thread state
+ messages.push({ role: 'assistant', content: text });
+ await ctx.thread.state.set('messages', messages);
+ await ctx.thread.state.set('turnCount', turnCount + 1);
+
+ ctx.logger.info('Conversation turn', {
+ threadId: ctx.thread.id,
+ turnCount: turnCount + 1,
+ });
+
+ return text;
+ },
+});
+
+export default agent;
+```
+
+### Thread Properties and Methods
+
+```typescript
+ctx.thread.id; // Thread ID (thrd_...)
+
+// All state methods are async
+await ctx.thread.state.set('key', value);
+await ctx.thread.state.get('key');
+await ctx.thread.state.has('key');
+await ctx.thread.state.delete('key');
+await ctx.thread.state.clear();
+
+// Array operations with optional sliding window
+await ctx.thread.state.push('messages', newMessage);
+await ctx.thread.state.push('messages', newMessage, 100); // Keep last 100
+
+// Bulk access (returns arrays, not iterators)
+const keys = await ctx.thread.state.keys(); // string[]
+const values = await ctx.thread.state.values(); // Message[]
+const entries = await ctx.thread.state.entries(); // [string, Message][]
+const count = await ctx.thread.state.size(); // number
+
+// State status
+ctx.thread.state.loaded; // Has state been fetched?
+ctx.thread.state.dirty; // Are there pending changes?
+
+// Reset the conversation
+await ctx.thread.destroy();
+```
+
+### Resetting a Conversation
+
+Call `ctx.thread.destroy()` to clear all thread state and start fresh:
+
+```typescript
+handler: async (ctx, input) => {
+ if (input.command === 'reset') {
+ await ctx.thread.destroy();
+ return 'Conversation reset. Thread state cleared.';
+ }
+
+ // Continue conversation...
+}
+```
+
+## ctx.state vs ctx.session.state
+
+Both `ctx.state` and `ctx.session.state` are request-scoped and reset after each request. The difference:
+
+- **`ctx.state`**: General request state, accessible in agent event listeners and evals
+- **`ctx.session.state`**: Accessible via `session` in completion event callbacks
+
+For most use cases, use `ctx.state`. Use `ctx.session.state` only when you need data in session completion events. See [Events & Lifecycle](/Build/Agents/events-lifecycle) for more on event handlers.
+
+
+Neither `ctx.state` nor `ctx.session.state` persist across requests. For data that should survive across requests, use `ctx.thread.state` (up to 1 hour) or [KV storage](/Build/Storage/key-value) (durable).
+
+
+## Persisting to Storage
+
+In-memory state is lost on server restart. For durability, combine state management with KV storage:
+
+### Load → Cache → Save Pattern
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import * as v from 'valibot';
+
+type Message = { role: 'user' | 'assistant'; content: string };
+
+const agent = createAgent('PersistentChat', {
+ schema: {
+ input: v.object({ message: v.string() }),
+ stream: true,
+ },
+ handler: async (ctx, input) => {
+ const key = `chat_${ctx.thread.id}`;
+ let messages: Message[] = [];
+
+ // Load from KV on first access in this thread
+ if (!(await ctx.thread.state.has('kvLoaded'))) {
+ const result = await ctx.kv.get('conversations', key);
+ if (result.exists) {
+ messages = result.data;
+ ctx.logger.info('Loaded conversation from KV', { messageCount: messages.length });
+ }
+ await ctx.thread.state.set('messages', messages);
+ await ctx.thread.state.set('kvLoaded', true);
+ } else {
+ messages = await ctx.thread.state.get('messages') || [];
+ }
+
+ // Add user message
+ messages.push({ role: 'user', content: input.message });
+
+ // Stream response
+ const result = streamText({
+ model: openai('gpt-5-mini'),
+ messages,
+ });
+
+ // Save in background (non-blocking)
+ ctx.waitUntil(async () => {
+ const fullText = await result.text;
+ messages.push({ role: 'assistant', content: fullText });
+
+ // Keep last 20 messages to bound state size
+ const recentMessages = messages.slice(-20);
+ await ctx.thread.state.set('messages', recentMessages);
+
+ // Persist to KV
+ await ctx.kv.set('conversations', key, recentMessages, {
+ ttl: 86400, // 24 hours
+ });
+ });
+
+ return result.textStream;
+ },
+});
+
+export default agent;
+```
+
+**Key points:**
+- Load from KV once per thread, cache in thread state
+- Use `ctx.waitUntil()` for non-blocking saves
+- Bound state size to prevent unbounded growth
+
+
+Thread state supports write-only operations without loading existing state. If you only call `set()`, `delete()`, or `push()` without any reads, the SDK batches these as a merge operation, avoiding the latency of fetching existing state.
+
+
+## Thread Lifecycle
+
+Threads expire after 1 hour of inactivity. Use the `destroyed` event to archive data before expiration:
+
+```typescript
+ctx.thread.addEventListener('destroyed', async (eventName, thread) => {
+ const messages = await thread.state.get('messages') || [];
+ if (messages.length > 0) {
+ await ctx.kv.set('archives', thread.id, {
+ messages,
+ endedAt: new Date().toISOString(),
+ }, { ttl: 604800 });
+ }
+});
+```
+
+Similarly, track when sessions complete with `ctx.session.addEventListener('completed', ...)`.
+
+For app-level monitoring of all threads and sessions, see [Events & Lifecycle](/Build/Agents/events-lifecycle).
+
+## Thread vs Session IDs
+
+| ID | Format | Lifetime | Purpose |
+|----|--------|----------|---------|
+| Thread ID | `thrd_` | Up to 1 hour (shared across requests) | Group related requests into conversations |
+| Session ID | `sess_` | Single request (unique per call) | Request tracing and analytics |
+
+```typescript
+handler: async (ctx, input) => {
+ ctx.logger.info('Request received', {
+ threadId: ctx.thread.id, // Same across conversation
+ sessionId: ctx.sessionId, // Unique per request
+ });
+
+ return { threadId: ctx.thread.id, sessionId: ctx.sessionId };
+}
+```
+
+## Advanced: Custom Thread IDs
+
+By default, thread IDs are generated automatically and managed via signed cookies. For advanced use cases, you can provide custom thread ID logic using a `ThreadIDProvider`.
+
+**Use cases:**
+- Integrating with external identity systems
+- Multi-tenant applications where threads should be scoped to users
+- Custom conversation management tied to your domain model
+
+### ThreadIDProvider Interface
+
+```typescript
+import type { Context } from 'hono';
+import type { Env, AppState } from '@agentuity/runtime';
+
+interface ThreadIDProvider {
+ getThreadId(appState: AppState, ctx: Context): string | Promise;
+}
+```
+
+### Thread ID Format Requirements
+
+Custom thread IDs must follow these rules:
+
+| Requirement | Value |
+|-------------|-------|
+| Prefix | Must start with `thrd_` |
+| Length | 32-64 characters total |
+| Characters | After prefix: `[a-zA-Z0-9]` only |
+
+```typescript
+// Valid thread IDs
+'thrd_abc123def456789012345678901' // 32 chars - minimum
+'thrd_' + 'a'.repeat(59) // 64 chars - maximum
+
+// Invalid thread IDs
+'thrd_abc' // Too short
+'thrd_abc-def-123' // Dashes not allowed
+'thread_abc123' // Wrong prefix
+```
+
+### Custom Provider Example
+
+Create a provider that generates deterministic thread IDs based on authenticated users:
+
+```typescript
+import { createApp, getThreadProvider } from '@agentuity/runtime';
+import type { ThreadIDProvider } from '@agentuity/runtime';
+
+const userThreadProvider: ThreadIDProvider = {
+ getThreadId: async (appState, ctx) => {
+ const userId = ctx.req.header('x-user-id');
+
+ if (userId) {
+ // Create deterministic thread ID from user ID
+ const data = new TextEncoder().encode(userId);
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
+ const hex = Array.from(new Uint8Array(hashBuffer))
+ .map(b => b.toString(16).padStart(2, '0'))
+ .join('')
+ .slice(0, 27);
+ return `thrd_${hex}`;
+ }
+
+ // Fall back to random ID for unauthenticated requests
+ const arr = new Uint8Array(16);
+ crypto.getRandomValues(arr);
+ return `thrd_${Array.from(arr).map(b => b.toString(16).padStart(2, '0')).join('')}`;
+ }
+};
+
+await createApp({
+ setup: () => {
+ getThreadProvider().setThreadIDProvider(userThreadProvider);
+ return {};
+ }
+});
+```
+
+### Default Thread ID Behavior
+
+The built-in `DefaultThreadIDProvider` handles thread IDs automatically:
+
+1. **Check header**: Looks for signed `x-thread-id` header
+2. **Check cookie**: Falls back to signed `atid` cookie
+3. **Generate new**: Creates a new random thread ID if neither exists
+4. **Persist**: Sets both the response header and cookie for future requests
+
+The signing uses `AGENTUITY_SDK_KEY` (or defaults to `'agentuity'` in development) with HMAC SHA-256 to prevent tampering.
+
+### Client-Side Thread Persistence
+
+When building frontends, you can maintain thread continuity by storing and sending the thread ID:
+
+```typescript
+// Client-side: store thread ID from response header
+const response = await fetch('/api/chat', { method: 'POST', body: message });
+const threadId = response.headers.get('x-thread-id');
+localStorage.setItem('threadId', threadId);
+
+// Subsequent requests: send thread ID header
+const nextResponse = await fetch('/api/chat', {
+ method: 'POST',
+ headers: { 'x-thread-id': localStorage.getItem('threadId') },
+ body: nextMessage
+});
+```
+
+
+The `x-thread-id` header must include the signature (format: `threadId;signature`). Use the exact value from the response header. Unsigned or tampered thread IDs are rejected.
+
+
+## State Size Limits
+
+
+Thread and session state are limited to **1MB** after JSON serialization. Values that exceed this limit are truncated with a warning. Non-JSON-serializable values (functions, circular references) are silently dropped.
+
+
+To stay within limits:
+- Store large data in [KV storage](/Build/Storage/key-value) instead of state
+- Keep only recent messages (e.g., last 20-50)
+- Store IDs or references rather than full objects
+
+## Best Practices
+
+- **Use the right scope**: `ctx.state` for request-scoped data, `ctx.thread.state` for conversations
+- **Keep state bounded**: Limit conversation history (e.g., last 20-50 messages)
+- **Persist important data**: Don't rely on state for data that must survive restarts
+- **Clean up resources**: Use `destroyed` event to save or archive data
+- **Cache strategically**: Load from KV once, cache in thread state, save on completion
+- **Watch state size**: Stay under 1MB to avoid truncation
+- **Use `push()` for arrays**: The `push()` method with `maxRecords` handles sliding windows efficiently
+
+```typescript
+// Good: Use push() with maxRecords for bounded history
+await ctx.thread.state.push('messages', newMessage, 50); // Keeps last 50
+
+// Alternative: Manual bounding when you need the full array
+const messages = await ctx.thread.state.get('messages') || [];
+if (messages.length > 50) {
+ const archived = messages.slice(0, -50);
+ ctx.waitUntil(async () => {
+ await ctx.kv.set('archives', `${ctx.thread.id}_${Date.now()}`, archived);
+ });
+ await ctx.thread.state.set('messages', messages.slice(-50));
+}
+```
+
+## Next Steps
+
+- [Key-Value Storage](/Build/Storage/key-value): Durable data persistence with namespaces and TTL
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Share state between agents in workflows
+- [Events & Lifecycle](/Build/Agents/events-lifecycle): Monitor agent execution and cleanup
diff --git a/content/Agents/streaming-responses.mdx b/content/Agents/streaming-responses.mdx
new file mode 100644
index 00000000..b145e9d3
--- /dev/null
+++ b/content/Agents/streaming-responses.mdx
@@ -0,0 +1,233 @@
+---
+title: Returning Streaming Responses
+description: Return real-time LLM output with streaming agents
+---
+
+Show LLM output as it's generated instead of waiting for the full response. Streaming reduces perceived latency and creates a more responsive experience.
+
+## Streaming Types
+
+Agentuity supports two streaming patterns:
+
+### Ephemeral Streaming
+
+Uses `stream()` middleware for direct streaming to the HTTP client. Data flows through and is not stored. Use this for real-time chat responses.
+
+```typescript
+// In src/api/index.ts
+import { createRouter, stream } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/', stream(async (c) => {
+ return await chatAgent.run({ message: '...' });
+}));
+
+export default router;
+```
+
+### Persistent Streaming
+
+Uses `ctx.stream.create()` to create stored streams with public URLs. Data persists and can be accessed after the connection closes. Use this for batch processing, exports, or content that needs to be accessed later.
+
+```typescript
+// In agent.ts
+const stream = await ctx.stream.create('my-export', {
+ contentType: 'text/csv',
+});
+await stream.write('data');
+await stream.close();
+```
+
+This page focuses on ephemeral streaming with the AI SDK. For persistent streaming patterns, see the [Storage documentation](/Build/Storage/durable-streams).
+
+
+Streaming requires both: `schema.stream: true` in your agent (so the handler returns a stream) and `stream()` middleware in your route (so the response is streamed to the client).
+
+
+## Basic Streaming
+
+Enable streaming by setting `stream: true` in your schema and returning a `textStream`:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { anthropic } from '@ai-sdk/anthropic';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('ChatStream', {
+ schema: {
+ input: s.object({ message: s.string() }),
+ stream: true,
+ },
+ handler: async (ctx, input) => {
+ const { textStream } = streamText({
+ model: anthropic('claude-sonnet-4-5'),
+ prompt: input.message,
+ });
+
+ return textStream;
+ },
+});
+
+export default agent;
+```
+
+## Route Configuration
+
+Use `stream()` middleware to handle streaming responses:
+
+```typescript
+// src/api/index.ts
+import { createRouter, stream } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chatAgent.validator(), stream(async (c) => {
+ const body = c.req.valid('json');
+ return chatAgent.run(body);
+}));
+
+export default router;
+```
+
+
+Use `stream()` middleware for streaming agents. Regular `router.post()` works but may buffer the response depending on the client.
+
+
+## Consuming Streams
+
+### With Fetch API
+
+Read the stream using the Fetch API:
+
+```typescript
+const response = await fetch('http://localhost:3500/api/chat', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ message: 'Tell me a story' }),
+});
+
+const reader = response.body?.getReader();
+const decoder = new TextDecoder();
+
+while (reader) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const text = decoder.decode(value);
+ // Process each chunk as it arrives
+ appendToUI(text);
+}
+```
+
+### With React
+
+Use the `useAPI` hook from `@agentuity/react`:
+
+```tsx
+import { useAPI } from '@agentuity/react';
+
+function Chat() {
+ const { data, isLoading, invoke } = useAPI('POST /api/chat');
+
+ const handleSubmit = async (message: string) => {
+ await invoke({ message });
+ };
+
+ return (
+
+ {isLoading &&
Generating...
}
+ {data &&
{data}
}
+
handleSubmit('Hello!')}>Send
+
+ );
+}
+```
+
+For streaming with React, see [Frontend Hooks](/Build/Frontend/react-hooks).
+
+## Streaming with System Prompts
+
+Add context to streaming responses:
+
+```typescript
+handler: async (ctx, input) => {
+ const { textStream } = streamText({
+ model: anthropic('claude-sonnet-4-5'),
+ system: 'You are a helpful assistant. Be concise.',
+ messages: [
+ { role: 'user', content: input.message },
+ ],
+ });
+
+ return textStream;
+}
+```
+
+## Streaming with Conversation History
+
+Combine streaming with thread state for multi-turn conversations:
+
+```typescript
+handler: async (ctx, input) => {
+ // Get existing messages from thread state (async)
+ const messages = (await ctx.thread.state.get('messages')) || [];
+
+ // Add new user message
+ messages.push({ role: 'user', content: input.message });
+
+ const { textStream, text } = streamText({
+ model: anthropic('claude-sonnet-4-5'),
+ messages,
+ });
+
+ // Save assistant response after streaming completes
+ ctx.waitUntil(async () => {
+ const fullText = await text;
+ messages.push({ role: 'assistant', content: fullText });
+ await ctx.thread.state.set('messages', messages);
+ });
+
+ return textStream;
+}
+```
+
+
+Use `ctx.waitUntil()` to save conversation history without blocking the stream. The response starts immediately while state updates happen in the background.
+
+
+## When to Stream
+
+| Scenario | Recommendation |
+|----------|----------------|
+| Chat interfaces | Stream for better UX |
+| Long-form content | Stream to show progress |
+| Quick classifications | Buffer (faster overall, consider Groq for speed) |
+| Structured data | Buffer (use `generateObject`) |
+
+## Error Handling
+
+Handle streaming errors with the `onError` callback:
+
+```typescript
+const { textStream } = streamText({
+ model: anthropic('claude-sonnet-4-5'),
+ prompt: input.message,
+ onError: (error) => {
+ ctx.logger.error('Stream error', { error });
+ },
+});
+```
+
+
+Errors in streaming are part of the stream, not thrown exceptions. Always provide an `onError` callback.
+
+
+## Next Steps
+
+- [Using the AI SDK](/Build/Agents/ai-sdk-integration): Structured output and non-streaming responses
+- [State Management](/Build/Agents/state-management): Multi-turn conversations with memory
+- [Server-Sent Events](/Build/Routes/sse): Server-push updates without polling
diff --git a/content/Agents/workbench.mdx b/content/Agents/workbench.mdx
new file mode 100644
index 00000000..f3890bf8
--- /dev/null
+++ b/content/Agents/workbench.mdx
@@ -0,0 +1,133 @@
+---
+title: Testing with Workbench
+description: Use the built-in development UI to test agents, validate schemas, and debug responses
+---
+
+Workbench is a built-in UI for testing your agents during development. It automatically discovers your agents, displays their input/output schemas, and lets you execute them with real inputs.
+
+## Enabling Workbench
+
+Add a `workbench` section to your `agentuity.config.ts`:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/workbench',
+ headers: {},
+ },
+} satisfies AgentuityConfig;
+```
+
+Start the dev server and visit [http://localhost:3500/workbench](http://localhost:3500/workbench).
+
+
+Workbench is only available in development mode (`agentuity dev`). It is not included in production builds.
+
+
+## Adding Test Prompts
+
+Export a `welcome` function from your agent to customize Workbench:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('Support Agent', {
+ schema: {
+ input: z.object({ message: z.string() }),
+ output: z.object({ response: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Agent logic
+ return { response: 'Hello!' };
+ },
+});
+
+export const welcome = () => ({
+ welcome: `Welcome to the **Support Agent**.
+
+Ask questions about your account, billing, or technical issues.`,
+ prompts: [
+ {
+ data: JSON.stringify({ message: 'How do I reset my password?' }),
+ contentType: 'application/json',
+ },
+ {
+ data: JSON.stringify({ message: 'What are your business hours?' }),
+ contentType: 'application/json',
+ },
+ ],
+});
+
+export default agent;
+```
+
+The `welcome` field supports Markdown. The `prompts` array provides quick-test buttons in the UI.
+
+## What You See
+
+Workbench displays:
+
+- **Agent selector**: Switch between agents in your project
+- **Input schema**: See what fields the agent expects
+- **Output schema**: See what the agent returns
+- **Execution metrics**: Token usage and response time
+- **Response viewer**: Formatted output with copy support
+
+## Thread Persistence
+
+Workbench maintains thread state across requests, allowing you to test multi-turn conversations. Each browser tab gets its own thread, and state persists until you close the tab.
+
+Test conversational agents that use thread state:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('Chat', {
+ schema: {
+ input: z.object({ message: z.string() }),
+ output: z.object({ response: z.string(), turnCount: z.number() }),
+ },
+ handler: async (ctx, input) => {
+ // Initialize turn count on first request (async)
+ if (!(await ctx.thread.state.has('turns'))) {
+ await ctx.thread.state.set('turns', 0);
+ }
+
+ const turns = ((await ctx.thread.state.get('turns')) || 0) + 1;
+ await ctx.thread.state.set('turns', turns);
+
+ return {
+ response: `You said: ${input.message}`,
+ turnCount: turns,
+ };
+ },
+});
+
+export default agent;
+```
+
+Send multiple requests in Workbench to see the turn count increment.
+
+## Custom Route
+
+Serve Workbench at a different path:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/dev',
+ },
+} satisfies AgentuityConfig;
+```
+
+## Next Steps
+
+- [Workbench Configuration](/Build/Frontend/workbench): Configuration options and embedding in custom frontends
+- [Creating Agents](/Build/Agents/creating-agents): Agent patterns and best practices
+- [Local Development](/Reference/CLI/development): Dev server options
diff --git a/content/Build/meta.json b/content/Build/meta.json
new file mode 100644
index 00000000..66bd96cb
--- /dev/null
+++ b/content/Build/meta.json
@@ -0,0 +1,4 @@
+{
+ "title": "Build",
+ "pages": ["Agents", "Routes", "APIs", "Frontend", "Storage", "Sandbox", "Observability"]
+}
diff --git a/content/CLI/agent.mdx b/content/CLI/agent.mdx
deleted file mode 100644
index a1a0ec61..00000000
--- a/content/CLI/agent.mdx
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: Agent Commands
-description: Commands for managing agents
----
-
-The `agent` commands allow you to create, list, delete, and manage agents in your Agentuity project.
-
-## Commands
-
-### agent create
-
-Creates a new agent in your project.
-
-**Aliases:** new
-
-**Usage**
-
-
-
-**Arguments:**
-- `name` - The name of the agent
-- `description` - A description of what the agent does
-- `auth_type` - Authentication method for the agent (API Key or None)
-
-**Flags:**
-- `-d, --dir string` - The project directory
-
-This command will prompt you for:
-- The name of the agent
-- A description of what the agent does
-- Authentication type (API Key or None)
-
-After providing this information, the command will:
-1. Create the agent in the Agentuity Cloud
-2. Set up the necessary local files for the agent
-3. Update your project configuration to include the new agent
-
-**Example**
-
-
- What should we name the agent? MyNewAgent
- How should we describe what the MyNewAgent agent does? This agent processes customer support requests
- ✓ Agent created successfully
-
-
-### agent list
-
-Lists all agents in your project.
-
-**Aliases:** ls
-
-**Usage**
-
-
-
-**Flags:**
-- `-d, --dir string` - The project directory
-
-This command will display a list of all agents in your project, including:
-- Agent name
-- Agent ID
-- Agent description
-- Status (whether the agent exists locally, remotely, or both)
-
-**Example**
-
-
-src/agents
-├── MyFirstAgent
-│ ├── ID: 3c4c0b692533d7807cf0f649ef425dfa29b58bcc99be03e208e52749107fca2e
-│ └── Description: A simple agent that can generate text
-│
-└── MyNewAgent
- ├── ID: 7a8b9c0d1e2f3g4h5i6j7k8l9m0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d7e8f
- └── Description: This agent processes customer support requests
-
-
-### agent delete
-
-Deletes one or more agents from your project.
-
-**Aliases:** rm, del
-
-**Usage**
-
-
-
-**Flags:**
-- `-d, --dir string` - The project directory
-
-This command will:
-1. Display a list of all agents in your project
-2. Allow you to select one or more agents to delete
-3. Ask for confirmation before deleting the selected agents
-4. Delete the selected agents from both the Agentuity Cloud and your local project
-
-**Example**
-
-
-Select one or more agents to delete:
-[ ] MyFirstAgent 3c4c0b692533d7807cf0f649ef425dfa29b58bcc99be03e208e52749107fca2e
-[x] MyNewAgent 7a8b9c0d1e2f3g4h5i6j7k8l9m0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d7e8f
-
-Are you sure you want to delete the selected agents? This action cannot be undone. [y/N] y
-✓ Agent deleted successfully
-
-
-### agent apikey
-
-Gets the API key for an agent.
-
-**Aliases:** key
-
-**Usage**
-
-
-
-**Arguments:**
-- `agent_name` - The name or ID of the agent (optional)
-
-**Flags:**
-- `-d, --dir string` - The project directory
-
-This command will:
-1. If an agent name is provided, retrieve the API key for that agent
-2. If no agent name is provided and there's only one agent in the project, retrieve the API key for that agent
-3. If no agent name is provided and there are multiple agents, display a list of agents to select from
-
-**Example**
-
-Get an API key for a specific agent:
-
-
-✓ Agent MyFirstAgent API key: apikey_1234567890abcdefghijklmnopqrstuvwxyz
-
-
-Get an API key for an agent interactively:
-
-
-Select an Agent:
- [x] MyFirstAgent 3c4c0b692533d7807cf0f649ef425dfa29b58bcc99be03e208e52749107fca2e
- [ ] MyNewAgent 7a8b9c0d1e2f3g4h5i6j7k8l9m0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d7e8f
-
-✓ Agent MyFirstAgent API key: apikey_1234567890abcdefghijklmnopqrstuvwxyz
-
-
-## Global Flags
-
-These flags apply to all agent commands:
-
-- `--config string` - Config file (default is `$HOME/.config/agentuity/config.yaml`)
-- `--log-level string` - The log level to use (default "info")
diff --git a/content/CLI/apikey.mdx b/content/CLI/apikey.mdx
deleted file mode 100644
index 78e27f1c..00000000
--- a/content/CLI/apikey.mdx
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: API Key Commands
-description: Commands for managing API keys
----
-
-The `apikey` commands allow you to create, list, delete, and manage API keys for authentication with the Agentuity Cloud Platform.
-
-## apikey
-
-Base command for API key management.
-
-
-
-**Aliases:** apikeys
-
-**Examples:**
-
-
-
-
-## apikey create
-
-Creates a new API key for use with the Agentuity Cloud Platform.
-
-
-
-**Aliases:** new, add
-
-**Flags:**
-- `--expires-at string` - The expiration date of the API key
-- `--format string` - The format to output the API key in (default "text")
-- `-h, --help` - help for create
-- `-o, --org-id string` - The organization ID to associate the API key with
-- `-p, --project-id string` - The project ID to associate the API key with
-
-## apikey delete
-
-Deletes an existing API key.
-
-
-
-**Aliases:** rm, del
-
-Specify an optional API key ID to delete a specific API key or choose from a list of API keys.
-
-## apikey get
-
-Retrieves information about a specific API key.
-
-
-
-**Aliases:** None
-
-Specify an optional API key ID to get a specific API key or choose from a list of API keys.
-
-**Flags:**
-- `--format string` - The format to output the API key in (default "text")
-- `-h, --help` - help for get
-- `-m, --mask` - Mask the API key value
-
-## apikey list
-
-Lists all available API keys for your account.
-
-
-
-**Aliases:** None
-
-**Flags:**
-- `--format string` - The format to output the API key in (default "text")
-- `-h, --help` - help for list
-- `-m, --mask` - Mask the API key value
-- `-o, --org-id string` - The organization ID to filter by
-- `-p, --project-id string` - The project ID to filter by
\ No newline at end of file
diff --git a/content/CLI/auth.mdx b/content/CLI/auth.mdx
deleted file mode 100644
index a07b08bc..00000000
--- a/content/CLI/auth.mdx
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Authentication Commands
-description: Commands for authenticating with Agentuity
----
-
-The `auth` commands allow you to authenticate with the Agentuity Cloud Platform, manage your login session, and check your authentication status.
-
-## auth login
-
-Logs you into the Agentuity Cloud Platform.
-
-**Aliases:** login
-
-**Usage**
-
-
-
-This command will print out a one-time code and a link to a URL where you can log in to your Agentuity account and provide the one-time code.
-
-After successful authentication, your credentials will be stored locally for future use. By default, the credentials and other configuration are stored in the following file: `$HOME/.config/agentuity/config.yaml`.
-
-**Example**
-
-
-✓ You are now logged in
-
-
-## auth logout
-
-Logs you out of the Agentuity Cloud Platform.
-
-**Aliases:** logout
-
-**Usage**
-
-
-
-This command will remove your stored credentials.
-
-**Example**
-
-
-✓ You have been logged out
-
-
-## auth whoami
-
-Displays information about the currently logged-in user.
-
-**Aliases:** whoami
-
-**Usage**
-
-
-
-**Example**
-
-
-╭──────────────────────────────────────────────────────────────────────────────────╮
-│ │
-│ Currently logged in as │
-│ │
-│ Name: Your Name user_0123456789abcedefghijklmnop │
-│ │
-│ Organization: Your Organization org_0123456789abcdefghijklmnopq │
-│ │
-╰──────────────────────────────────────────────────────────────────────────────────╯
-
diff --git a/content/CLI/bundle.mdx b/content/CLI/bundle.mdx
deleted file mode 100644
index 0eb3a247..00000000
--- a/content/CLI/bundle.mdx
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: Bundle Command
-description: Command for bundling agents for deployment
----
-
-The `bundle` command allows you to create a bundled version of your Agentuity project for deployment.
-
-## bundle
-
-Runs the build bundle process for an Agentuity project.
-
-**Aliases:** build
-
-**Usage**
-
-
-
-**Flags:**
-- `--deploy` - Whether to deploy after bundling
-- `-d, --dir string` - The directory to the project (default ".")
-- `-h, --help` - help for bundle
-- `-i, --install` - Whether to install dependencies before bundling
-- `-p, --production` - Whether to bundle for production
-
-> You generally don't need to use this command as it is automatically called when you run `agentuity dev` or `agentuity deploy`.
\ No newline at end of file
diff --git a/content/CLI/cloud.mdx b/content/CLI/cloud.mdx
deleted file mode 100644
index 5c19ecf9..00000000
--- a/content/CLI/cloud.mdx
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: Cloud Commands
-description: Commands for deploying and managing agents
----
-
-The `cloud` commands allow you to deploy and manage your projects in the Agentuity Cloud Platform.
-
-## cloud deploy
-
-Deploys a project to the Agentuity Cloud Platform.
-
-**Aliases:** deploy
-
-**Usage**
-
-
-
-**Flags:**
-- `--description string` - Description for the deployment
-- `-d, --dir string` - The directory to the project to deploy (default ".")
-- `--force` - Force the processing of environment files
-- `--format string` - The output format to use for results which can be either 'text' or 'json' (default "text")
-- `-h, --help` - help for deploy
-- `--message string` - A shorter description for the deployment
-- `--org-id string` - The organization to create the project in
-- `--tag stringArray` - Tag(s) to associate with this deployment (can be specified multiple times)
-- `--templates-dir string` - The directory to load the templates. Defaults to loading them from the github.com/agentuity/templates repository
-
-**Examples**
-
-Deploy a project from the current directory:
-
-
-✓ Project deployed successfully
-
-
-Deploy a project from a specific directory:
-
-
-✓ Project deployed successfully
-
-
-## cloud rollback
-
-Rolls back a project to a previous version.
-
-**Usage**
-
-
-
-**Flags:**
-- `--delete` - Delete the deployment instead of rolling back
-- `--dir string` - The directory to the project to rollback if project is not specified
-- `--force` - Force the rollback or delete
-- `-h, --help` - help for rollback
-- `--project string` - Project to rollback a deployment
-- `--tag string` - Tag of the deployment to rollback
-
-**Examples**
-
-Rollback the most recent deployment:
-
-
-✓ Deployment rolled back successfully
-
-
-Rollback a project to a specific tag:
-
-
-✓ Deployment rolled back successfully
-
-
-Rollback and delete the most recent deployment:
-
-
-✓ Deployment rolled back successfully
-
diff --git a/content/CLI/dev.mdx b/content/CLI/dev.mdx
deleted file mode 100644
index f7686b75..00000000
--- a/content/CLI/dev.mdx
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Development Commands
-description: Commands for local development of agents using DevMode
----
-
-The `dev` commands allow you to run and test your Agentuity projects locally during development using DevMode.
-
-## dev
-
-Runs a development server for local testing and development.
-
-**Aliases:** run
-
-**Usage**
-
-
-
-**Flags:**
-- `-d, --dir string` - The directory to run the development server in (default ".")
-- `-h, --help` - help for dev
-- `--port int` - The port to run the development server on (uses project default if not provided)
-
-**Examples**
-
-Run a development server for a project in the current directory:
-
-
-✓ Development server started
-
-
-Run a development server for a project in a specific directory:
-
-
-✓ Development server started
-
-
-> See the [DevMode](/Guides/devmode) documentation for more information on how to use DevMode.
\ No newline at end of file
diff --git a/content/CLI/env.mdx b/content/CLI/env.mdx
deleted file mode 100644
index bbfe76c1..00000000
--- a/content/CLI/env.mdx
+++ /dev/null
@@ -1,123 +0,0 @@
----
-title: Environment Commands
-description: Commands for managing environment variables and secrets
----
-
-The `env` commands allow you to manage environment variables and secrets for your Agentuity projects.
-
-## env set
-
-Sets environment variables or secrets for a project.
-
-**Usage**
-
-
-
-**Aliases:** put, add
-
-**Flags:**
-- `-d, --dir string` - The directory to the project to deploy (default ".")
-- `-f, --file string` - The path to a file containing environment variables to set
-- `--force` - Don't prompt for confirmation
-- `-h, --help` - help for set
- -s, --secret Force the value(s) to be treated as a secret
-
-**Examples**
-
-Set a single environment variable:
-
-
-✓ Environment variable saved
-
-
-Set a secret:
-
-
-✓ Secret saved
-
-
-Set environment variables from a file:
-
-
-✓ Environment variables and secrets saved
-
-
-
-All environment and secret values are encrypted at rest and in transit.
-
-
-
-Secrets are like passwords. They should be treated as such. Never share them with anyone. Never store them in a source code repository. Never store them in a file that is not encrypted.
-
-
-## env list
-
-Lists all environment variables and secrets for a project.
-
-**Usage**
-
-
-
-**Aliases:** ls, show, print
-
-**Flags:**
-- `-d, --dir string` - The directory to the project to deploy (default ".")
-- `--format string` - The format to use for the output. Can be either 'text' or 'json' (default "text")
-- `-h, --help` - help for list
-
-**Examples**
-
-
-API_KEY=your-api-key
-DB_PASSWORD=********
-
-
-## env get
-
-Gets the value of an environment variable or secret.
-
-**Usage**
-
-
-
-**Flags:**
-- `-d, --dir string` - The directory to the project to deploy (default ".")
-- `--format string` - The format to use for the output. Can be either 'text' or 'json' (default "text")
-- `-h, --help` - help for list
-
-**Examples**
-
-
-your-api-key
-
-
-## env delete
-
-Deletes environment variables or secrets.
-
-**Usage**
-
-
-
-**Aliases:** rm, del
-
-**Flags:**
-- `-d, --dir string` - The directory to the project to deploy (default ".")
-- `--force` - Don't prompt for confirmation
-- `-h, --help` - help for delete
-
-**Examples**
-
-Delete a single environment variable:
-
-
-✓ Environment variable deleted
-
-
-Delete multiple environment variables:
-
-
-✓ Environment variables and secrets deleted
-
-
-> You can also manage your environment variables and secrets in the [Console](/Cloud/api-keys).
\ No newline at end of file
diff --git a/content/CLI/installation.mdx b/content/CLI/installation.mdx
deleted file mode 100644
index 7a26a754..00000000
--- a/content/CLI/installation.mdx
+++ /dev/null
@@ -1,113 +0,0 @@
----
-title: Installation
-description: Insructions for installing the CLI
----
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-The Agentuity CLI is a command line tool for managing your Agentuity projects. It's a cross-platform tool that can be used on Windows (using WSL), MacOS, and Linux.
-
-### Install Script
-
-The easiest way to install the Agentuity CLI is to use the install script. This script will automatically detect your operating system and install the appropriate version of the CLI.
-
-
-
-
- The install script for Windows only works in the WSL (Windows Subsystem for Linux) environment
-
-
-
- On MacOS, if you have Homebrew installed, the install script will automatically use brew for installation.
-
-
-### Version
-
-To print the version of the Agentuity CLI:
-
-
-
-You can also use the `-v` flag to print the version:
-
-
-
-To check if you have the latest version of the Agentuity CLI:
-
-
-
-### Upgrading
-
-To upgrade to the latest version of the Agentuity CLI:
-
-
-
-For more details on the `version` command, see the [CLI Version Commands](/CLI/version).
-
-## Manual Installation
-
-You can also manually download and install the Agentuity CLI from the [GitHub releases page](https://github.com/agentuity/cli/releases) for any platform:
-
-1. Visit the [Agentuity CLI releases page](https://github.com/agentuity/cli/releases)
-2. Download the appropriate version for your operating system
-3. Extract the downloaded file
-4. Add the executable to your system PATH
-
-## Source Code
-
-The source code for the Agentuity CLI is available on [GitHub](https://github.com/agentuity/cli).
-
-## Shell Completions
-
-The Agentuity CLI provides shell completions for bash, zsh, fish, and PowerShell. These can help make your command line experience more efficient by providing tab-completion for commands and options.
-
-### Automatic Setup
-
-When you install the CLI using the installer scripts, completions are automatically set up for:
-- **Bash and Zsh** on MacOS and Linux (when you have write permissions to the completion directories)
-
-### Manual Setup
-
-You can manually set up completions for any supported shell using the `agentuity completion` command.
-
-
-
- To load completions in your current bash session:
-
-
-
- To load completions for every new session:
-
- For Linux:
-
-
- For MacOS:
-
-
- Note: This depends on the `bash-completion` package. If not already installed, you can install it via your OS's package manager.
-
-
- To load completions in your current zsh session:
-
-
-
- To load completions for every new session:
-
- For Linux:
-
-
- For MacOS:
-
-
- If shell completion is not already enabled in your environment, you need to enable it:
-
-
-
-
- To load completions in your current fish session:
-
-
-
- To load completions for every new session:
-
-
-
-
diff --git a/content/CLI/mcp.mdx b/content/CLI/mcp.mdx
deleted file mode 100644
index 030e3cdb..00000000
--- a/content/CLI/mcp.mdx
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: MCP Commands
-description: Commands for the Model Context Protocol (MCP) integration
----
-
-The `mcp` commands allow you to install and manage the Agentuity MCP server.
-
-The Agentuity CLI implements the Model Context Protocol (MCP), which allows integration with AI-powered code editors and tools. This integration enhances the capabilities of AI agents inside supported clients.
-The MCP server is automatically installed when you install the Agentuity CLI.
-
-For more information on the MCP protocol, see [https://modelcontextprotocol.io/](https://modelcontextprotocol.io/)
-
-## Commands
-
-### mcp
-
-The base command for all MCP-related operations.
-
-
-
-**Aliases:** None
-
-**Examples:**
-
-
-
-
-
-### mcp install
-
-Installs the Agentuity CLI as an MCP server, enabling integration with supported MCP clients.
-
-
-
-**Aliases:** i, add
-
-**Examples:**
-
-
-### mcp uninstall
-
-Uninstalls the Agentuity CLI as an MCP server, removing integration with MCP clients.
-
-
-
-**Aliases:** rm, delete, del, remove
-
-**Examples:**
-
-
-### mcp list
-
-Lists all MCP server configurations detected on the machine, showing which clients are configured.
-
-
-
-**Aliases:** ls
-
-**Examples:**
-
-
-
-## Manual Installation
-
-If you need to manually configure an MCP client, you can use the following command:
-
-
-
-This command is typically used for advanced configuration scenarios.
diff --git a/content/CLI/meta.json b/content/CLI/meta.json
deleted file mode 100644
index 684e52f1..00000000
--- a/content/CLI/meta.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "title": "CLI",
- "pages": ["installation", "..."]
-}
diff --git a/content/CLI/project.mdx b/content/CLI/project.mdx
deleted file mode 100644
index 1035f09d..00000000
--- a/content/CLI/project.mdx
+++ /dev/null
@@ -1,101 +0,0 @@
----
-title: Project Commands
-description: Commands for creating and managing projects
----
-
-The `project` commands allow you to create and manage Agentuity projects.
-
-## project create
-
-Creates a new Agentuity project.
-
-**Aliases:** create, new
-
-**Usage**
-
-
-
-**Flags:**
-- `--action string` - The action to take for the project (github-action, github-app, none) (default "github-app")
-- `--auth string` - The authentication type for the agent (project, webhook, or none) (default "project")
-- `-d, --dir string` - The directory for the project
-- `--force` - Force the project to be created even if the directory already exists
-- `--format string` - The format to use for the output. Can be either 'text' or 'json' (default "text")
-- `-h, --help` - help for create
-- `--org-id string` - The organization to create the project in
-- `-r, --runtime string` - The runtime to use for the project
-- `-t, --template string` - The template to use for the project
-- `--templates-dir string` - The directory to load the templates. Defaults to loading them from the github.com/agentuity/templates repository
-
-**Examples**
-
-Create a new project with interactive prompts:
-
-
-✓ Project created successfully
-
-
-## project list
-
-Lists all projects in your Agentuity account.
-
-**Aliases:** ls
-
-**Usage**
-
-
-
-**Examples**
-
-
-Projects:
- my-project (proj_123456)
- test-project (proj_789012)
- demo-app (proj_345678)
-
-
-## project delete
-
-Deletes one or more projects from your Agentuity account.
-
-**Aliases**: rm, del
-
-**Usage**
-
-
-
-This command will:
-1. Display a list of all projects in your account
-2. Allow you to select one or more projects to delete
-3. Ask for confirmation before deleting the selected projects
-
-**Examples**
-
-
-Select one or more projects to delete:
-[ ] my-project (proj_123456)
-[x] test-project (proj_789012)
-[ ] demo-app (proj_345678)
-
-Are you sure you want to delete the selected projects? This action cannot be undone. [y/N] y
-✓ Project deleted successfully
-
-
-## project import
-
-Imports an existing Agentuity project into your Agentuity account.
-
-**Usage**
-
-
-
-**Flags:**
-- `-d, --dir string` - The directory for the project
-- `--force` - Force the processing of environment files
-- `-h, --help` - help for import
-
-**Examples**
-
-
-✓ Project imported successfully
-
diff --git a/content/CLI/version.mdx b/content/CLI/version.mdx
deleted file mode 100644
index f7e440ad..00000000
--- a/content/CLI/version.mdx
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Version Commands
-description: Commands for checking the version of the CLI
----
-
-The `version` command allows you to check, display, and upgrade the Agentuity CLI version.
-
-## version
-
-Displays the version of the Agentuity CLI.
-
-**Aliases:** -v, --version
-
-**Usage**
-
-
-
-**Flags:**
-- `-h, --help` - help for version
-- `--long` - Print the long version
-
-**Examples**
-
-Basic version information:
-
-0.0.139
-
-
-Detailed version information:
-
-Version: 0.0.139
-Commit: 1633cea4fa7c0841605f3d4d501425e4068fae79
-Date: 2025-05-24T03:41:26Z
-
-
-## check
-
-Checks if you're using the latest version of the Agentuity CLI.
-
-**Usage**
-
-
-
-**Flags:**
-- `-h, --help` - help for check
-- `--upgrade` - Upgrade to the latest version if possible
-
-**Examples**
-
-Check if you're using the latest version:
-
-
- ✓ You are using the latest version (0.0.139) of the Agentuity CLI.
-
-
-Check and upgrade to the latest version:
-
- ✓ A new version (0.0.139) of the Agentuity CLI is available. Upgrading...
- ✓ Successfully upgraded to version 0.0.139.
-
-
-## upgrade
-
-Upgrades the Agentuity CLI to the latest version. This command is also available as `agentuity upgrade`.
-
-**Usage**
-
-
-
-**Aliases:** upgrade, update
-
-**Flags:**
-- `--force` - Force upgrade even if already on the latest version
-- `-h, --help` - help for upgrade
-
-**Examples**
-
-Upgrade to the latest version:
-
- ✓ Checking for updates...
- ✓ A new version (0.0.139) is available. Upgrading...
- ✓ Creating backup of current binary...
- ✓ Successfully upgraded to version 0.0.139.
-
-
-Force upgrade:
-
- ✓ Creating backup of current binary...
- ✓ Successfully upgraded to version 0.0.139.
-
-
-> On MacOS, if the CLI was installed using Homebrew, it will use Homebrew to perform the upgrade.
diff --git a/content/Changelog/cli.mdx b/content/Changelog/cli.mdx
deleted file mode 100644
index ef0a88e3..00000000
--- a/content/Changelog/cli.mdx
+++ /dev/null
@@ -1,1339 +0,0 @@
----
-title: CLI Changelog
-description: Release notes and version history for the Agentuity CLI
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-This page documents the release history of the [Agentuity CLI](https://github.com/agentuity/cli).
-## v0.0.175
-
-
- Released: October 13, 2025
-
-
-**Changes:**
-- **Changed**: Bump go-common to remove gravity log ([#466](https://github.com/agentuity/cli/pull/466))
-
-
-
-## v0.0.176
-
-
- Released: October 14, 2025
-
-
-**Changes:**
-- **Changed**: Add breaking change check for 0.0.154 ([#470](https://github.com/agentuity/cli/pull/470))
-- **Changed**: Remove [gravity] log prefix ([#467](https://github.com/agentuity/cli/pull/467))
-
-## v0.0.175
-
-
- Released: October 13, 2025
-
-
-**Changes:**
-- **Changed**: Bump go-common to remove gravity log ([#466](https://github.com/agentuity/cli/pull/466))
-
-## v0.0.174
-
-
- Released: October 10, 2025
-
-
-**Changes:**
-- **Changed**: Updated go-common dependency to v1.0.103
-
-## v0.0.173
-
-
- Released: October 10, 2025
-
-
-**Changes:**
-- **Added**: Add support for automatic bundling of native external modules ([#458](https://github.com/agentuity/cli/pull/458))
-- **Changed**: DevMode 2.0 ([#449](https://github.com/agentuity/cli/pull/449))
-- **Fixed**: Fix duplicate Agentuity keys in .env file creation ([#459](https://github.com/agentuity/cli/pull/459))
-
-
-## v0.0.172
-
-
- Released: October 10, 2025
-
-
-**Changes:**
-- **Added**: Added patching logic for prompt metadata ([#462](https://github.com/agentuity/cli/pull/462))
-
-
-## v0.0.171
-
-
- Released: October 3, 2025
-
-
-**Changes:**
-- **Added**: Multi-file YAML prompt support ([#460](https://github.com/agentuity/cli/pull/460))
-- **Changed**: Function signature modifications and code generation enhancements ([#460](https://github.com/agentuity/cli/pull/460))
-
-
-## v0.0.170
-
-
- Released: October 2, 2025
-
-
-**Changes:**
-- **Added**: Public key encryption for self-hosted deployments and new infra ([#429](https://github.com/agentuity/cli/pull/429))
-
-
-## v0.0.169
-
-
- Released: October 2, 2025
-
-
-**Changes:**
-- **Added**: Prompt eval changes ([#455](https://github.com/agentuity/cli/pull/455))
-- **Added**: Added feature flag to the CLI config ([#456](https://github.com/agentuity/cli/pull/456))
-
-
-## v0.0.168
-
-
- Released: September 24, 2025
-
-
-**Changes:**
-- **Added**: Add support for importing: yaml, json, txt, png, gif, jpg, svg, webp, md, csv, pdf, sql, xml ([#452](https://github.com/agentuity/cli/pull/452))
-- **Added**: Onboard nudges on next steps. Changed shell completion failure from warn to ohai so it doesn't look like installation failed. ([#454](https://github.com/agentuity/cli/pull/454))
-
-
-## v0.0.167
-
-
- Released: September 24, 2025
-
-
-**Changes:**
-- **Added**: [AGENT-684] Check if zsh is installed before adding autocomplete in the CLI ([#450](https://github.com/agentuity/cli/pull/450))
-- **Added**: [AGENT-628] Unit tests ([#441](https://github.com/agentuity/cli/pull/441))
-- **Added**: feat: automatically add AGENTUITY_SDK_KEY and AGENTUITY_PROJECT_KEY to .env file when running dev command ([#442](https://github.com/agentuity/cli/pull/442))
-- **Changed**: Dont sort releases by commit msg ([#447](https://github.com/agentuity/cli/pull/447))
-- **Changed**: [AGENT-628] prevent local development env files from syncing to production ([#440](https://github.com/agentuity/cli/pull/440))
-- **Fixed**: Fix npm workspaces ([#451](https://github.com/agentuity/cli/pull/451))
-- **Fixed**: Fix 'Press any key to continue' to accept any key, not just Enter ([#445](https://github.com/agentuity/cli/pull/445))
-
-## v0.0.166
-
-
- Released: August 28, 2025
-
-
-**Changes:**
-- **Added**: Adds support for pnpm as a bundler ([#438](https://github.com/agentuity/cli/pull/438))
-- **Fixed**: bump go-common to get light mode color fixes
-
-## v0.0.165
-
-
- Released: August 18, 2025
-
-
-**Changes:**
-- **Changed**: Exclude the .jj folder automatically ([#434](https://github.com/agentuity/cli/pull/434))
-- **Changed**: Changes to make teams work ([#432](https://github.com/agentuity/cli/pull/432))
-
-## v0.0.164
-
-
- Released: August 12, 2025
-
-
-**Changes:**
-- **Added**: Allow setup.sh in case we need to run some script in docker image ([#427](https://github.com/agentuity/cli/pull/427))
-- **Changed**: Add more debugging around new project to debug failure ([#430](https://github.com/agentuity/cli/pull/430))
-- **Changed**: Make it scroll with arrows as well ([#428](https://github.com/agentuity/cli/pull/428))
-
-## v0.0.163
-
-
- Released: July 22, 2025
-
-
-**Changes:**
-- **Added**: Support for dry-run command ([#425](https://github.com/agentuity/cli/pull/425))
-
-## v0.0.162
-
-
- Released: July 18, 2025
-
-
-**Changes:**
-- **Fixed**: Fix issue with env on deploy asking for setting when set. Suppress some logs ([#424](https://github.com/agentuity/cli/pull/424))
-- **Fixed**: Added an option to open login OTP with enter ([#420](https://github.com/agentuity/cli/pull/420))
-
-## v0.0.161
-
-
- Released: July 16, 2025
-
-
- **Changes:**
-- **Added**: Support for multiple deployment tags in bundle command ([#422](https://github.com/agentuity/cli/pull/422))
-
-## v0.0.160
-
-
- Released: July 15, 2025
-
-
- **Changes:**
-- **Added**: Support for preview environments ([#418](https://github.com/agentuity/cli/pull/418))
-
-## v0.0.159
-
-
- Released: July 15, 2025
-
-
- **Changes:**
-- **Fixed**: Fix issue with deployment error not having a write to write out the error ([#416](https://github.com/agentuity/cli/pull/416))
-
-## v0.0.158
-
-
- Released: July 8, 2025
-
-
- **Changes:**
-- **Fixed**: Bun: re-generate the lock file when we go to install for the first time or in CI ([#414](https://github.com/agentuity/cli/pull/414))
-
-## v0.0.157
-
-
- Released: July 7, 2025
-
-
- **Changes:**
-- **Fixed**: Bun/Node: remove the --no-save flag which was causing issues during package installation ([#412](https://github.com/agentuity/cli/pull/412))
-
-## v0.0.156
-
-
- Released: July 3, 2025
-
-
- **Changes:**
-- **Added**: Deployment: add new deployment options ([#410](https://github.com/agentuity/cli/pull/410))
-- **Fixed**: [GITHUB-338] Do not create a git repo if we're already in a git repo ([#406](https://github.com/agentuity/cli/pull/406))
-- **Fixed**: BUG FIX compare with original, not masked ([#409](https://github.com/agentuity/cli/pull/409))
-
-## v0.0.155
-
-
- Released: June 30, 2025
-
-
- **Changes:**
-- **Added**: List deployments ([#405](https://github.com/agentuity/cli/pull/405))
-- **Fixed**: Fix upgrade success message styling ([#404](https://github.com/agentuity/cli/pull/404))
-- **Security**: Don't upload masked values to backend ([#407](https://github.com/agentuity/cli/pull/407))
-
-## v0.0.154
-
-
- Released: June 26, 2025
-
-
- **Changes:**
-- **Added**: Add project delete in headless mode with support for specifying project IDs as arguments and --force flag ([#402](https://github.com/agentuity/cli/pull/402))
-
-## v0.0.153
-
-
- Released: June 24, 2025
-
-
- **Changes:**
-- **Changed**: When running dev mode, make sure we have a .env.development file ([#400](https://github.com/agentuity/cli/pull/400))
-
-## v0.0.152
-
-
- Released: June 24, 2025
-
-
- **Changes:**
-- **Fixed**: Railgurd the user from creating a project in an existing project directory ([#396](https://github.com/agentuity/cli/pull/396))
-- **Fixed**: Fix regression in hot reload for new bun/node templates ([#398](https://github.com/agentuity/cli/pull/398))
-
-## v0.0.151
-
-
- Released: June 18, 2025
-
-
- **Changes:**
-- **Changed**: Switch to using a more compatible docker internal hostname that works cross platform ([#394](https://github.com/agentuity/cli/pull/394))
-- **Changed**: Split up the upload vs deploy status messages ([#395](https://github.com/agentuity/cli/pull/395))
-
-## v0.0.150
-
-
- Released: June 13, 2025
-
-
- **Changes:**
-- **Added**: Add groq patch module ([#390](https://github.com/agentuity/cli/pull/390))
-- **Fixed**: Complete JSONC parsing fix for MCPConfig.UnmarshalJSON method ([#388](https://github.com/agentuity/cli/pull/388))
-- **Fixed**: Fix install script race condition by eliminating separate HEAD request ([#389](https://github.com/agentuity/cli/pull/389))
-
-## v0.0.149
-
-
- Released: June 13, 2025
-
-
- **Changes:**
-- **Fixed**: Fix Amp MCP config parsing to support JSON with comments ([#386](https://github.com/agentuity/cli/pull/386))
-- **Fixed**: Add more flexible ignore matching for full ignore rule ([#385](https://github.com/agentuity/cli/pull/385))
-
-## v0.0.148
-
-
- Released: June 11, 2025
-
-
- **Changes:**
-- **Changed**: More normalized Python project naming ([#383](https://github.com/agentuity/cli/pull/383))
-- **Changed**: Add AMP MCP support ([#382](https://github.com/agentuity/cli/pull/382))
-
-## v0.0.147
-
-
- Released: June 11, 2025
-
-
- **Changes:**
-- **Changed**: Skip TypeScript type checking in production builds to improve build performance ([#380](https://github.com/agentuity/cli/pull/380))
-
-## v0.0.146
-
-
- Released: June 11, 2025
-
-
- **Changes:**
-- **Changed**: Need to use the changed directory when using last known project ([#358](https://github.com/agentuity/cli/pull/358))
-
-## v0.0.145
-
-
- Released: June 10, 2025
-
-
- **Changes:**
-- **Added**: TypeScript type checking is now performed automatically during the build process if a TypeScript compiler is present ([#376](https://github.com/agentuity/cli/pull/376))
-- **Changed**: Enhanced file watcher to use ignore rules for filtering, improving reliability and performance ([#376](https://github.com/agentuity/cli/pull/376))
-- **Changed**: Streamlined development server restart logic for smoother and more predictable restarts ([#376](https://github.com/agentuity/cli/pull/376))
-- **Changed**: Centralized ignore rules creation for project deployments to simplify configuration management ([#376](https://github.com/agentuity/cli/pull/376))
-- **Fixed**: Improved error message handling when a required project file is missing, ensuring messages are displayed appropriately based on terminal capabilities ([#375](https://github.com/agentuity/cli/pull/375))
-- **Fixed**: Improved file and directory ignore handling, ensuring that common development files and directories (e.g., swap files, backup files, node_modules, virtual environments) are consistently excluded across all relevant features ([#376](https://github.com/agentuity/cli/pull/376))
-
-## v0.0.144
-
-
- Released: June 3, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed terminal cursor disappearing after breaking change error by returning error instead of os.Exit(1) ([#373](https://github.com/agentuity/cli/pull/373))
-- **Fixed**: Fixed issue with agent casing not being considered ([#372](https://github.com/agentuity/cli/pull/372))
-- **Fixed**: Fixed filtering of environment variables and secrets that are internal ([#371](https://github.com/agentuity/cli/pull/371))
-
-## v0.0.143
-
-
- Released: May 30, 2025
-
-
- **Changes:**
-- **Changed**: Improvements around packaging ([#368](https://github.com/agentuity/cli/pull/368))
-- **Fixed**: [AGENT-258] Use utility function from envutil for better environment variable handling ([#364](https://github.com/agentuity/cli/pull/364))
-- **Fixed**: Cloned projects now automatically include an .env file ([#369](https://github.com/agentuity/cli/pull/369))
-
-## v0.0.142
-
-
- Released: May 29, 2025
-
-
- **Changes:**
-- **Changed**: [AGENT-272] Always reinitialize the viewport on resize to avoid invalid state ([#363](https://github.com/agentuity/cli/pull/363))
-- **Changed**: MCP: Relaxed types for MCP parsing configs ([#365](https://github.com/agentuity/cli/pull/365))
-- **Changed**: Allow SDK to be copied into a project for development purposes ([#366](https://github.com/agentuity/cli/pull/366))
-- **Fixed**: [AGENT-232] Fixed issue with Python project name by ensuring agent names are lowercase ([#359](https://github.com/agentuity/cli/pull/359))
-- **Fixed**: Don't run git init when you are already in a git repository ([#362](https://github.com/agentuity/cli/pull/362))
-
-## v0.0.141
-
-
- Released: May 28, 2025
-
-
- **Changes:**
-- **Added**: Added additional ignore rule defaults for better project management ([#357](https://github.com/agentuity/cli/pull/357))
-- **Added**: Added missing disk units for better user feedback ([#355](https://github.com/agentuity/cli/pull/355))
-- **Fixed**: Deploy: Fixed error with missing files during zip creation ([#354](https://github.com/agentuity/cli/pull/354))
-- **Fixed**: Fixed directory handling when using last known project ([#358](https://github.com/agentuity/cli/pull/358))
-
-## v0.0.140
-
-
- Released: May 27, 2025
-
-
- **Changes:**
-- **Added**: [AGENT-122] Added logs command with filtering and streaming capabilities including tail option, flexible duration parsing, and customizable output formatting ([#342](https://github.com/agentuity/cli/pull/342))
-- **Added**: Added tag and description options to the bundle command for deployment metadata ([#351](https://github.com/agentuity/cli/pull/351))
-- **Added**: Added --org-id filter to project list and delete commands for organization-specific operations ([#350](https://github.com/agentuity/cli/pull/350))
-- **Fixed**: Fixed mono repository support by improving SDK resolution process with better logging for directory traversal ([#352](https://github.com/agentuity/cli/pull/352))
-- **Fixed**: DevMode: Fixed sourcemap resolution when node_modules is outside the project directory ([#348](https://github.com/agentuity/cli/pull/348))
-
-## v0.0.139
-
-
- Released: May 24, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed Bun sourcemap shim issue to improve source map support for projects using the "bunjs" runtime ([#346](https://github.com/agentuity/cli/pull/346))
-
-## v0.0.138
-
-
- Released: May 23, 2025
-
-
- **Changes:**
-- **Changed**: DevMode: Removed TUI (Terminal User Interface) in favor of a simpler logging approach ([#344](https://github.com/agentuity/cli/pull/344))
-- **Fixed**: Fixed prepareStackTrace error handling and improved DevMode logging ([#343](https://github.com/agentuity/cli/pull/343))
-- **Fixed**: Added better handling for Ctrl+C in DevMode ([#343](https://github.com/agentuity/cli/pull/343))
-
-## v0.0.137
-
-
- Released: May 23, 2025
-
-
- **Changes:**
-- **Changed**: Updated Discord community invite links across the CLI, TUI, README, and error system ([#339](https://github.com/agentuity/cli/pull/339))
-- **Changed**: Modified prompt in environment handling to separate informational messages from interactive questions ([#339](https://github.com/agentuity/cli/pull/339))
-- **Changed**: Updated dependency `github.com/agentuity/go-common` from v1.0.60 to v1.0.64 ([#339](https://github.com/agentuity/cli/pull/339))
-- **Fixed**: Fixed DevMode: Removed "server" and "force" flags and all related logic, including environment file processing ([#339](https://github.com/agentuity/cli/pull/339))
-
-## v0.0.136
-
-
- Released: May 22, 2025
-
-
- **Changes:**
-- **Added**: Add copy attributes to project when importing ([#332](https://github.com/agentuity/cli/pull/332))
-- **Added**: Quality of life improvement: if disk requested is smaller than needed, will tell you and potentially adjust ([#330](https://github.com/agentuity/cli/pull/330))
-- **Added**: [AGENT-130] Delete and Roll Back deployments ([#313](https://github.com/agentuity/cli/pull/313))
-
-This page documents the release history of the [Agentuity CLI](https://github.com/agentuity/cli).
-## v0.0.135
-
-
- Released: May 22, 2025
-
-
- **Changes:**
-- **Added**: [AGENT-130] Added deployment management features with rollback and delete commands ([#313](https://github.com/agentuity/cli/pull/313))
-- **Added**: Added disk size validation during bundling for JavaScript and Python projects with auto-adjustment option ([#330](https://github.com/agentuity/cli/pull/330))
-
-## v0.0.134
-
-
- Released: May 22, 2025
-
-
- **Changes:**
-- **Fixed**: Python: improve devmode logging with support for additional log prefixes ([#328](https://github.com/agentuity/cli/pull/328))
-- **Fixed**: Fixed handling of Python package versions containing "+" in pre-release builds ([#328](https://github.com/agentuity/cli/pull/328))
-- **Fixed**: Fixed headless import by correcting flag name from "apikey" to "api-key" ([#327](https://github.com/agentuity/cli/pull/327))
-
-## v0.0.133
-
-
- Released: May 21, 2025
-
-
- **Changes:**
-- **Changed**: Removed Windows from the build matrix in CI workflow ([73fe98b](https://github.com/agentuity/cli/commit/73fe98bca31f3864a1028c379b29aac6cf36350f))
-- **Added**: DevMode: Allow the API to return a preferred server ([#325](https://github.com/agentuity/cli/pull/325))
-- **Fixed**: DevMode: Improved logging output and sourcemap support ([#321](https://github.com/agentuity/cli/pull/321))
-- **Fixed**: [AGENT-209] Refactor adding env vars from file ([#324](https://github.com/agentuity/cli/pull/324))
-
-## v0.0.132
-
-
- Released: May 21, 2025
-
-
- **Changes:**
-- **Fixed**: [AGENT-166] Add dev mode flag and improved error handling during server streaming operations ([#322](https://github.com/agentuity/cli/pull/322))
-
-## v0.0.129
-
-
- Released: May 20, 2025
-
-
- **Changes:**
-- **Changed**: [AGENT-169] Expose framework to the UI ([#295](https://github.com/agentuity/cli/pull/295))
-
-## v0.0.128
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: automatic reconnect if losing connection to echo server ([#308](https://github.com/agentuity/cli/pull/308))
-
-## v0.0.127
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: Added better logging on startup, make sure we kill server if healthcheck fails, wait longer ([#306](https://github.com/agentuity/cli/pull/306))
-
-## v0.0.126
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: Fixed issue when using short agent ID wasn't going upstream ([#304](https://github.com/agentuity/cli/pull/304))
-
-## v0.0.125
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed regression with transport having no IO (public) ([#302](https://github.com/agentuity/cli/pull/302))
-
-## v0.0.124
-
-
- Released: May 17, 2025
-
-
- **Changes:**
-- **Added**: Mouse support for developer UI (scrolling and log selection) ([#300](https://github.com/agentuity/cli/pull/300))
-- **Added**: Agent welcome messages and optional prompts for richer metadata ([#300](https://github.com/agentuity/cli/pull/300))
-- **Added**: Support for non-TUI mode in VS Code terminals and pipe environments ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Renamed interface label from "Dashboard" to "DevMode" for clarity ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Enhanced log display with timestamps and improved formatting ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Don't use alt screen so content is preserved on exit ([#300](https://github.com/agentuity/cli/pull/300))
-
-## v0.0.131
-
-
- Released: May 20, 2025
-
-
- **Changes:**
-- **Added**: Added headless import functionality for non-interactive project imports ([#318](https://github.com/agentuity/cli/pull/318))
-- **Fixed**: Fixed release workflow by removing invalid subject-checksums-type parameter ([#319](https://github.com/agentuity/cli/pull/319))
-
-## v0.0.130
-
-
- Released: May 20, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: remove mouse tracking as it caused the inability to copy/paste in the terminal ([#316](https://github.com/agentuity/cli/pull/316))
-## v0.0.129
-
-
- Released: May 20, 2025
-
-
- **Changes:**
-- **Changed**: [AGENT-169] Expose framework to the UI ([#295](https://github.com/agentuity/cli/pull/295))
-
-## v0.0.128
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: automatic reconnect if losing connection to echo server ([#308](https://github.com/agentuity/cli/pull/308))
-
-## v0.0.127
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: Added better logging on startup, make sure we kill server if healthcheck fails, wait longer ([#306](https://github.com/agentuity/cli/pull/306))
-
-## v0.0.126
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: Fixed issue when using short agent ID wasn't going upstream ([#304](https://github.com/agentuity/cli/pull/304))
-
-## v0.0.125
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed regression with transport having no IO (public) ([#302](https://github.com/agentuity/cli/pull/302))
-
-## v0.0.124
-
-
- Released: May 17, 2025
-
-
- **Changes:**
-- **Added**: Mouse support for developer UI (scrolling and log selection) ([#300](https://github.com/agentuity/cli/pull/300))
-- **Added**: Agent welcome messages and optional prompts for richer metadata ([#300](https://github.com/agentuity/cli/pull/300))
-- **Added**: Support for non-TUI mode in VS Code terminals and pipe environments ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Renamed interface label from "Dashboard" to "DevMode" for clarity ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Enhanced log display with timestamps and improved formatting ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Don't use alt screen so content is preserved on exit ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Modified CI workflows to ignore documentation-only PRs ([#300](https://github.com/agentuity/cli/pull/300))
-- **Changed**: Updated port selection logic for dev server and agent testing ([#300](https://github.com/agentuity/cli/pull/300))
-- **Fixed**: Fixed port binding conflicts when running multiple agents ([#300](https://github.com/agentuity/cli/pull/300))
-- **Fixed**: Fixed escape key behavior in main screen ([#300](https://github.com/agentuity/cli/pull/300))
-- **Fixed**: Fixed log filtering issue ([#300](https://github.com/agentuity/cli/pull/300))
-- **Fixed**: Fixed regression in welcome prompt not showing up ([#300](https://github.com/agentuity/cli/pull/300))
-
-## v0.0.123
-
-
- Released: May 17, 2025
-
-
- **Changes:**
-- **Fixed**: Auto switch to local echo if using localhost, fix terminal reset issues ([#298](https://github.com/agentuity/cli/pull/298))
-
-## v0.0.122
-
-
- Released: May 16, 2025
-
-
- **Changes:**
-- **Changed**: Initial Refactor for DevMode to use new Bridge API and new TUI ([#270](https://github.com/agentuity/cli/pull/270))
-
-## v0.0.121
-
-
- Released: May 16, 2025
-
-
- **Changes:**
-- **Added**: [AGENT-133] Added "test" command ([#290](https://github.com/agentuity/cli/pull/290))
-- **Added**: [AGENT-129] Multiple tags for a deployment ([#291](https://github.com/agentuity/cli/pull/291))
-- **Changed**: Add tag and message to deployments in CI ([#293](https://github.com/agentuity/cli/pull/293))
-- **Fixed**: [AGENT-179] Call the agent from the correct endpoint ([#294](https://github.com/agentuity/cli/pull/294))
-
-## v0.0.120 ⚠️
-
-
- Released: May 14, 2025
-
-
- **Changes:**
-- **Added**: Add project key for agent comms ([#285](https://github.com/agentuity/cli/pull/285))
-- **Changed**: Shorten install script, skip prebuilds on breaking change check ([#287](https://github.com/agentuity/cli/pull/287))
-- **Changed**: Cleanup: remove old vscode settings, move release to use blacksmith now that we dont need MSI build ([#289](https://github.com/agentuity/cli/pull/289))
-- **Changed**: Update copy in upgrade.go for upgrade
-- **Fixed**: [AGENT-163] Update command for Windows ([#284](https://github.com/agentuity/cli/pull/284))
-- **Documentation**: Update changelog for v0.0.119 ([#283](https://github.com/agentuity/cli/pull/283))
-
- **⚠️ Breaking Changes**
-
-This version includes breaking changes that require updates to your JavaScript and Python SDKs:
-
-- **JavaScript SDK**: Update to v0.0.115 or later for compatibility with the new agent communications protocol. See the [JavaScript SDK Changelog](https://agentuity.dev/Changelog/sdk-js#v00115) for upgrade instructions.
-- **Python SDK**: Update to v0.0.84 or later to support the new project key feature. See the [Python SDK Changelog](https://agentuity.dev/Changelog/sdk-py#v0084) for upgrade instructions.
-
-If you're using an Agentic code editor (such as Cursor, Windsurf, etc.), you can use this prompt to update your code with these changes:
-
-```
-The Agentuity SDK v0.0.115 has renamed AGENTUITY_API_KEY to AGENTUITY_SDK_KEY.
-Please find all instances of AGENTUITY_API_KEY in my code and replace them with AGENTUITY_SDK_KEY.
-```
-
-## v0.0.119
-
-
- Released: May 8, 2025
-
-
- **Changes:**
-- **Added**: Added path completion to the CLI ([#282](https://github.com/agentuity/cli/pull/282))
-- **Changed**: Cleanup install script ([#281](https://github.com/agentuity/cli/pull/281))
- - Removed Windows native support (WSL is now recommended)
- - Improved installation testing with Docker
- - Restructured installation script for better maintainability
-
-## v0.0.118
-
-
- Released: May 6, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed check on dev for Linux by using `sys.IsRunningInsideDocker()` instead of checking for specific Docker files ([#279](https://github.com/agentuity/cli/pull/279))
-
-## v0.0.117
-
-
- Released: May 5, 2025
-
-
- **Changes:**
-- **Fixed**: Fixed typo in CI flag name (changed "ci-messsage" to "ci-message") ([#277](https://github.com/agentuity/cli/pull/277))
-
-## v0.0.116
-
-
- Released: May 5, 2025
-
-
- **Changes:**
-- **Fixed**: Missed annotation on GitInfo ([#275](https://github.com/agentuity/cli/pull/275))
-- **Fixed**: AGENT-29 Check mask value for secrets ([#274](https://github.com/agentuity/cli/pull/274))
-- **Fixed**: Passing CI logs URL to display GitHub action logs in the UI ([#273](https://github.com/agentuity/cli/pull/273))
-- **Changed**: Taking a walk to get the git data 🚶♂️➡️ ([#272](https://github.com/agentuity/cli/pull/272))
-- **Changed**: Pass on the git info from deploy to bundle when for --deploy ([#271](https://github.com/agentuity/cli/pull/271))
-
-## v0.0.115
-
-
- Released: May 2, 2025
-
-
- **Changes:**
-- **Added**: Added mono repofix ([#267](https://github.com/agentuity/cli/pull/267))
-- **Changed**: Add flags for deployment data overwrite from github action ([#266](https://github.com/agentuity/cli/pull/266))
-- **Fixed**: Allow non-admin users to uninstall CLI without admin privileges ([#264](https://github.com/agentuity/cli/pull/264))
-
-## v0.0.114
-
-
- Released: May 1, 2025
-
-
- **Changes:**
-- **Fixed**: Don't call close handler if conn is nil ([#255](https://github.com/agentuity/cli/pull/255))
-- **Fixed**: Fix 'text file busy' error during CLI updates ([#254](https://github.com/agentuity/cli/pull/254))
-- **Fixed**: Windows: improve the output for windows upgrade ([#253](https://github.com/agentuity/cli/pull/253))
-- **Fixed**: Fix PowerShell installation issues in install.ps1 ([#257](https://github.com/agentuity/cli/pull/257))
-- **Fixed**: DevMode: Make sure to terminate child processes ([#259](https://github.com/agentuity/cli/pull/259))
-- **Fixed**: Don't error if deliberate restart ([#260](https://github.com/agentuity/cli/pull/260))
-- **Fixed**: Set ALLUSERS=0 for non-admin installations to ensure proper installation to AppData/Local/Agentuity ([#261](https://github.com/agentuity/cli/pull/261))
-- **Added**: Update install.sh to support /home/ubuntu/.bin and prompt for shell reload ([#258](https://github.com/agentuity/cli/pull/258))
-- **Added**: Add breaking change for new Python SDK ([#256](https://github.com/agentuity/cli/pull/256))
-
-## v0.0.113
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Added**: Make sure agent create has a reference to the template so we can reference it in interpolation ([#251](https://github.com/agentuity/cli/pull/251))
-- **Changed**: DevMode: debounce hot reloads ([#250](https://github.com/agentuity/cli/pull/250))
-
-## v0.0.111
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Fixed**: Fix PowerShell installation error with global drive ([#246](https://github.com/agentuity/cli/pull/246))
-- **Fixed**: Improve hot reload stability ([#245](https://github.com/agentuity/cli/pull/245))
-- **Fixed**: Fix Windows upgrade process to uninstall existing CLI before installation ([#244](https://github.com/agentuity/cli/pull/244))
-## v0.0.110
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Fixed**: More logging and cleanup for dev server startup, more safe filename fixes for python which is stricter ([#242](https://github.com/agentuity/cli/pull/242))
-
-## v0.0.109
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Fixed**: Fix issue with windows startup for devmode ([#240](https://github.com/agentuity/cli/pull/240))
- - Increased wait time for devmode on Windows
- - Added more logging
- - Fixed Windows path escape issue in agents JSON
- - Decreased attempt duration
-
-## v0.0.108
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Fixed**: Only use SIGINT which is compatible with all platforms vs SIGKILL which doesn't work on Windows ([#239](https://github.com/agentuity/cli/pull/239))
-
-## v0.0.107
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-- **Fixed**: DevMode: connect to ipv4 loopback explicitly ([#237](https://github.com/agentuity/cli/pull/237))
-
-## v0.0.106
-
-
- Released: April 26, 2025
-
-
- **Changes:**
-- **Changed**: Use update not upgrade ([#235](https://github.com/agentuity/cli/pull/235))
-- **Changed**: Some Node libraries which have already been bundled conflict with our bundle require shim ([#233](https://github.com/agentuity/cli/pull/233))
-- **Documentation**: Update changelog for v0.0.105 ([#232](https://github.com/agentuity/cli/pull/232))
-- **Documentation**: Fix doc link
-
-## v0.0.105
-
-
- Released: April 25, 2025
-
-
- **Changes:**
-- **Changed**: Temporarily revert the agent rename detection ([#231](https://github.com/agentuity/cli/pull/231))
-- **Changed**: Revert "temporarily comment out the new sdk upgrade requirement until ready" ([#229](https://github.com/agentuity/cli/pull/229))
-- **Changed**: Update the dev help output to use the direct agent route instead of legacy route ([#224](https://github.com/agentuity/cli/pull/224))
-
-## v0.0.104
-
-
- Released: April 24, 2025
-
-
- **Changes:**
-- **Changed**: Small tweaks around help and error dialog ([#227](https://github.com/agentuity/cli/pull/227))
-- **Fixed**: Fix regression in devmode input json using new binary protocol ([#228](https://github.com/agentuity/cli/pull/228))
-- **Fixed**: Add error message for JS SDK breaking change ([#225](https://github.com/agentuity/cli/pull/225))
-- **Fixed**: Project Name uniqueness check should be within project not any project in the users org ([#223](https://github.com/agentuity/cli/pull/223))
-- **Fixed**: Add a more helpful error message when dev command cannot validate the project ([#222](https://github.com/agentuity/cli/pull/222))
-- **Fixed**: Better handling when you rename an agent and attempt to deploy ([#221](https://github.com/agentuity/cli/pull/221))
-- **Documentation**: Update changelog for v0.0.103 ([#220](https://github.com/agentuity/cli/pull/220))
-
-## v0.0.103
-
-
- Released: April 23, 2025
-
-
- **Changes:**
-- **Fixed**: Fix dev mode for new sdk ([#219](https://github.com/agentuity/cli/pull/219))
-- **Fixed**: A better error messages when trying to load a project ([#218](https://github.com/agentuity/cli/pull/218))
-
-## v0.0.102
-
-
- Released: April 21, 2025
-
-
- **Changes:**
-- **Fixed**: Don't fail if MCP detection fails for any reason on create project ([#216](https://github.com/agentuity/cli/pull/216))
-
-## v0.0.101
-
-
- Released: April 19, 2025
-
-
- **Changes:**
-- **Fixed**: Fix unzip function to properly close file handles ([#215](https://github.com/agentuity/cli/pull/215))
-
-## v0.0.100
-
-
- Released: April 19, 2025
-
-
- **Changes:**
-- **Changed**: Be smart about remembering the last project ([#212](https://github.com/agentuity/cli/pull/212))
-- **Changed**: Hide websocket-id flag from CLI help text ([#211](https://github.com/agentuity/cli/pull/211))
-- **Documentation**: Update changelog for v0.0.99 ([#210](https://github.com/agentuity/cli/pull/210))
-
-## v0.0.99
-
-
- Released: April 18, 2025
-
-
- **Changes:**
-- **Changed**: Add a better error message on new project by using a dialog component ([#209](https://github.com/agentuity/cli/pull/209))
-
-## v0.0.98
-
-
- Released: April 18, 2025
-
-
- **Changes:**
-- **Changed**: Add exponential backoff for agent welcome connection with 30s max time ([#207](https://github.com/agentuity/cli/pull/207))
-
-## v0.0.97
-
-
- Released: April 17, 2025
-
-
- **Changes:**
-- **Fixed**: Fix issue with too many files error ([#205](https://github.com/agentuity/cli/pull/205))
-- **Fixed**: Fixed small error (55996e3)
-- **Changed**: Bump golang.org/x/net from 0.36.0 to 0.38.0 ([#204](https://github.com/agentuity/cli/pull/204))
-- **Documentation**: Update changelog for v0.0.96 ([#203](https://github.com/agentuity/cli/pull/203))
-
-## v0.0.96
-
-
- Released: April 16, 2025
-
-
- **Changes:**
-- Guard against conn being nil ([e095c09](https://github.com/agentuity/cli/commit/e095c09))
-- Only set step cursor on page 1 ([#202](https://github.com/agentuity/cli/pull/202))
-
-## v0.0.95
-
-
- Released: April 16, 2025
-
-
- **Changes:**
-
-- **Added**: Add retries to HTTP client ([#200](https://github.com/agentuity/cli/pull/200))
-- **Changed**: Attempt to have better UX handling of upgrade checks ([#199](https://github.com/agentuity/cli/pull/199))
-- **Changed**: Template Improvements ([#198](https://github.com/agentuity/cli/pull/198))
-- **Documentation**: Update changelog for v0.0.94 ([#197](https://github.com/agentuity/cli/pull/197))
-
-## v0.0.93
-
-
- Released: April 16, 2025
-
-
- **Changes:**
-
-- **Changed**: Improve TUI semantics ([#193](https://github.com/agentuity/cli/pull/193))
-- **Fixed**: Add more debug logging around CI bundling for github app ([#194](https://github.com/agentuity/cli/pull/194))
-- **Documentation**: Update changelog for v0.0.92 ([#192](https://github.com/agentuity/cli/pull/192))
-
-## v0.0.92
-
-
- Released: April 15, 2025
-
-
- **Changes:**
-
-- **Fixed**: Fix the Git URL to rewrite to https ([#190](https://github.com/agentuity/cli/pull/190))
-- **Changed**: Add hyperlinks to older release versions in CHANGELOG.md ([#191](https://github.com/agentuity/cli/pull/191))
-- **Changed**: Update changelog for v0.0.91 ([#189](https://github.com/agentuity/cli/pull/189))
-
-## v0.0.91
-
-
- Released: April 14, 2025
-
-
- **Changes:**
-
-- **Fixed**: Fix go-common flag issue with overriding log level from env and add more debug to bundle ([#188](https://github.com/agentuity/cli/pull/188))
-
-## v0.0.90
-
-
- Released: April 14, 2025
-
-
- **Changes:**
-
-- **Added**: Add support for managing API Keys from CLI ([#186](https://github.com/agentuity/cli/pull/186))
-- **Fixed**: Make sure we set the working directory when running the project dev command since we could be using --dir
-
-## v0.0.89
-
-
- Released: April 10, 2025
-
-
- **Changes:**
-
-- **Added**: Add CLI Signup Flow ([#182](https://github.com/agentuity/cli/pull/182))
-- **Fixed**: Fix MacOS segfault during reinstallation ([#183](https://github.com/agentuity/cli/pull/183))
-- **Fixed**: Smart login or setup ([#184](https://github.com/agentuity/cli/pull/184))
-
-## v0.0.88
-
-
- Released: April 8, 2025
-
-
- **Changes:**
-
-- **Added**: Webhook instructions ([#179](https://github.com/agentuity/cli/pull/179))
-- **Changed**: Proxy GitHub public APIs ([#180](https://github.com/agentuity/cli/pull/180))
-- **Changed**: Small improvements on devmode
-- **Fixed**: Make it clear that the webhook is a POST ([#178](https://github.com/agentuity/cli/pull/178))
-- **Fixed**: If node_modules or .venv/lib directory are missing when bundling, force install ([#177](https://github.com/agentuity/cli/pull/177))
-
-## v0.0.87
-
-
- Released: April 8, 2025
-
-
- **Changes:**
-
-- **Fixed**: Fix regression in step 2 (new project) related to cursor selection ([234b330](https://github.com/agentuity/cli/commit/234b3307d1fd96005d4f656ab319d438e7b60626))
-
-## v0.0.86
-
-
- Released: April 7, 2025
-
-
- **Changes:**
-
-- **Added**: Add Clone Repo step ([#171](https://github.com/agentuity/cli/pull/171))
-- **Added**: Add Agent Welcome on DevMode ([#172](https://github.com/agentuity/cli/pull/172))
-- **Changed**: Totally re-write the TUI for the new project ([#170](https://github.com/agentuity/cli/pull/170))
-- **Changed**: Better upgrade handling ([#174](https://github.com/agentuity/cli/pull/174))
-- **Fixed**: Fix crewai installation issue (exit status 130) ([#169](https://github.com/agentuity/cli/pull/169))
-- **Fixed**: Make sure command is executed with a context ([#173](https://github.com/agentuity/cli/pull/173))
-
-## v0.0.74
-
-
- Released: March 25, 2025
-
-
- **Changes:**
-
-- **Added**: JSON Schema for agentuity.yaml file ([#126](https://github.com/agentuity/cli/pull/126), [#127](https://github.com/agentuity/cli/pull/127))
-- **Added**: MCP Support ([#121](https://github.com/agentuity/cli/pull/121))
-- **Fixed**: Windows installer and MCP fixes ([#129](https://github.com/agentuity/cli/pull/129))
-- **Fixed**: Improved dev command shutdown to ensure all child processes are terminated ([#128](https://github.com/agentuity/cli/pull/128))
-- **Fixed**: Issue when dev port is taken by automatically choosing another port ([#125](https://github.com/agentuity/cli/pull/125))
-- **Fixed**: Git deployment metadata fix ([#120](https://github.com/agentuity/cli/pull/120))
-- **Changed**: GitHub improvements ([#123](https://github.com/agentuity/cli/pull/123))
-
-## v0.0.73
-
-
- Released: March 21, 2025
-
-
- **Changes:**
-
-- **Fixed**: Python: force --env-file when running in devmode ([#118](https://github.com/agentuity/cli/pull/118))
-- **Changed**: place .env on another line to be safe
-
-## v0.0.71
-
-
- Released: March 20, 2025
-
-
- **Changes:**
-
-- **Changed**: Pass on dir flag when doing bundle --deploy ([#115](https://github.com/agentuity/cli/pull/115))
-
-## v0.0.70
-
-
- Released: March 19, 2025
-
-
- **Changes:**
-
-- **Added**: Initial Implementation of Automatic Version checking ([#113](https://github.com/agentuity/cli/pull/113))
-
-## v0.0.69
-
-
- Released: March 19, 2025
-
-
- **Changes:**
-
-- **Fixed**: Handle auth failure better ([#112](https://github.com/agentuity/cli/pull/112))
-- **Changed**: Move internal/tui package to use go-common/tui package so we can reuse ([#111](https://github.com/agentuity/cli/pull/111))
-- **Changed**: Improve Project List View and Auth Whoami ([#110](https://github.com/agentuity/cli/pull/110))
-
-## v0.0.68
-
-
- Released: March 19, 2025
-
-
- **Changes:**
-
-- **Fixed**: Better handle user interruption errors ([#109](https://github.com/agentuity/cli/pull/109))
-
-## v0.0.67
-
-
- Released: March 19, 2025
-
-
- **Changes:**
-
-- **Added**: Force new project to always use the latest sdk ([#108](https://github.com/agentuity/cli/pull/108))
-- **Fixed**: DevMode: cleanup payload to make sure we keep it as []byte vs using string so we always transmit in base64 w/o recoding by accident ([#107](https://github.com/agentuity/cli/pull/107))
-
-## v0.0.66
-
-
- Released: March 17, 2025
-
-
- **Changes:**
-
-- **Changed**: Rename devmode ([#106](https://github.com/agentuity/cli/pull/106))
-- **Changed**: Dev Mode: deterministic room id ([#63](https://github.com/agentuity/cli/pull/63))
-
-## v0.0.65
-
-
- Released: March 17, 2025
-
-
- **Changes:**
-
-- **Fixed**: Be smarter on error message of JS when running node directly ([#105](https://github.com/agentuity/cli/pull/105))
-- **Added**: Added project id on for matt ([#104](https://github.com/agentuity/cli/pull/104))
-- **Fixed**: Add environment variable checks to Python boot.py ([#103](https://github.com/agentuity/cli/pull/103))
-
-## v0.0.64
-
-
- Released: March 16, 2025
-
-
- **Changes:**
-
-- **Added**: Add README template for JavaScript projects ([#102](https://github.com/agentuity/cli/pull/102))
-
-## v0.0.63
-
-
- Released: March 16, 2025
-
-
- **Changes:**
-
-- **Changed**: Improve CTRL-C cancel, always send user-agent with version for API requests ([#101](https://github.com/agentuity/cli/pull/101))
-
-## v0.0.62
-
-
- Released: March 16, 2025
-
-
- **Changes:**
-
-- **Fixed**: Fix change in signature with request.text -> request.data.text ([#100](https://github.com/agentuity/cli/pull/100))
-- **Added**: Add Long property documentation to all CLI commands ([#99](https://github.com/agentuity/cli/pull/99))
-- **Added**: Add traceparent in the error handling logic to aid in debugging issues ([#98](https://github.com/agentuity/cli/pull/98))
-
-## v0.0.61
-
-
- Released: March 15, 2025
-
-
- **Changes:**
-
-- **Added**: Add Org Level data encryption for agent source ([#97](https://github.com/agentuity/cli/pull/97))
-- **Added**: Improve missing LLM environment variables ([#95](https://github.com/agentuity/cli/pull/95))
-- **Fixed**: Don't set AGENTUITY_ENVIRONMENT on the production bundle, let it get set by the infra ([#96](https://github.com/agentuity/cli/pull/96))
-- **Fixed**: Fix issue with --env-file not getting picked up in node when running dev ([#94](https://github.com/agentuity/cli/pull/94))
-- **Documentation**: Update changelog for v0.0.60 ([#93](https://github.com/agentuity/cli/pull/93))
-
-## v0.0.72
-
-
- Released: March 20, 2025
-
-
- **Changes:**
-
-- **Added**: Deployment metadata and CI flag for GitHub actions ([#116](https://github.com/agentuity/cli/pull/116))
-- **Fixed**: Bug in file watcher ([#114](https://github.com/agentuity/cli/pull/114))
-- **Fixed**: Don't send error reports when using the dev version
-
-## v0.0.60
-
-
- Released: March 13, 2025
-
-
- **Changes:**
-
-- **Added**: Support for new transport domain (agentuity.ai) ([#89](https://github.com/agentuity/cli/pull/89))
-- **Added**: Profile switching for local development ([#89](https://github.com/agentuity/cli/pull/89))
-- **Fixed**: Improved agent deletion logic with backup functionality ([#90](https://github.com/agentuity/cli/pull/90))
-- **Fixed**: Corrected .dev domain references ([#91](https://github.com/agentuity/cli/pull/91), [#92](https://github.com/agentuity/cli/pull/92))
-
-## v0.0.59
-
-
- Released: March 13, 2025
-
-
- **Changes:**
-
-- Move deployment manifest from `agentuity-deployment.yaml` to `.agentuity/.manifest.yaml` ([#86](https://github.com/agentuity/cli/pull/86))
-- Improve UI by showing information banner instead of error when a requirement cannot be met ([#85](https://github.com/agentuity/cli/pull/85))
-- Fix development mode issues and environment variable handling for JavaScript environments ([#87](https://github.com/agentuity/cli/pull/87))
-
-## v0.0.58
-
-
- Released: March 12, 2025
-
-
- **Changes:**
-
-- Fix filepath issues by converting to localized path separators for Windows compatibility ([#80](https://github.com/agentuity/cli/pull/80))
-
-## v0.0.57
-
-
- Released: March 12, 2025
-
-
- **Changes:**
-
-- Add Python cursor rules files ([#75](https://github.com/agentuity/cli/pull/75))
-- Add support for remembering new project preferences ([#74](https://github.com/agentuity/cli/pull/74))
-- Fix issue when importing with an existing env ([#78](https://github.com/agentuity/cli/pull/78))
-
-## v0.0.56
-
-
- Released: March 12, 2025
-
-
- **Changes:**
-
-- **Project Import on Cloud Deploy**: Added functionality to automatically import projects when deploying to the cloud if the project ID is not found or when using a new template ([#73](https://github.com/agentuity/cli/pull/73))
-- Added project import command (`agentuity project import`)
-- Added project import checks during cloud deployment
-- Added project import checks during development mode
-- Added project import checks for new agent creation
-
-## v0.0.55
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Add debugging for random panic ([#72](https://github.com/agentuity/cli/pull/72))
-- Small TypeScript complainer fix
-
-## v0.0.54
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Better error handling when using an invalid project_id and better handle dev mode shutdown ([#71](https://github.com/agentuity/cli/pull/71))
-- Self update should be tried before brew. Fix issue on project name exists check
-
-## v0.0.53
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Make sure we set the AGENTUITY_URL when running in dev mode ([#70](https://github.com/agentuity/cli/pull/70))
-
-## v0.0.52
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Improve Error Handling from 400 Bad Request routes ([#69](https://github.com/agentuity/cli/pull/69))
-
-## v0.0.51
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Add cursor rules file for JavaScript SDK API reference ([#67](https://github.com/agentuity/cli/pull/67))
-- Fix YAML schema for templates validation ([#65](https://github.com/agentuity/cli/pull/65))
-- Fix cursor rules placement to use .cursor/rules instead of .cursorrules ([#66](https://github.com/agentuity/cli/pull/66))
-- Make sure all API calls use the APIClient and enhance the error system to send api error details to aide in debugging ([#68](https://github.com/agentuity/cli/pull/68))
-- Update Python logging format to use [LEVEL] message format ([#64](https://github.com/agentuity/cli/pull/64))
-
-## v0.0.50
-
-
- Released: March 10, 2025
-
-
- **Changes:**
-
-- Updated templates to match new SDK types ([#59](https://github.com/agentuity/cli/pull/59))
-- Fixed issue with template dependencies check not running ([#62](https://github.com/agentuity/cli/pull/62))
-- Updated JavaScript templates to use `req.data.text` instead of `req.text()`
-- Updated Python template to import `autostart` from the main package
diff --git a/content/Changelog/index.mdx b/content/Changelog/index.mdx
deleted file mode 100644
index 811da137..00000000
--- a/content/Changelog/index.mdx
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: Changelog
-description: Release notes and version history for Agentuity products
----
-
-This section contains the release notes and version history for Agentuity products:
-
-- [CLI](/Changelog/cli) - Command Line Interface [GitHub](https://github.com/agentuity/cli)
-- [JavaScript SDK](/Changelog/sdk-js) - JavaScript/TypeScript SDK [GitHub](https://github.com/agentuity/sdk-js)
-- [Python SDK](/Changelog/sdk-py) - Python SDK [GitHub](https://github.com/agentuity/sdk-py)
-
-Each page documents the changes, improvements, and bug fixes in each release.
diff --git a/content/Changelog/meta.json b/content/Changelog/meta.json
deleted file mode 100644
index 9896e881..00000000
--- a/content/Changelog/meta.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "title": "Changelog",
- "pages": ["cli", "sdk-js", "sdk-py"]
-}
diff --git a/content/Changelog/sdk-js.mdx b/content/Changelog/sdk-js.mdx
deleted file mode 100644
index c0b2156d..00000000
--- a/content/Changelog/sdk-js.mdx
+++ /dev/null
@@ -1,927 +0,0 @@
----
-title: JavaScript SDK Changelog
-description: Release notes and version history for the Agentuity JavaScript SDK
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-This page documents the release history of the [Agentuity JavaScript SDK](https://github.com/agentuity/sdk-js).
-
-## v0.0.156
-
-
- Released: October 15, 2025
-
-
-**Changes**
-
-- **Added**: Support for listing streams with flexible filtering and pagination options ([PR #200](https://github.com/agentuity/sdk-js/pull/200))
-- **Added**: Support for deleting streams by ID ([PR #200](https://github.com/agentuity/sdk-js/pull/200))
-- **Changed**: Updated telemetry logging to be more generic ([PR #199](https://github.com/agentuity/sdk-js/pull/199))
-
-## v0.0.155
-
-
- Released: October 14, 2025
-
-
-**Changes**
-
-- **Added**: Functionality to send email
-
-## v0.0.154
-
-
- Released: October 8, 2025
-
-
-**Changes**
-
-- **Added**: Prompt tracking data to AI SDK
-
-## v0.0.153
-
-
- Released: October 8, 2025
-
-
-**Changes**
-
-- **Added**: Custom user OTEL logger support
-
-## v0.0.152
-
-
- Released: October 6, 2025
-
-
-**Changes**
-
-- **Fixed**: Issue with OTEL headers not propagating for outbound services
-
-## v0.0.151
-
-
- Released: October 6, 2025
-
-
-**Changes**
-
-- **Fixed**: Issue with vector.get
-
-## v0.0.150
-
-
- Released: October 4, 2025
-
-
-**Changes**
-
-- **Fixed**: Issue where DataType can't support arbitrary valid custom objects as Json ([PR #192](https://github.com/agentuity/sdk-js/pull/192))
-
-## v0.0.149
-
-
- Released: October 3, 2025
-
-
-**Changes**
-
-- **Changed**: Prompt API signature from `_experimental_prompts()` method to `prompts` property ([PR #190](https://github.com/agentuity/sdk-js/pull/190))
-- **Added**: Generic types for prompts (PromptName, PromptObject, PromptsAPI) ([PR #190](https://github.com/agentuity/sdk-js/pull/190))
-- **Added**: Conditional exports with fallback handling for generated content ([PR #190](https://github.com/agentuity/sdk-js/pull/190))
-
-
-## v0.0.148
-
-
- Released: October 2, 2025
-
-
-**Changes**
-
-- **Added**: Experimental support for prompts ([PR #184](https://github.com/agentuity/sdk-js/pull/184))
-
-## v0.0.147
-
-
- Released: October 1, 2025
-
-
-**Changes**
-
-- **Added**: Support for automatic stream compression (defaults off) ([PR #186](https://github.com/agentuity/sdk-js/pull/186))
-- **Added**: Support for direct write to Stream in addition to getWriter() ([PR #186](https://github.com/agentuity/sdk-js/pull/186))
-- **Added**: Property `bytesWritten` to the Stream interface to track total bytes written ([PR #186](https://github.com/agentuity/sdk-js/pull/186))
-- **Added**: Property `compressed` to the Stream interface to indicate if compression is enabled ([PR #186](https://github.com/agentuity/sdk-js/pull/186))
-- **Fixed**: Remove explicit Content-Type header for application/json in GET requests ([PR #185](https://github.com/agentuity/sdk-js/pull/185))
-## v0.0.146
-
-
- Released: September 25, 2025
-
-
-**Changes**
-
-- **Added**: Add streams as first class context API ([PR #180](https://github.com/agentuity/sdk-js/pull/180))
-- **Added**: Add support for context.waitUntil to run background processing without blocking the response ([PR #179](https://github.com/agentuity/sdk-js/pull/179))
-- **Added**: Stream improvements with getReader() method, immediate waitUntil task scheduling, and automatic stream redirects ([PR #181](https://github.com/agentuity/sdk-js/pull/181))
-- **Added**: Support for waitUntil and low-level streams ([PR #182](https://github.com/agentuity/sdk-js/pull/182))
-- **Fixed**: Fix fetch function issues with streaming in certain environments ([PR #178](https://github.com/agentuity/sdk-js/pull/178))
-- **Fixed**: Fix spelling errors in link and repository information ([PR #177](https://github.com/agentuity/sdk-js/pull/177))
-- **Changed**: Update changelog formatting for v0.0.145 ([PR #175](https://github.com/agentuity/sdk-js/pull/175))
-
-## v0.0.145
-
-
- Released: September 8, 2025
-
-
-**Changes**
-
-- **Fixed**: Fix malformed From headers in email replies that caused parsing errors in backend ([PR #174](https://github.com/agentuity/sdk-js/pull/174))
-
-## v0.0.144
-
-
- Released: August 28, 2025
-
-
-**Changes**
-
-- **Fixed**: Issues between streaming for node and bun and keep alive differences
-
-## v0.0.143
-
-
- Released: August 28, 2025
-
-
-**Changes**
-
-- **Changed**: Use traceloop for otel for consistency across Python and TS SDK's ([PR #170](https://github.com/agentuity/sdk-js/pull/170))
-
-## v0.0.142
-
-
- Released: August 26, 2025
-
-
-**Changes**
-
-- **Changed**: Increase api timeout from 20 seconds to NEVER ([PR #168](https://github.com/agentuity/sdk-js/pull/168))
-
-## v0.0.141
-
-
- Released: August 25, 2025
-
-
-**Changes**
-
-- **Changed**: Restructured slack IO and payloads ([PR #164](https://github.com/agentuity/sdk-js/pull/164))
-- **Fixed**: Fix email attachment parsing for Slack-formatted filenames ([PR #160](https://github.com/agentuity/sdk-js/pull/160))
-- **Changed**: Use sessionId instead of runId for AgentContext to better align with how we reference it ([PR #165](https://github.com/agentuity/sdk-js/pull/165))
-
-## v0.0.140
-
-
- Released: August 19, 2025
-
-
-### Changes
-
-- **Fixed**: Fix cloud runs for teams agents with improved credential validation and metadata-driven configuration ([PR #162](https://github.com/agentuity/sdk-js/pull/162))
-
-## v0.0.139
-
-
- Released: August 18, 2025
-
-
-### Changes
-
-- **Added**: Teams support ([PR #161](https://github.com/agentuity/sdk-js/pull/161))
-
-## v0.0.138
-
-
- Released: August 8, 2025
-
-
-### Changes
-
-- **Fixed**: Fix the sms error ([PR #158](https://github.com/agentuity/sdk-js/pull/158))
-
-## v0.0.137
-
-
- Released: August 7, 2025
-
-
-### Changes
-
-- **Added**: Expose ts and ts_thread in the payload for Slack IO integration ([PR #157](https://github.com/agentuity/sdk-js/pull/157))
-
-## v0.0.136
-
-
- Released: August 4, 2025
-
-
-### Changes
-
-- **Changed**: The AgentResponse.stream() method now supports both function and generator transformers while maintaining full backward compatibility! The enhancement includes:
-
- **Original Requirements:**
- - Generic object streaming with automatic JSON conversion
- - Runtime type detection between ReadableDataType and objects
- - Auto-conversion to JSON newline format for objects
- - Intelligent content-type detection (application/json for objects)
- - Full backward compatibility
-
- **Function Transformer Enhancement:**
- - Optional transformer function as 4th parameter
- - Data transformation and filtering capabilities
- - Type safety with generic types
- - Error handling and edge cases
-
- **Generator Transformer Enhancement:**
- - Support for generator functions as alternative syntax
- - One-to-one transformation with yield syntax
- - Filtering support: generators can yield nothing to skip items
- - Same capabilities as regular functions but with generator syntax
-
- **Key Benefits:**
- - Maximum Flexibility: Choose between function or generator syntax
- - Developer Choice: Use familiar function syntax or expressive generator syntax
- - Consistent Behavior: Both approaches work identically
- - Type Safety: Full TypeScript support with generic types
- - Performance: Efficient one-to-one transformations
- - Backward Compatibility: Existing code continues to work unchanged
-
- **Test Coverage:**
- - 26 test cases covering all functionality
- - Function transformer scenarios (8 tests)
- - Generator transformer scenarios (7 tests)
- - Backward compatibility verified
- - Error handling tested
- - Mixed scenarios validated
- - Both ReadableStream and AsyncIterable support
-
- **Files Modified:**
- - src/types.ts - Enhanced interface with generator support
- - src/router/response.ts - Full implementation with generator detection and processing
- - test/router/response-stream.test.ts - Comprehensive test coverage
-
- The Agentuity SDK now provides the most flexible and powerful streaming API that supports object auto-conversion, intelligent content-type detection, data transformation, filtering, and both function and generator transformer syntaxes! ([PR #155](https://github.com/agentuity/sdk-js/pull/155))
-
-## v0.0.135
-
-
- Released: August 4, 2025
-
-
-### Changes
-
-- **Added**: Slack IO integration with support for parsing and replying to Slack messages ([PR #153](https://github.com/agentuity/sdk-js/pull/153))
-
-## v0.0.134
-
-
- Released: July 28, 2025
-
-
-### Changes
-
-- **Added**: Telegram IO integration with support for parsing and replying to Telegram messages ([PR #151](https://github.com/agentuity/sdk-js/pull/151))
-
-## v0.0.133
-
-
- Released: July 16, 2025
-
-
-### Changes
-
-- **Added**: Enable the ability to use custom email domains for email replies ([PR #149](https://github.com/agentuity/sdk-js/pull/149))
-
-
-Contact us if you would like to enable custom email addresses to your organization.
-
-
-## v0.0.132
-
-
- Released: July 14, 2025
-
-
- **Changes:**
-
-- **Changed**: DevMode fallback values for headers, url and method in metadata ([PR #148](https://github.com/agentuity/sdk-js/pull/148))
-
-## v0.0.131
-
-
- Released: July 8, 2025
-
-
- **Changes:**
-
-- **Added**: Support for bulk delete in vector storage - The `vector.delete()` method now accepts multiple keys as variadic arguments, allowing efficient bulk deletion of vectors. Supports both single key deletion (`delete(name, key)`) and bulk deletion (`delete(name, key1, key2, key3)`) patterns. This is more efficient than making multiple individual delete calls. ([PR #145](https://github.com/agentuity/sdk-js/pull/145))
-- **Changed**: Improved documentation of vector search parameters and tightened vector search metadata type definition ([PR #146](https://github.com/agentuity/sdk-js/pull/146))
-
-## v0.0.130
-
-
- Released: June 30, 2025
-
-
- **Changes:**
-
-- **Changed**: Shortened Discord interface from `discordMessage` to `discord` for improved usability ([PR #144](https://github.com/agentuity/sdk-js/pull/144))
-
-## v0.0.129
-
-
- Released: June 30, 2025
-
-
- **Changes:**
-
-- **Added**: Discord IO integration with support for parsing and replying to Discord messages ([PR #130](https://github.com/agentuity/sdk-js/pull/130))
-- **Fixed**: Release stream lock in all cases especially error scenarios ([PR #136](https://github.com/agentuity/sdk-js/pull/136))
-- **Fixed**: Issue with handoff not passing data from previous request ([PR #139](https://github.com/agentuity/sdk-js/pull/139))
-
-## v0.0.128
-
-
- Released: June 19, 2025
-
-
- **Changes:**
-
-- **Fixed**: Release stream lock in all cases especially error scenarios ([PR #136](https://github.com/agentuity/sdk-js/pull/136))
-
-## v0.0.127
-
-
- Released: June 19, 2025
-
-
- **Changes:**
-
-- **Added**: SMS Twilio IO functionality with support for parsing and replying to SMS messages ([PR #124](https://github.com/agentuity/sdk-js/pull/124))
-
-## v0.0.126
-
-
- Released: June 16, 2025
-
-
- **Changes:**
-
-- **Added**: Enhanced ObjectStore API with additional headers and metadata support ([PR #133](https://github.com/agentuity/sdk-js/pull/133))
-- **Changed**: Better handling for yield / generators ([PR #134](https://github.com/agentuity/sdk-js/pull/134))
-
-## v0.0.125
-
-
- Released: June 16, 2025
-
-
- **Changes:**
-
-- **Added**: Support for new object store API
-- **Fixed**: Description for similarity property for vector search
-- **Fixed**: Issue with incorrect type for Vector delete API
-
-## v0.0.124
-
-
- Released: June 9, 2025
-
-
- **Changes:**
-
-- **Changed**: Refactored Bun handler to consolidate logic and ensure all paths go through unified method ([PR #128](https://github.com/agentuity/sdk-js/pull/128))
-
-## v0.0.123
-
-
- Released: June 9, 2025
-
-
- **Changes:**
-
-- **Fixed**: Improved handling of requests for common static files and enhanced support for multiple path segments and different HTTP methods ([PR #126](https://github.com/agentuity/sdk-js/pull/126))
-
-## v0.0.122
-
-
- Released: June 9, 2025
-
-
- **Changes:**
-
-- **Added**: Support for large email attachments ([PR #123](https://github.com/agentuity/sdk-js/pull/123))
-
-## v0.0.121
-
-
- Released: May 25, 2025
-
-
- **Changes:**
-
-- **Added**: Support for agents to be able to reply to incoming email ([PR #118](https://github.com/agentuity/sdk-js/pull/118))
-
-## v0.0.120
-
-
- Released: May 24, 2025
-
-
- **Changes:**
-
-- **Added**: Support for handling inbound email trigger type ([PR #117](https://github.com/agentuity/sdk-js/pull/117))
-
-## v0.0.119
-
-
- Released: May 21, 2025
-
-
- **Changes:**
-
-- Logger message arg accepts number type ([PR #113](https://github.com/agentuity/sdk-js/pull/113))
-- Prevent multiple logs for the same exception ([PR #115](https://github.com/agentuity/sdk-js/pull/115))
-
-## v0.0.118
-
-
- Released: May 19, 2025
-
-
- **Changes:**
-
-- Improve error handling ([PR #111](https://github.com/agentuity/sdk-js/pull/111))
-
-## v0.0.117
-
-
- Released: May 19, 2025
-
-
- **Changes:**
-
-- **Improvement**: Better type handling for metadata where it can be any valid JSON object ([PR #110](https://github.com/agentuity/sdk-js/pull/110))
-
-## v0.0.116
-
-
- Released: May 18, 2025
-
-
- **Changes:**
-
-- Fixed issue where empty POST body would cause a hang ([PR #109](https://github.com/agentuity/sdk-js/pull/109))
-
-## v0.0.115 ⚠️
-
-
- Released: May 14, 2025
-
-
- **Changes:**
-
-- Added AGENTUITY_SDK_KEY ([PR #107](https://github.com/agentuity/sdk-js/pull/107))
-
- **⚠️ Breaking Changes**
-
-The environment variable `AGENTUITY_API_KEY` has been renamed to `AGENTUITY_SDK_KEY` for better clarity and consistency. You will need to update your environment variables and code references accordingly.
-
-If you're using the Agentuity CLI, it will detect this change and offer to automatically migrate your code references for you.
-
-For example, you'll need to make the following changes in your code and environment variables:
-
-```diff
-- process.env.AGENTUITY_API_KEY
-+ process.env.AGENTUITY_SDK_KEY
-```
-
-If you're using an Agentic code editor (such as Cursor, Windsurf, etc.), you can use this prompt to update your code with these changes:
-
-```
-The Agentuity SDK v0.0.115 has renamed AGENTUITY_API_KEY to AGENTUITY_SDK_KEY.
-Please find all instances of AGENTUITY_API_KEY in my code and replace them with AGENTUITY_SDK_KEY.
-```
-
-## v0.0.114
-
-
- Released: May 10, 2025
-
-
- **Changes:**
-
-- Fixed issue with Vector get type being wrong ([PR #106](https://github.com/agentuity/sdk-js/pull/106))
-
-## v0.0.113
-
-
- Released: May 8, 2025
-
-
- **Changes:**
-
-- Cross platform support for headers.toJSON ([PR #105](https://github.com/agentuity/sdk-js/pull/105), resolves [#103](https://github.com/agentuity/sdk-js/issues/103))
-
-## v0.0.112
-
-
- Released: May 2, 2025
-
-
- **Changes:**
-
-- Add a bun server handler to handle unhandled errors ([PR #100](https://github.com/agentuity/sdk-js/pull/100))
-- Add missing console methods ([PR #101](https://github.com/agentuity/sdk-js/pull/101))
-
-## v0.0.111
-
-
- Released: May 1, 2025
-
-
- **Changes:**
-
-- More fixes related to gzip compression when using keyvalue
-- Change the name of the span when doing a remote solution vs remote execution
-- Update to use versioned routes for API services ([PR #97](https://github.com/agentuity/sdk-js/pull/97))
-
-## v0.0.110
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-
-- In cloud we must bind to all addresses ([PR #96](https://github.com/agentuity/sdk-js/pull/96))
-
-## v0.0.109
-
-
- Released: April 29, 2025
-
-
- **Changes:**
-
-- Add the ability for an agent to return a Response object directly to provide more flexibility to integrate with existing APIs and protocols ([PR #93](https://github.com/agentuity/sdk-js/pull/93))
-- Bind explicitly to ipv4 when creating server ([PR #94](https://github.com/agentuity/sdk-js/pull/94))
-
-## v0.0.108
-
-
- Released: April 25, 2025
-
-
- **Changes:**
-
-- Fixed issue when the keyvalue returns a gzip encoded value ([PR #92](https://github.com/agentuity/sdk-js/pull/92))
-
-## v0.0.107
-
-
- Released: April 25, 2025
-
-
- **Changes:**
-
-- Fix issue with chunking and streaming text not matching in some cases ([PR #91](https://github.com/agentuity/sdk-js/pull/91))
-## v0.0.106 ⚠️
-
-
- Released: April 25, 2025
-
-
- **Changes:**
-
-- Add support for streaming data to and from agents. This includes streaming data to the agent via the `data` object and streaming data from the agent via the `stream` property of the `AgentResponse` object.
-- The `trigger` property of the `AgentRequest` object will have the value `agent` when the request is invoked by another agent.
-- The `AgentContext` object now has a `scope` property that will have the value of `local` when the context is local or `remote` when agent is being invoked by another agent remotely. In the case of agent-to-agent invocation or handoff within the same project, the scope will be `local`.
-- Deprecated the local `/run/:agentId` route since the updated `/:agentId` route now supports streaming data to and from the agent directly. This route will be removed in a near future release.
-
- **⚠️ Breaking Changes**
-
-The `data` object of `AgentRequest` has changed to support fully streaming data and this required a breaking change. Most of the property accessors are now async functions to support the streaming use case. You can read more about this change in [Pull Request #87](https://github.com/agentuity/sdk-js/pull/87).
-
-For example, the following code changes are required to get the request data as text:
-
-```diff
-- const text = req.data.text;
-+ const text = await req.data.text();
-```
-
-For example, to get the request data as JSON, you need to make the following changes:
-
-```diff
-- const json = req.data.json;
-+ const json = await req.data.json();
-```
-
-See the following documentation [Pull Request](https://github.com/agentuity/docs/pull/92) for specific SDK changes.
-
-If you're using an Agentic code editor (such as Cursor, Windsurf, etc.), you can use this prompt to update your code with these changes:
-
-```
-The agents in the agents folder use an older version of the Agentuity SDK which assume the req.data object has properties on it like req.data.json
-
-The new way to do this is with a promise. eg. `await req.data.json()`
-
-The breaking change is here: https://github.com/agentuity/sdk-js/pull/87
-
-Review this PR, make a plan to change the agents to the latest agentuity SDK with async await support, and execute on it.
-```
-
-## v0.0.105
-
-
- Released: April 23, 2025
-
-
- **Changes:**
-
-- Add support for remote agent handoff ([PR #85](https://github.com/agentuity/sdk-js/pull/85)). This means you can now handoff the request to another agent outside of your current project in the same organization or even outside of your organization if the Agent is public. The agent-to-agent invocation is secured automatically and doesn't require any additional configuration or authentication. Internally, the SDK will request a one-time authorization token to invoke the agent on your agent's behalf.
-
-## v0.0.104
-
-
- Released: April 23, 2025
-
-
- **Changes:**
-
-- Add support for remote agent-to-agent invocation ([PR #83](https://github.com/agentuity/sdk-js/pull/83)). This means you can now invoke another agent outside of your current project in the same organization or even outside of your organization if the Agent is public. The agent-to-agent invocation is secured automatically and doesn't require any additional configuration or authentication. Internally, the SDK will request a one-time authorization token to invoke the agent on your agent's behalf.
-
-## v0.0.103
-
-
- Released: April 23, 2025
-
-
- **Changes:**
-
-- Refactor to support binary streams instead of intermediate JSON protocol ([PR #81](https://github.com/agentuity/sdk-js/pull/81))
-- Improved handling of HTTP native protocol
-- Added support for passing in the runId
-- Better handling of stream data and binary content
-
-## v0.0.102
-
-
- Released: April 16, 2025
-
-
- **Changes:**
-
-- Fix issue where the child span had the wrong parent on outbound requests for agent-to-agent ([PR #79](https://github.com/agentuity/sdk-js/pull/79))
-
-## v0.0.101
-
-
- Released: April 18, 2025
-
-
- **Changes:**
-
-- Add agent context to console logger when running inside agent scope ([PR #77](https://github.com/agentuity/sdk-js/pull/77))
-
-## v0.0.100
-
-
- Released: April 15, 2025
-
-
- **Changes:**
-
-- Add permissions
-- Add more otel trace context headers, remove old trace provider ([PR #72](https://github.com/agentuity/sdk-js/pull/72))
-- Automatically base64 encode welcome prompts ([PR #73](https://github.com/agentuity/sdk-js/pull/73))
-- Fix NodeJS issue where the buffer isn't correctly sending the blob but works fine in Bun version ([PR #74](https://github.com/agentuity/sdk-js/pull/74))
-- Debug github workflow git tag issue
-
-## v0.0.99
-
-
- Released: April 14, 2025
-
-
- **Changes:**
-
-- More debug for github workflow
-
-## v0.0.98
-
-
- Released: April 13, 2025
-
-
- **Changes:**
-
-- More debug for github release tags
-
-## v0.0.97
-
-
- Released: April 12, 2025
-
-
- **Changes:**
-
-- Attempt to fix issue with github workflow not pushing tag after release
-
-## v0.0.96
-
-
- Released: April 11, 2025
-
-
- **Changes:**
-
-- Fix issue with node keyvalue not correctly handling the buffer upload
-
-## v0.0.95
-
-
- Released: April 10, 2025
-
-
- **Changes:**
-
-- Add more otel trace context headers, remove old trace provider
-- Base64 encode the welcome prompts
-
-## v0.0.94
-
-
- Released: April 8, 2025
-
-
- **Changes:**
-
-- Fix regression in otel traces missing for AI SDK by change in opentelemetry-api version change
-
-## v0.0.93
-
-
- Released: April 7, 2025
-
-
- **Changes:**
-
-- Add support for agent inspection discovery ([PR #70](https://github.com/agentuity/sdk-js/pull/70))
-
-## v0.0.92
-
-
- Released: April 5, 2025
-
-
- **Changes:**
-
-- Add data and markdown methods to AgentResponse interface and implementation
-
-## v0.0.91
-
-
- Released: April 3, 2025
-
-
- **Changes:**
-
-- Use new agentuity sdk api
-- Add GitHub workflow for npm package release triggered by version tags ([PR #53](https://github.com/agentuity/sdk-js/pull/53))
-
-## v0.0.90
-
-
- Released: April 1, 2025
-
-
- **Changes:**
-
-- Fix Vector delete api
-
-## v0.0.89
-
-
- Released: March 25, 2025
-
-
- **Changes:**
-
-- Add the agentName to the log attributes ([PR #33](https://github.com/agentuity/sdk-js/pull/33))
-- Console Logger: show max depth for any objects ([PR #32](https://github.com/agentuity/sdk-js/pull/32))
-- When stream is requested but the response isn't a stream, chunk up the response data into chunks and smooth out as if streamed ([PR #31](https://github.com/agentuity/sdk-js/pull/31))
-- Fixed issue with buffer underrun getting sent and issue with json encoding ([PR #34](https://github.com/agentuity/sdk-js/pull/34))
-
-## v0.0.88
-
-
- Released: March 21, 2025
-
-
- **Changes:**
-
-- Improve loading project when using node or bun directly vs using start script or agentuity dev
-- Fix mismatch between local run vs remote run with HTTP headers as property of metadata vs the metadata object
-
-## v0.0.87
-
-
- Released: March 18, 2025
-
-
- **Changes:**
-
-- Slight improvement in location of when context.logger for agent is created
-
-## v0.0.86
-
-
- Released: March 16, 2025
-
-
- **Changes:**
-
-- Add support for agentId on context.logger
-- Fix issue with underrun on base64 stream
-
-## v0.0.85
-
-
- Released: March 15, 2025
-
-
- **Changes:**
-
-- Streaming Support including SSE
-
-## v0.0.84
-
-
- Released: March 14, 2025
-
-
- **Changes:**
-
-- Stream IO Input: add new facility to support stream io for input data ([PR #23](https://github.com/agentuity/sdk-js/pull/23))
-- Release with new transport model
-
-## v0.0.83
-
-
- Released: March 12, 2025
-
-
- **Changes:**
-
-- Fix devmode logging when devmode environment is set by live ([PR #24](https://github.com/agentuity/sdk-js/pull/24))
-
-## v0.0.82
-
-
- Released: March 12, 2025
-
-
- **Changes:**
-
-- KeyValue compression only on upload, not download ([PR #20](https://github.com/agentuity/sdk-js/pull/20))
-
-## v0.0.81
-
-
- Released: March 11, 2025
-
-
- **Changes:**
-
-- Add support for compressing keyvalue entries ([PR #19](https://github.com/agentuity/sdk-js/pull/19))
-- Better format log message if the first parameter is an object ([PR #18](https://github.com/agentuity/sdk-js/pull/18))
-
-## v0.0.80
-
-
- Released: March 10, 2025
-
-
- **Changes:**
-
-- Refactored the types to make it easier to use
-- Fixed various small issues
-
-## v0.0.79 and earlier
-
-For earlier versions, see the [CHANGELOG.md](https://github.com/agentuity/sdk-js/blob/main/CHANGELOG.md) file in the repository.
diff --git a/content/Changelog/sdk-py.mdx b/content/Changelog/sdk-py.mdx
deleted file mode 100644
index f70ba7b6..00000000
--- a/content/Changelog/sdk-py.mdx
+++ /dev/null
@@ -1,448 +0,0 @@
----
-title: Python SDK Changelog
-description: Release notes and version history for the Agentuity Python SDK
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-This page documents the release history of the [Agentuity Python SDK](https://github.com/agentuity/sdk-py).
-
-## v0.0.105
-
-
- Released: August 28, 2025
-
-
- **Changes:**
-- **Fixed:** Fixed issue with session_id formatting in OpenTelemetry tracing to ensure proper string conversion
-
-## v0.0.104
-
-
- Released: August 28, 2025
-
-
-**⚠️ Breaking Changes:**
-
-- AgentContext constructor parameter renamed from `run_id` to `session_id` for better alignment with session references. The `runId` property remains available for backward compatibility but is deprecated.
-
-**Changed:**
-
-- Switch from OpenLIT to TraceLoop SDK for OpenTelemetry instrumentation to improve async context management
-
-**Fixed:**
-
-- Resolved "context attached/detached in a different context" warnings in async environments, particularly with LangChain instrumentation
-## v0.0.103
-
-
- Released: August 8, 2025
-
-
-**Added:**
-
-- Telegram IO support with comprehensive Telegram integration capabilities
-- New Telegram API module for Telegram-specific operations and utilities
-- Telegram data processing support in the data layer for handling Telegram-specific content types
-
-**Changed:**
-
-- Updated agent directory structure to prefer `agentuity_agents` over `agentuity-agents` for improved Python compatibility
-
-## v0.0.102
-
-
- Released: July 16, 2025
-
-
- **Changes:**
-- **Added:** Enable the ability to use custom email domains for email replies
-
-
-Contact us if you would like to enable custom email addresses to your organization.
-
-
-## v0.0.101
-
-
- Released: July 14, 2025
-
-
- **Changes:**
-- **Fixed:** DevMode: make sure certain props are set on metadata for improved development mode debugging
-
-## v0.0.100 ⚠️
-
-
- Released: June 30, 2025
-
-
- **Changes:**
-- **Changed:** Shortened Discord interface method name from `discord_message()` to `discord()` for improved usability
-
- **⚠️ Breaking Changes**
-
-The Discord interface method has been renamed from `discord_message()` to `discord()`. Update your code to use the new method name:
-
-```diff
-- message = await req.data.discord_message()
-+ message = await req.data.discord()
-```
-
-## v0.0.98
-
-
- Released: June 19, 2025
-
-
- **Changes:**
-- **Fixed:** Email: text and html should return a str not a list of str to match JS behavior
-
-## v0.0.97
-
-
- Released: June 19, 2025
-
-
- **Changes:**
-- **Fixed:** Filter out empty headers from headers special HTTP header
-
-## v0.0.96
-
-
- Released: June 19, 2025
-
-
- **Changes:**
-- **Added:** Enhanced ObjectStorePutParams with additional headers and metadata support
-- **Fixed:** Fixed difference in HTTP header casing and other cleanup items
-
-## v0.0.95
-
-
- Released: June 13, 2025
-
-
- **Changes:**
-- **Added:** ObjectStore service with comprehensive object storage capabilities including get, put, delete, and public URL generation
-## v0.0.94
-
-
- Released: June 11, 2025
-
-
- **Changes:**
-- **Fixed:** Fixed naming conflict with openAI Agents SDK by renaming agents directory to agentuity-agents with backward compatibility
-- **Fixed:** Removed ruff from runtime dependencies as it's only needed for development
-
-## v0.0.93
-
-
- Released: June 9, 2025
-
-
- **Changes:**
-- **Fixed:** Improved route handling for extra path segments and better 404 error messages
-- **Fixed:** Enhanced logging to display actual HTTP method and full request path
-- **Fixed:** Simplified health check response headers and consolidated route registration
-
-## v0.0.92
-
-
- Released: June 9, 2025
-
-
- **Changes:**
-- **Added:** Email class support for large attachments and send reply functionality
-- **Added:** Structured interfaces for agent requests, context, data, and email processing with streaming and async capabilities
-- **Added:** Ability to send reply emails with attachments and telemetry support
-- **Changed:** Standardized naming conventions for content type attributes across the application
-- **Changed:** Enhanced encapsulation and interface compliance for agent context, data, and request objects
-- **Changed:** Deprecated legacy property names in favor of new, consistent ones, with warnings for backward compatibility
-- **Fixed:** Added OpenTelemetry tracing headers to HTTP requests for improved observability
-- **Fixed:** Corrected attribute names in tests and code to ensure consistent access to content type properties
-
-## v0.0.91
-
-
- Released: May 31, 2025
-
-
- **Changes:**
-- **Added:** LlamaIndex instrumentation for automatic Agentuity gateway integration
-- **Added:** LlamaIndex now automatically uses Agentuity API key and gateway when no OpenAI API key is provided
-- **Added:** OpenAI client patching within LlamaIndex for seamless Agentuity integration
-
-## v0.0.90
-
-
- Released: May 30, 2025
-
-
- **Changes:**
-- **Fixed:** Apply safe filename fix similar to CLI and always prefer to load config but fallback to yaml in dev
-
-## v0.0.89
-
-
- Released: May 29, 2025
-
-
- **Changes:**
-- **Fixed:** Fix outgoing requests missing traceid in OpenTelemetry instrumentation
-
-## v0.0.88
-
-
- Released: May 28, 2025
-
-
- **Changes:**
-- **Added:** Agent startup checks with stack trace printing in development mode
-- **Fixed:** Fixed issue with OTel trace id not getting propagated correctly and causing it not to be associated with the correct session in production
-
-## v0.0.87
-
-
- Released: May 27, 2025
-
-
- **Changes:**
-- **Fixed:** Fixed handoff issues by implementing deferred handoff execution with improved error handling and agent communication
-- **Fixed:** Added configurable HTTP timeouts for agent communication
-- **Fixed:** Improved connection error handling for client disconnections during streaming
-
-## v0.0.86
-
-
- Released: May 24, 2025
-
-
- **Changes:**
-- **Added:** Email class for parsing inbound email messages with support for extracting subject, sender, recipients, and attachments
-- **Added:** Async email() method to Data class for parsing RFC822 email content
-- **Added:** mail-parser dependency for email parsing functionality
-- **Changed:** Updated AgentResponse.handoff() to accept DataLike types instead of only dict for improved flexibility
-- **Changed:** Enhanced JSON serialization in AgentResponse.json() with better error handling and fallback for objects with __dict__
-- **Fixed:** Fixed duplicate variable assignment in RemoteAgent.run() method
-
-## v0.0.85
-
-
- Released: May 22, 2025
-
-
-**Added:**
-
-- Added support for constructing data objects from both synchronous and asynchronous byte iterators ([#45](https://github.com/agentuity/sdk-py/pull/45))
-- Added synchronous reading methods for data objects ([#45](https://github.com/agentuity/sdk-py/pull/45))
-
-**Changed:**
-
-- Improved local development instructions in README ([#44](https://github.com/agentuity/sdk-py/pull/44))
-- Enhanced agent input handling to accept a broader range of data types ([#45](https://github.com/agentuity/sdk-py/pull/45))
-- Configured explicit timeout settings for agent network operations ([#45](https://github.com/agentuity/sdk-py/pull/45))
-
-**Fixed:**
-
-- Improved data conversion logic to handle a wider range of input types ([#45](https://github.com/agentuity/sdk-py/pull/45))
-
-## v0.0.84 ⚠️
-
-
- Released: May 14, 2025
-
-
-**Added:**
-
-- Added AGENTUITY_SDK_KEY ([#42](https://github.com/agentuity/sdk-py/pull/42))
-
- **⚠️ Breaking Changes**
-
-The environment variable for API authentication has changed from `AGENTUITY_API_KEY` to `AGENTUITY_SDK_KEY`. You will need to update any references to this environment variable in your code and deployment configurations.
-
-For example, the following changes are required:
-
-```diff
-- os.environ["AGENTUITY_API_KEY"] = "your-api-key"
-+ os.environ["AGENTUITY_SDK_KEY"] = "your-api-key"
-```
-
-When using the Agentuity CLI, it will detect this change and ask if you would like assistance migrating your code automatically.
-
-If you're using an Agentic code editor (such as Cursor, Windsurf, etc.), you can use this prompt to update your code with these changes:
-
-```
-The Agentuity SDK v0.0.115 has renamed AGENTUITY_API_KEY to AGENTUITY_SDK_KEY.
-Please find all instances of AGENTUITY_API_KEY in my code and replace them with AGENTUITY_SDK_KEY.
-```
-
-## v0.0.83
-
-
- Released: May 9, 2025
-
-
-**Fixed:**
-
-- Fix issue vectors, better typing for Vector and KeyValue in context ([#40](https://github.com/agentuity/sdk-py/pull/40))
-
-## v0.0.82 ⚠️
-
-
- Released: April 30, 2025
-
-
- **Changes:**
-
-- Add support for streaming data to and from agents. This includes streaming data to the agent via the `data` object and streaming data from the agent via the `stream` property of the `AgentResponse` object.
-- The `trigger` property of the `AgentRequest` object will have the value `agent` when the request is invoked by another agent.
-- The `AgentContext` object now has a `scope` property that will have the value of `local` when the context is local or `remote` when agent is being invoked by another agent remotely. In the case of agent-to-agent invocation or handoff within the same project, the scope will be `local`.
-- Deprecated the local `/run/:agentId` route since the updated `/:agentId` route now supports streaming data to and from the agent directly. This route will be removed in a near future release.
-
- **⚠️ Breaking Changes**
-
-The `data` object of `AgentRequest` has changed to support fully streaming data and this required a breaking change. Most of the property accessors are now async functions to support the streaming use case. You can read more about this change in [Pull Request #38](https://github.com/agentuity/sdk-py/pull/38).
-
-For example, the following code changes are required to get the request data as text:
-
-```diff
-- text = req.data.text;
-+ text = await req.data.text();
-```
-
-For example, to get the request data as JSON, you need to make the following changes:
-
-```diff
-- json = req.data.json;
-+ json = await req.data.json();
-```
-
-See the following documentation [Pull Request](https://github.com/agentuity/docs/pull/114) for specific SDK changes.
-
-If you're using an Agentic code editor (such as Cursor, Windsurf, etc.), you can use this prompt to update your code with these changes:
-
-```
-The agents in the agents folder use an older version of the Agentuity SDK which assume the req.data object has properties on it like req.data.json
-
-The new way to do this is with a promise. eg. `await req.data.json()`
-
-The breaking change is here: https://github.com/agentuity/sdk-py/pull/38
-
-Review this PR, make a plan to change the agents to the latest agentuity SDK with async await support, and execute on it.
-```
-
-## v0.0.77
-
-
- Released: April 7, 2025
-
-
-**Added:**
-
-- Add comprehensive test suite with pytest ([#27](https://github.com/agentuity/sdk-py/pull/27))
-- Expand test coverage for logger, context, and langchain instrumentation ([#28](https://github.com/agentuity/sdk-py/pull/28))
-- Add agent inspect endpoint support ([#29](https://github.com/agentuity/sdk-py/pull/29))
-
-## v0.0.76
-
-
- Released: April 3, 2025
-
-
-**Fixed:**
-
-- Fix Langchain instrumentation and add openai-agents dependency ([#24](https://github.com/agentuity/sdk-py/pull/24))
-
-## v0.0.75
-
-
- Released: April 1, 2025
-
-
-**Added:**
-
-- Add data and markdown methods to AgentResponse class ([#26](https://github.com/agentuity/sdk-py/pull/26))
-- Add PyPI release workflow ([#22](https://github.com/agentuity/sdk-py/pull/22))
-
-**Changed:**
-
-- Update logo URL from relative to absolute path ([#19](https://github.com/agentuity/sdk-py/pull/19))
-- Remove 'work in progress' warning from README ([#20](https://github.com/agentuity/sdk-py/pull/20))
-- Update Agentuity gateway URL from /llm/ to /gateway/ ([#21](https://github.com/agentuity/sdk-py/pull/21))
-- Update to use AGENTUITY_CLOUD_PORT with fallback to PORT ([#23](https://github.com/agentuity/sdk-py/pull/23))
-- Use transport instead of API for hosted SDK api ([#25](https://github.com/agentuity/sdk-py/pull/25))
-- Update CHANGELOG.md for v0.0.74 ([#18](https://github.com/agentuity/sdk-py/pull/18))
-
-## v0.0.74
-
-
- Released: March 25, 2025
-
-
-**Added:**
-
-- Better support for OpenAI and Agents framework ([#16](https://github.com/agentuity/sdk-py/pull/16))
-- Add agentName to logger ([#17](https://github.com/agentuity/sdk-py/pull/17))
-
-## v0.0.73
-
-
- Released: March 19, 2025
-
-
-**Fixed:**
-
-- Fix issue with non-stream functionality ([#15](https://github.com/agentuity/sdk-py/pull/15))
-
-## v0.0.72
-
-
- Released: March 16, 2025
-
-
-**Added:**
-
-- Add the @agentuity/agentId to the context.logger for an agent ([#13](https://github.com/agentuity/sdk-py/pull/13))
-
-**Fixed:**
-
-- Fix import issue and add ruff for formatting and linting ([#14](https://github.com/agentuity/sdk-py/pull/14))
-
-## v0.0.71
-
-
- Released: March 16, 2025
-
-
-**Added:**
-
-- SSE and Stream support with new stream() method and improved documentation ([#12](https://github.com/agentuity/sdk-py/pull/12))
-
-## v0.0.70
-
-
- Released: March 13, 2025
-
-
-**Added:**
-
-- Stream IO Input: add new facility to support stream io for input data ([#10](https://github.com/agentuity/sdk-py/pull/10))
-
-## v0.0.69
-
-
- Released: March 10, 2025
-
-
- **Changes:**
-
-- Implemented Vector and KeyValue services
-- Reorganized types into logical files
-- Added support for local handoff
-- Improved error handling
-- Added support for dynamic return types
-- Added `get_agents` method on context
-- Moved `autostart` into main package
-- Added tracing for remote agent calls
-- Added httpx dependency for improved HTTP client support
diff --git a/content/Cloud/agents.mdx b/content/Cloud/agents.mdx
deleted file mode 100644
index 5a7a5ea1..00000000
--- a/content/Cloud/agents.mdx
+++ /dev/null
@@ -1,469 +0,0 @@
----
-title: Agents
-description: The agents page is for managing your agents
----
-
-## Agent Dashboard Overview
-
-The agent dashboard provides a list of your agents. This page helps you monitor your agent's status, usage metrics, and recent activity.
-
-
-
-### Managing an Agent
-
-You can select a specific agent to view and manage its details. The agent detail page provides a list of the agent's inputs and outputs, recent sessions and overview of costs.
-
-
-
-### Agent Input & Output
-
-Agents receive data from various sources and send data to various destinations (input and output, or we call it IO).
-
-
-
-You can think of the agent as an intelligent black box that receives data from sources and responds with data which is sent to the configured destinations.
-
-Read the [Agent IO](/Guides/agent-io) guide for more information.
-
-You can add a new input or output by clicking the plus button in the agent IO visualization.
-
-
-
-When you agent is invoked, it will process the data and send the output to the output destination.
-
-The agent request object will contain a property called `trigger` that will contain the source that triggered the agent. You can use this to determine the source of the data and process it accordingly. This is particularly useful when you are using multiple sources to trigger the same agent.
-
-
-
-#### Webhook Source
-
-To configure your agent to receive data from a webhook, you need to add a new webhook source. When receiving data from a webhook, the agent will send the data to the agent's inputs asynchronously without waiting for the agent to finish processing the data.
-
-
-
-For Webhook sources, you can require authorization to access the webhook. This is useful if you want to protect your webhook from unauthorized access.
-
-The following authentication methods are supported:
-
-| Type | Description |
-|---------|-------------|
-| Project | Authenticated using the project API Key |
-| Public | No authentication required - webhook is publicly accessible |
-| Bearer | Authenticated using Bearer Token via `Authorization: Bearer ` header |
-| Basic | Authenticated using Basic Auth via `Authorization: Basic :` header |
-| Header | Authenticated using custom header via `: ` header |
-
-When using the Bearer, Basic or Header authentication methods, you can specify the authentication values for each agent.
-
-To trigger a webhook using curl with a required Bearer token authentication, you can use the following command:
-
-' \\\n\t--json '{"some":"data"}'`} />
-
-
- Make sure to use the correct agent ID in the webhook URL.
-
-
-The response from the webhook will contain an informational message if successful. Additionally, the `Location` header will contain the URL that can be used to read the agent output. This URL will block until the agent has started streaming the output response.
-
-#### API Source
-
-To configure your agent to receive data as an API endpoint, you need to add a new API source. When receiving data from an API endpoint, the agent will send the data to the agent's inputs synchronously and wait for the agent to respond.
-
-
-
-For API sources, you can require authorization to access the API. This is useful if you want to protect your API from unauthorized access.
-
-The following authentication methods are supported:
-
-| Type | Description |
-|---------|-------------|
-| Project | Authenticated using the project API Key |
-| Public | No authentication required - webhook is publicly accessible |
-| Bearer | Authenticated using Bearer Token via `Authorization: Bearer ` header |
-| Basic | Authenticated using Basic Auth via `Authorization: Basic :` header |
-| Header | Authenticated using custom header via `: ` header |
-
-When using the Bearer, Basic or Header authentication methods, you can specify the authentication values for each agent.
-
-When you plan on using the API source, it is recommended that you stream data to and from the agent.
-
-To invoke an API using curl with a required Bearer token authentication, you can use the following command:
-
-' \\\n\t--json '{"some":"data"}'`} />
-
-
- Make sure to use the correct agent ID in the webhook URL.
-
-
-#### Email Source
-
-For Email sources, you can configure your agent at a unique agent email address. When receiving an email, the agent will send the email content to the agent's inputs asynchronously without waiting for the agent to finish processing the email.
-
-
-
-
- An email source can only be triggered by an email sent to the agent's email address and not via the API.
-
-
-After an email is received, the platform will enqueue processing and your agent will handle the message asynchronously. Any replies will be delivered via the configured destination(s).
-
-#### Discord Source
-
-For Discord sources, you can configure your agent to receive messages from a Discord server. When a user tags the bot in a Discord message, the agent will receive the message content asynchronously without waiting for the agent to finish processing the message.
-
-
-
-
- You must have a Discord account linked to your Agentuity account to use Discord Integration. The bot must be invited to your Discord server before it can receive messages.
-
-
-**Prerequisite: Connecting Your Account**
-
-Before configuring a Discord source, you must first link your personal Discord account to Agentuity. This one-time setup allows Agentuity to see your available servers.
-
-1. Click your user profile name in the bottom-left corner of the App.
-2. Select **Account** from the menu that appears.
-3. In your Profile settings, find the **Connected accounts** section and click the **Connect account** button to add Discord.
-4. Follow the authorization flow in the pop-up window to grant the requested permissions.
-
-**Configuration Steps**
-
-To set up Discord Integration:
-
-1. **Add Discord IO**: Click the plus button in the agent IO visualization and select Discord
-2. **Select Server**: Choose a Discord server from your connected servers
-3. **Invite Bot**: If the bot isn't already in the server, use the provided invite link to add the Agentuity bot to your Discord server
-4. **Tag Bot**: Once configured, tag the bot (@Agentuity) in Discord messages to forward them to your agent
-
-The Discord Integration provides the following data when a message is forwarded:
-
-- **Message Content**: The text content of the Discord message
-- **Author Information**: Username and user ID of the message author
-- **Server Context**: Guild ID and channel ID
-- **Message ID**: Unique identifier for the Discord message
-
-When your agent receives a Discord message, you can access the Discord-specific data through the request object:
-
-
-
-
- Discord sources can only be triggered by messages where the bot is tagged in a Discord server. The bot cannot receive all messages in a channel for privacy reasons.
-
-
-{/* #### Slack Source
-
-For Slack sources, you can configure your agent to receive messages from a Slack workspace. Users @mention your agent in Slack to trigger responses. By default, replies are sent as threads (configurable).
-
-
-
-To set up Slack Integration, you'll need to create a Slack App and configure OAuth:
-
-1. **Create a Slack App** in your Slack workspace
-2. **Configure OAuth** with the following credentials:
- - App Name
- - Client ID
- - Client Secret
- - Signing Secret
-3. **Set OAuth Redirect URL** to: `https://api.agentuity.com/io/slack/source/oauth/callback`
-4. **Configure Event Subscriptions** with the Request URL provided by Agentuity
-5. **Subscribe to Bot Events**: `message.channels`, `message.im`, `app_mention`
-
-
- You must configure OAuth and Event Subscriptions in your Slack App settings for the integration to work properly.
- */}
-
-#### Telegram Source
-
-For Telegram sources, you can configure your agent to receive messages from Telegram users. Users can message your agent directly on Telegram.
-
-
-
-To configure a Telegram source:
-
-1. **Get a Bot Token** from @BotFather on Telegram
-2. **Enter the Bot Token** in the configuration
-
-#### SMS Source
-
-For SMS sources, you can connect your Twilio account to allow your agent to be triggered by incoming text messages. This requires providing your Twilio API credentials.
-
-
-
-To configure an SMS source, you will need the following credentials from your Twilio console:
-- **Account SID**
-- **API SID**
-- **API Secret**
-
-Once validated, you can select one or more of your Twilio numbers to forward incoming messages to your agent.
-
-#### Schedule Source
-
-For running an agent on a schedule, you can configure your agent to use a cron source. When the agent is scheduled to run, the agent will send the data to the agent's inputs asynchronously without waiting for the agent to finish processing the data.
-
-
-
-When creating a new schedule, you can specify the cron expression to run the agent. The cron expression is a string that represents the schedule to run the agent.
-
-Click the sparkle icon to help you create a new cron expression using AI.
-
-You can optionally specify a content type and payload to send to the agent when the agent is scheduled to run.
-
-A cron source can only be triggered internally by the Agentuity Platform and not via the API. However, you can trigger a scheduled agent to run by selecting the schedule and selecting "Manual Run" in the context menu.
-
-
-
-#### Discord Destination
-
-For Discord destinations, you can configure your agent to send messages to a Discord channel when triggered by external sources (webhooks, APIs, other agents, etc.). This is different from Discord sources which handle @mentions within Discord.
-
-
-
-To configure a Discord destination:
-
-1. **Select a Discord Server** from your connected servers
-2. **Choose a Channel** where messages will be sent
-3. **Invite the Bot** if not already in the server using the provided invite link
-
-
- The bot must be invited to your Discord server before you can configure it as a destination. Use the invite link provided if you see "Bot not found in server" error.
-
-
-#### Email Destination
-
-For Email destinations, you can configure your agent to send emails when triggered.
-
-By default, emails are sent from `no-reply@agentuity.run`:
-
-
-
-When you also configure Email as a source (inbound), your agent gets a dedicated email address that can be used as well:
-
-
-
-All in all, there are three sender address options:
-
-- **Default**: Sends from `no-reply@agentuity.run`
-- **With Inbound Email**: Sends from your agent's address `[agent-id]@agentuity.run`
-- **Custom Domain** (Enterprise): Use your organization's domain for outbound emails
-
-Configuration requires:
-- **Recipient Addresses**: List of email addresses to send to
-- **Subject Line**: Email subject for outbound messages
-
-> Note: Email subject and recipients can only be configured through the UI at this time.
-
-
- **Enterprise Feature:** Organizations can configure custom email domains for outbound emails. This requires DNS configuration and is currently only available through Agentuity support. Contact us to set up custom email domains for your organization.
-
-
-### Agent Deployments
-
-Agentuity supports continuous deployment using a native GitHub App integration and a GitHub Actions workflow.
-
-#### GitHub App Integration
-
-The GitHub App integration is a native integration that allows you to deploy your agents to the Agentuity Platform from your GitHub repository.
-
-To enable the GitHub App integration, you need to provide permission for Agentuity to access your GitHub account. On your Project Settings page, you can find the GitHub App integration.
-
-
-
-Once connected, each Project can be configured to deploy from a specific GitHub repository automatically.
-
-
-
-When a new commit is pushed to the repository, the GitHub Actions workflow will be triggered and the agent will be deployed to the Agentuity Platform.
-
-
-
-You can select a specific deployment to view the deployment details including logs.
-
-
-
-When using GitHub to deploy (either the GitHub App or the GitHub Actions workflow), your GitHub commit information will be displayed in the deployment details.
-
-You can see all the projects that are connected to your GitHub account in the Settings > Integrations section.
-
-
-
-From here you can disconnect a specific project from your GitHub account or disconnect Agentuity from your GitHub account.
-
-#### GitHub Actions Workflow
-
-The GitHub Actions workflow is a native integration that allows you to deploy your agents to the Agentuity Platform from your GitHub repository using GitHub Actions.
-
-You can install the GitHub Actions workflow by visiting the [Agentuity GitHub Actions Marketplace](https://github.com/marketplace/actions/agentuity-deploy-action) and clicking the "Install" button.
-
-
-
-You can also directly use the [Agentuity GitHub Actions](https://github.com/agentuity/deploy-action) repository to deploy your agents to the Agentuity Platform.
-
-#### Manual Deployment
-
-You can also manually deploy your agents to the Agentuity Platform with the CLI using the following command:
-
-
-
-By default, the CLI will use the `latest` tag to deploy your agents. You can specify one or more tags to deploy by using the `--tag` flag. The active deployment will only be used for agent requests based on the `latest` tag.
-
-You can test new versions of your agents by using the `--tag` flag to specify a specific tag and then using the tag in either the `webhook` or `api` source.
-
-For example, if you have a tag called `v1.0.0`, you can use the following command to deploy it:
-
-
-
-This will tag the deployment with the `v1.0.0` tag but not make it the active deployment.
-
-You can the invoke the agent with the `v1.0.0` tag by using curl with the following command:
-
-' \\\n\t--json '{"some":"data"}'`} />
-
-
- Make sure to use the correct agent ID and tag in the API URL. Also, make sure to use the correct authentication token and that you have configured the API source.
-
-
-#### Rollback & Delete
-
-You can rollback to a previous deployment by using the CLI with the following command:
-
-
-
-If you would like to delete the deployment in addition to rolling back, you can use the `--delete` flag.
-
-
-
-You can select a specific deployment:
-
-
-
-### Agent Logs
-
-You can view the logs for a specific agent by selecting the agent and then clicking the "Logs" tab.
-
-
-
-If you select a specific log, you can view the log detail for the specific log entry.
-
-
-
-### Agent Sessions
-
-The sessions dashboard provides a list of your agent sessions. This page helps you monitor your agent's status, usage metrics, and recent activity.
-
-
-
-If you select a specific session, you can view the session detail for the specific session.
-
-
-
-If you select a specific span, a session span trace detail will be displayed with specific detail about the execution of the span.
-
-
-
-## CLI
-
-You can use the CLI to manage your agents using the following command:
-
-
-
-See the [CLI documentation](/CLI/agent) for more information on specific command usage and flags.
diff --git a/content/Cloud/aigateway.mdx b/content/Cloud/aigateway.mdx
deleted file mode 100644
index b0744516..00000000
--- a/content/Cloud/aigateway.mdx
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: AI Gateway
-description: The AI Gateway page is for understanding your AI Gateway usage
----
-
-## Understanding the AI Gateway
-
-
-
-## Viewing Your Session Usage
-
-When you navigate to the AI Gateway > Sessions page in the Cloud Console, you'll see a table listing all your sessions with the following information:
-
-- **Agent**: The name of your agent
-- **Provider**: The AI provider used for the session
-- **Model**: The model used for the session
-- **LLM Cost**: The cost of the LLM used for the session
-- **Timestamp**: The session timestamp
-
-You can filter the list of sessions using the search box at the top of the table to quickly find specific sessions or filter by properties such as provider.
-
-## Session Detail
-
-You can select a key value instance to view and manage its data.
-
-
-
-## AI Gateway Usage
-
-By default, when your agent is not configured to use a specific AI provider using the override, it will use the AI Gateway to route requests to the appropriate providers automatically.
-
-To override using the AI Gateway, use the AI provider specific environment variables to configure them.
-
-For example, to use the OpenAI API and use your own API key, you can set the provider API Gateway in the `.env` file of your agent project:
-
-```
-OPENAI_API_KEY=your-api-key
-```
-
-When you deploy your agent project, your agent will use the OpenAI API directly instead of the AI Gateway.
-
-
-Each AI Provider uses their own API Key and configuration. Please consult the documentation for your specific provider to learn how to set up the API Key.
-
diff --git a/content/Cloud/api-keys.mdx b/content/Cloud/api-keys.mdx
deleted file mode 100644
index ab10a01d..00000000
--- a/content/Cloud/api-keys.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: API Keys
-description: The API Keys page is for managing your API keys
----
-
-## Viewing Your API Keys
-
-When you navigate to the API Keys page in the Cloud Console (under Settings), you'll see a table listing all your API keys with the following information:
-
-- **Name**: The descriptive name you've given to the API key
-- **Key**: The actual API key value (hidden by default for security)
-- **Expires**: When the API key will expire
-- **Last Used**: When the API key was last used
-- **Owner**: The user who created the API key
-
-
-
-## Creating a New API Key
-
-To create a new API key:
-
-1. Navigate to the API Keys page in the Cloud Console (under Settings)
-2. Click the "Create API Key" button in the top-right corner
-3. In the dialog that appears:
- - Enter a descriptive name for the key (e.g., "Production API Key")
- - Set an expiration date for the key
-4. Click "Create Key" to generate the new API key
-5. **Important**: Copy the API key value immediately, as it will only be shown once
-
-Note: An API key is automatically created when you create a new project. You can view and manage this key in the API Keys page.
-
-
-
-## CLI
-
-You can use the CLI to manage your API keys using the following command:
-
-
-
-See the [CLI documentation](/CLI/apikey) for more information on specific command usage and flags.
\ No newline at end of file
diff --git a/content/Cloud/index.mdx b/content/Cloud/index.mdx
deleted file mode 100644
index 87e5803f..00000000
--- a/content/Cloud/index.mdx
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: Overview
-description: Introduction to the Agentuity Cloud Console and its features
----
-
-The Agentuity Cloud Console is a web-based interface for managing your Agentuity resources, projects, and settings. This guide provides an overview of the main features and functionality available in the Cloud Console.
-
-- Create and manage projects via the [Project Dashboard](/Cloud/project)
-- Configure settings and API keys [API Keys](/Cloud/api-keys)
-- Manage agentic services ([Vector](/Cloud/vector-memory), [Key-Value](/Cloud/key-value-memory), and [AI Gateway](/Cloud/aigateway))
-- Monitor agent deployments and runs via the [Agent Dashboard](/Cloud/agents)
-- View logs and telemetry data via the [Sessions](/Cloud/sessions)
-
-### Agentic Services
-
-The Services section provides tools for managing different types of agentic services:
-
-- **[Vector Memory Storage](/Cloud/vector-memory)**: For semantic search and large context windows, ideal for knowledge bases and historical data
-- **[Key Value Storage](/Cloud/key-value-memory)**: For fast, simple, or temporary data storage or caching
-- **[AI Gateway](/Cloud/aigateway)**: For managing access to various AI models and their usage and billing
-
-### Settings and Configuration
-
-The Settings section allows you to manage various configuration options:
-
-- **[API Keys](/Cloud/api-keys)**: Create and manage API keys for authenticating with Agentuity services
-- **[Organization Settings](/Cloud/organization)**: Manage organization details and members
-- **User Profile**: Update your user profile and preferences
diff --git a/content/Cloud/key-value-memory.mdx b/content/Cloud/key-value-memory.mdx
deleted file mode 100644
index 0dc75be7..00000000
--- a/content/Cloud/key-value-memory.mdx
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: Key Value Storage
-description: The Key Value Storage page is for managing your key value memory storage
----
-
-## Understanding Key Value Storage
-
-Key value memory storage is designed for fast, simple, or temporary data storage, making it ideal for:
-
-- Session data
-- Configuration settings
-- Caching
-- Temporary state management
-- Simple data structures
-- Sharing state between agents
-
-
-
-## Viewing Your Key Value Instances
-
-When you navigate to the Memory > Key Value page in the Cloud Console, you'll see a table listing all your key value instances with the following information:
-
-- **Name**: The name of your key value instance
-- **Size**: The storage size used by the key value instance
-
-You can filter the list of key value instances using the search box at the top of the table to quickly find specific instances by name.
-
-## View Key Value Data
-
-You can select a key value instance to view and manage its data.
-
-
-
-## Creating a New Key Value Instance
-
-There are two ways to create a new key value instance:
-
-1. From the Services > Key Value page in the Cloud Console
-2. In code, using the Agentuity SDK
-
-When creating a key value instance from the Cloud Console, click the **Create Storage** button and select **Key Value Store** from the storage type options.
-
-
\ No newline at end of file
diff --git a/content/Cloud/meta.json b/content/Cloud/meta.json
deleted file mode 100644
index 29b6a6a0..00000000
--- a/content/Cloud/meta.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "title": "Console",
- "pages": [
- "index",
- "project",
- "agents",
- "vector-memory",
- "key-value-memory",
- "object-storage",
- "ai-gateway",
- "settings"
- ]
-}
diff --git a/content/Cloud/object-storage.mdx b/content/Cloud/object-storage.mdx
deleted file mode 100644
index fc06f6e5..00000000
--- a/content/Cloud/object-storage.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Object Storage
-description: The Object Storage page is for managing your object storage buckets
----
-
-## Understanding Object Storage
-
-Object storage is designed for storing files, media, and unstructured data, making it ideal for:
-
-- Files and documents
-- Images and videos
-- Backups and archives
-- Static assets
-- Large binary data
-- Public content delivery
-
-## Viewing Your Object Storage Buckets
-
-When you navigate to the Services > Object Store page in the Cloud Console, you'll see a table listing all your object storage buckets with the following information:
-
-- **Bucket Name**: The name of your object storage bucket
-- **Provider**: The storage provider for the bucket
-- **Created At**: When the bucket was created
-- **Size**: The storage size used by the bucket
-- **Num. of Objects**: The number of objects stored in the bucket
-
-You can filter the list of buckets using the search box at the top of the table to quickly find specific buckets by name.
-
-
-
-## Creating a New Object Storage Bucket
-
-There are two ways to create a new object storage bucket:
-
-1. From the Services > Object Store page in the Cloud Console
-2. In code, using the Agentuity SDK
-
-When creating an object storage bucket from the Cloud Console, click the **Create Storage** button and select **Object Store** from the storage type options. You can also choose your preferred storage provider from the dropdown menu, including Agentuity's built-in storage, Google Cloud Storage, or Azure Blob Storage.
-
-
\ No newline at end of file
diff --git a/content/Cloud/organization.mdx b/content/Cloud/organization.mdx
deleted file mode 100644
index b8c03074..00000000
--- a/content/Cloud/organization.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Organization Settings
-description: The organization settings page allows you to manage members.
----
-
-## Organization Settings
-
-The Organization Settings page is used to manage your organization members, verified domain and your organization settings.
-
-
diff --git a/content/Cloud/project.mdx b/content/Cloud/project.mdx
deleted file mode 100644
index 5f1c3c7c..00000000
--- a/content/Cloud/project.mdx
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Projects
-description: The projects page is for managing your agent projects
----
-
-## Projects Overview
-
-The project dashboard provides a list of your agent projects. This page helps you monitor your projects' status, usage metrics, and recent activity.
-
-
-
-### Project Settings
-
-#### Environment Variables & Secrets
-
-You can manage environment variables and secrets for your project in the Project > Settings page.
-
-
-
-In addition to environment variables, you can also view your Project API Key and the SDK Key.
-
-You can also manage your environment variables and secrets from the CLI using the following command:
-
-
-
-Use `--help` to see other options.
-
-You can `get`, `delete`, `list` and `set` environment variables and secrets using the CLI.
-
-When setting an environment variable or secret, the CLI will attempt to determine the type of the value and set it accordingly. However, you can force the value to be a secret by using the `--secret` flag.
-
-The `.env` file is a special file that is used to store environment variables and secrets for your project. It is a simple text file that contains key-value pairs. The `.env` file is automatically loaded when you run the CLI but not used (or not uploaded) in production.
-
-If you would like to have different environment variables and secrets for development and production, you can use the `.env.development` file which will override values in the `.env` file when running `agentuity dev`.
-
-
- The `.env` file must not be committed to your source code repository as it contains sensitive information. By default, an Agentuity project will exclude this file and others like it in the `.gitignore` file if you use the `agentuity create` command to create your project.
-
-
-##### API Keys
-
-There are two automatically generated API keys for your project:
-
-- **Project API Key** (the environment variable is `AGENTUITY_PROJECT_API_KEY`)
-- **SDK Key** (the environment variable is `AGENTUITY_SDK_KEY`)
-
-The Project API Key is used to authenticate requests to the Agentuity API. You can view your Project API Key in the Project > Settings page.
-
-The SDK Key is used to authenticate requests to the Agentuity SDK from your agents when running in development mode. You can view your SDK Key in the Project > Settings page.
-
-Both keys are created automatically when you create a new project and stored in the project's `.env` file.
-
-You can create additional API keys for your project in the [Settings > API Keys page](./api-keys).
-
-## CLI
-
-You can use the CLI to manage your project using the following command:
-
-
-
-See the [CLI documentation](/CLI/project) for more information on specific command usage and flags.
\ No newline at end of file
diff --git a/content/Cloud/settings.mdx b/content/Cloud/settings.mdx
deleted file mode 100644
index 117835d6..00000000
--- a/content/Cloud/settings.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Settings
-description: The settings page allows you to manage your overall organization settings
----
-
-## Settings
-
-The Settings pages are used to manage your overall organization settings.
-
-### API Keys
-
-You can manage your API keys in the [Settings > API Keys page](./api-keys).
-
-### Organization
-
-You can manage your organization settings in the [Settings > Organization page](./organization).
\ No newline at end of file
diff --git a/content/Cloud/vector-memory.mdx b/content/Cloud/vector-memory.mdx
deleted file mode 100644
index 350d75fd..00000000
--- a/content/Cloud/vector-memory.mdx
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Vector Storage
-description: The Vector Storage page is for managing your vector storage
----
-
-## Understanding Vector Storage
-
-Vector memory storage is designed for semantic search and large context windows, making it ideal for:
-
-- Knowledge bases
-- Historical data
-- Semantic search applications
-- Applications requiring understanding of content meaning
-- Long-term memory for agents
-
-## Viewing Your Vector Instances
-
-When you navigate to the Memory > Vector page in the Cloud Console, you'll see a table listing all your vector instances with the following information:
-
-- **Name**: The name of your vector instance
-- **Size**: The storage size used by the vector instance
-
-You can filter the list of vector instances using the search box at the top of the table to quickly find specific instances by name.
-
-
-
-## View Vector Data
-
-You can select a vector instance to view and manage its data.
-
-
-
-## Creating a New Vector Instance
-
-There are two ways to create a new vector instance:
-
-1. From the Services > Vector page in the Cloud Console
-2. In code, using the Agentuity SDK
-
-When creating a vector instance from the Cloud Console, click the **Create Storage** button and select **Vector Database** from the storage type options.
-
-
\ No newline at end of file
diff --git a/content/Examples/index.mdx b/content/Examples/index.mdx
deleted file mode 100644
index 9486649b..00000000
--- a/content/Examples/index.mdx
+++ /dev/null
@@ -1,126 +0,0 @@
----
-title: Examples
-description: Links to examples across our GitHub repositories
----
-
-While our comprehensive examples documentation is coming soon,
-you can explore our GitHub repositories where we maintain a
-collection of reference implementations.
-
-
-
-## Featured Examples
-
-### Agentuity Kitchen Sink (TypeScript)
-
-An interactive SDK showcase with 20+ working agents demonstrating every Agentuity platform feature. Perfect for hands-on learning or as a reference implementation.
-
-- Test all SDK features in DevMode with real agents
-- Deploy and explore in minutes - no setup required
-- Copy working patterns directly into your projects
-
-
-
-### Miami Concierge Agent Template
-
-A React-based concierge service template for Miami visitors, showcasing how to build a user-friendly agent interface.
-
-
- VIDEO
-
-
-
-
-### Content Marketing Agent System
-
-Agents for creating, managing, and scheduling social media content using a multi-agent architecture.
-
-
-
-### Newsroom: AI-Powered Content Pipeline
-
-An automated content generation system that collects, processes, and publishes AI-related news content using specialized AI agents.
-
-
-
-### Agent Changelog
-
-A tool for automatically generating and managing changelogs for your projects.
-
-
-
-## SDK Examples
-
-We provide comprehensive examples for our SDKs to help you get started with building agents using Agentuity.
-
-### JavaScript SDK Examples
-
-Our JavaScript SDK examples demonstrate how to build agents using JavaScript:
-
-
-
-### Python SDK Examples
-
-Our Python SDK examples demonstrate how to build agents using Python:
-
-
diff --git a/content/Frontend/advanced-hooks.mdx b/content/Frontend/advanced-hooks.mdx
new file mode 100644
index 00000000..018f75bb
--- /dev/null
+++ b/content/Frontend/advanced-hooks.mdx
@@ -0,0 +1,142 @@
+---
+title: Advanced Hooks
+description: Connect to custom WebSocket and SSE endpoints with useWebsocket and useEventStream
+---
+
+For custom endpoints that aren't agents, use the low-level hooks directly.
+
+
+For most use cases, the standard hooks (`useAPI`, `useWebsocket`, `useEventStream`) work directly with your routes. These advanced patterns are for custom message handlers and third-party integrations.
+
+
+## useWebsocket
+
+Connect to any WebSocket endpoint:
+
+```tsx
+import { useWebsocket } from '@agentuity/react';
+import { useEffect } from 'react';
+
+function CustomWebSocket() {
+ const { isConnected, send, data, setHandler, close } = useWebsocket<
+ { action: string }, // Input type
+ { result: string } // Output type
+ >('/custom/websocket');
+
+ // Set a custom message handler
+ useEffect(() => {
+ setHandler((message) => {
+ console.log('Received:', message);
+ // Process message as needed
+ });
+ }, [setHandler]);
+
+ const handleClick = () => {
+ send({ action: 'ping' });
+ };
+
+ return (
+
+
Status: {isConnected ? 'Connected' : 'Disconnected'}
+
+ Send Ping
+
+
Disconnect
+
+ );
+}
+```
+
+**Return values:**
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isConnected` | `boolean` | True when WebSocket is open |
+| `send` | `(data: TInput) => void` | Send a message |
+| `data` | `TOutput \| undefined` | Last received message |
+| `setHandler` | `(fn: (data: TOutput) => void) => void` | Custom message handler |
+| `readyState` | `number` | WebSocket ready state |
+| `close` | `() => void` | Close the connection |
+| `reset` | `() => void` | Clear error state |
+| `error` | `Error \| null` | Connection error |
+
+## useEventStream
+
+Connect to any Server-Sent Events endpoint:
+
+```tsx
+import { useEventStream } from '@agentuity/react';
+import { useEffect } from 'react';
+
+function CustomEventStream() {
+ const { isConnected, data, setHandler, close, error } = useEventStream<
+ { event: string; timestamp: number }
+ >('/custom/events');
+
+ useEffect(() => {
+ setHandler((event) => {
+ console.log('Event received:', event);
+ });
+ }, [setHandler]);
+
+ if (error) {
+ return Error: {error.message}
;
+ }
+
+ return (
+
+
Stream: {isConnected ? 'Active' : 'Connecting...'}
+
Last event: {data?.event ?? 'None'}
+
Stop Stream
+
+ );
+}
+```
+
+**Return values:**
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isConnected` | `boolean` | True when stream is active |
+| `data` | `TOutput \| undefined` | Last received event |
+| `setHandler` | `(fn: (data: TOutput) => void) => void` | Custom event handler |
+| `readyState` | `number` | Connection state |
+| `close` | `() => void` | Close the stream |
+| `reset` | `() => void` | Clear error state |
+| `error` | `Error \| null` | Connection error |
+
+## Options
+
+Both hooks accept options for customizing the connection:
+
+```tsx
+const { isConnected, send } = useWebsocket('/path', {
+ query: new URLSearchParams({ token: 'abc123' }),
+ subpath: '/room/1', // Appends to path
+ signal: abortController.signal,
+});
+```
+
+## Reconnection Behavior
+
+Both hooks automatically reconnect when the connection drops using exponential backoff (delays increase between attempts, capped at 30 seconds).
+
+
+Connections are automatically closed when the component unmounts. You don't need to manually call `close()` in a cleanup effect.
+
+
+## When to Use These
+
+| Use Case | Recommended Hook |
+|----------|------------------|
+| HTTP API routes | `useAPI` |
+| WebSocket routes | `useWebsocket` |
+| SSE routes | `useEventStream` |
+| Third-party WebSocket | `useWebsocket` with custom handler |
+| Custom SSE endpoint | `useEventStream` with custom handler |
+
+## Next Steps
+
+- [React Hooks](/Build/Frontend/react-hooks): Agent-specific hooks for common use cases
+- [WebSockets](/Build/Routes/websockets): Create WebSocket routes in your agents
+- [Server-Sent Events](/Build/Routes/sse): Create SSE routes in your agents
diff --git a/content/Frontend/authentication.mdx b/content/Frontend/authentication.mdx
new file mode 100644
index 00000000..5128e866
--- /dev/null
+++ b/content/Frontend/authentication.mdx
@@ -0,0 +1,267 @@
+---
+title: Adding Authentication
+description: Add user authentication with Agentuity Auth
+---
+
+Protect your agents and routes with user authentication. Agentuity provides a first-party auth solution powered by [BetterAuth](https://better-auth.com).
+
+## Agentuity Auth
+
+The `@agentuity/auth` package provides authentication with built-in integration into agents and routes.
+
+### Quick Start
+
+```bash
+# Create a database (or use your own)
+agentuity cloud database create --region us
+
+# Initialize auth (installs deps, generates src/auth.ts)
+agentuity project auth init
+```
+
+
+Start with auth pre-configured: `bunx agentuity create my-app --template agentuity-auth`
+
+
+### Server Setup
+
+Create an auth instance and middleware:
+
+```typescript title="src/auth.ts"
+import { createAuth, createSessionMiddleware, mountAuthRoutes } from '@agentuity/auth';
+
+export const auth = createAuth({
+ connectionString: process.env.DATABASE_URL,
+ // Uses AGENTUITY_AUTH_SECRET env var by default
+});
+
+export const authMiddleware = createSessionMiddleware(auth);
+export const optionalAuthMiddleware = createSessionMiddleware(auth, { optional: true });
+```
+
+Mount auth routes and protect your API:
+
+```typescript title="src/api/index.ts"
+import { createRouter } from '@agentuity/runtime';
+import { auth, authMiddleware } from '../auth';
+import { mountAuthRoutes } from '@agentuity/auth';
+
+const router = createRouter();
+
+// Mount auth routes (sign-in, sign-up, sign-out, session, etc.)
+router.on(['GET', 'POST'], '/api/auth/*', mountAuthRoutes(auth));
+
+// Protect API routes
+router.use('/api/*', authMiddleware);
+
+router.get('/api/me', async (c) => {
+ const user = await c.var.auth.getUser();
+ return c.json({ id: user.id, email: user.email });
+});
+
+export default router;
+```
+
+### Client Setup
+
+```typescript title="src/web/auth-client.ts"
+import { createAuthClient } from '@agentuity/auth/react';
+
+export const authClient = createAuthClient();
+export const { signIn, signUp, signOut, useSession } = authClient;
+```
+
+```tsx title="src/web/frontend.tsx"
+import { AgentuityProvider } from '@agentuity/react';
+import { AuthProvider, createAuthClient } from '@agentuity/auth/react';
+import { App } from './App';
+
+const authClient = createAuthClient();
+
+export function Root() {
+ return (
+
+
+
+
+
+ );
+}
+```
+
+### Using Auth in Agents
+
+Auth is available natively on `ctx.auth` when using auth middleware:
+
+```typescript title="src/agent/protected/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+export default createAgent('Protected Agent', {
+ schema: {
+ input: z.object({ query: z.string() }),
+ output: z.object({ result: z.string(), userId: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ if (!ctx.auth) {
+ ctx.logger.warn('Unauthenticated request');
+ return { result: 'Please sign in', userId: '' };
+ }
+
+ const user = await ctx.auth.getUser();
+ const org = await ctx.auth.getOrg();
+
+ ctx.logger.info('Processing request', { userId: user.id, orgId: org?.id });
+
+ // Check organization roles
+ if (org && (await ctx.auth.hasOrgRole('admin'))) {
+ // Admin-only logic
+ }
+
+ return { result: `Hello ${user.name}`, userId: user.id };
+ },
+});
+```
+
+### API Key Authentication
+
+For programmatic access, use API key middleware:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createApiKeyMiddleware } from '@agentuity/auth';
+import { auth } from '../auth';
+
+const router = createRouter();
+
+router.use('/api/*', createApiKeyMiddleware(auth));
+
+router.get('/api/data', async (c) => {
+ // Check API key permissions
+ if (!c.var.auth.hasPermission('data', 'read')) {
+ return c.json({ error: 'Forbidden' }, 403);
+ }
+ return c.json({ data: '...' });
+});
+
+export default router;
+```
+
+### Environment Variables
+
+| Variable | Description |
+|----------|-------------|
+| `DATABASE_URL` | PostgreSQL connection string |
+| `AGENTUITY_AUTH_SECRET` | Auth secret (generate with `openssl rand -hex 32`) |
+
+### CLI Commands
+
+```bash
+agentuity project auth init # Initialize auth, generate src/auth.ts
+agentuity project auth generate # Generate SQL schema for auth tables
+```
+
+
+If no ORM is detected, `init` prompts to run migrations. If you're using Drizzle or Prisma, run migrations manually with your ORM tools. Use `--skipMigrations` to skip the prompt, then run `agentuity project auth generate` to get the SQL schema.
+
+
+### Database Configuration
+
+**Connection String (simplest):**
+
+```typescript
+import { createAuth } from '@agentuity/auth';
+
+export const auth = createAuth({
+ connectionString: process.env.DATABASE_URL,
+});
+```
+
+**Bring Your Own Drizzle:**
+
+```typescript
+import { drizzle } from 'drizzle-orm/bun-sql';
+import { drizzleAdapter } from 'better-auth/adapters/drizzle';
+import * as authSchema from '@agentuity/auth/schema';
+import * as appSchema from './schema';
+
+const schema = { ...authSchema, ...appSchema };
+const db = drizzle(process.env.DATABASE_URL!, { schema });
+
+export const auth = createAuth({
+ database: drizzleAdapter(db, { provider: 'pg', schema: authSchema }),
+});
+```
+
+---
+
+## Common Patterns
+
+These patterns work with any auth provider.
+
+### Using Auth State in Components
+
+```tsx
+import { useAPI, useAgentuity } from '@agentuity/react';
+
+function Dashboard() {
+ const { isAuthenticated, authLoading } = useAgentuity();
+ const { data, refetch } = useAPI('GET /api/profile');
+
+ if (authLoading) return Loading...
;
+ if (!isAuthenticated) return Please sign in
;
+
+ return (
+
+
Welcome, {data?.name}
+ refetch()}>Refresh
+
+ );
+}
+```
+
+### Global Route Protection
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { authMiddleware } from '../auth';
+
+const router = createRouter();
+
+// Protect all /api/* routes
+router.use('/api/*', authMiddleware);
+
+router.get('/api/profile', async (c) => {
+ const user = await c.var.auth.getUser();
+ return c.json({ email: user.email });
+});
+
+export default router;
+```
+
+### Optional Authentication
+
+Allow both authenticated and anonymous access:
+
+```typescript
+import { createSessionMiddleware } from '@agentuity/auth';
+import { auth } from '../auth';
+
+const optionalAuth = createSessionMiddleware(auth, { optional: true });
+
+router.get('/api/content', optionalAuth, async (c) => {
+ const user = await c.var.auth.getUser();
+
+ if (user) {
+ return c.json({ content: 'Premium content', userId: user.id });
+ }
+
+ return c.json({ content: 'Public content' });
+});
+```
+
+## Next Steps
+
+- [Middleware & Authentication](/Build/Routes/middleware): More middleware patterns
+- [Provider Setup](/Build/Frontend/provider-setup): AgentuityProvider configuration
+- [React Hooks](/Build/Frontend/react-hooks): Building custom UIs
diff --git a/content/Frontend/deployment-scenarios.mdx b/content/Frontend/deployment-scenarios.mdx
new file mode 100644
index 00000000..3841aa7c
--- /dev/null
+++ b/content/Frontend/deployment-scenarios.mdx
@@ -0,0 +1,121 @@
+---
+title: Deployment Scenarios
+description: Deploy your frontend alongside agents or separately on Vercel, Netlify, etc.
+---
+
+Choose where your frontend lives based on your project needs.
+
+## All-in-One Deployment
+
+Put your frontend code in `src/web/` and deploy everything together:
+
+```
+my-project/
+├── src/
+│ ├── agent/
+│ │ └── chat/
+│ │ └── agent.ts
+│ ├── api/
+│ │ └── index.ts
+│ └── web/
+│ ├── App.tsx
+│ ├── frontend.tsx
+│ └── index.html
+└── agentuity.json
+```
+
+When you run `agentuity deploy`, both your agents and frontend are bundled and deployed together.
+
+```tsx
+// src/web/App.tsx
+import { AgentuityProvider, useAPI } from '@agentuity/react';
+
+function Chat() {
+ const { invoke, data, isLoading } = useAPI('POST /api/chat');
+ // ... your chat UI
+}
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+
+When frontend and agents are deployed together, you don't need to set `baseUrl`. The provider automatically connects to the same origin.
+
+
+**Best for:**
+- New projects starting from scratch
+- Simple deployments with one codebase
+- Projects that don't need separate frontend scaling
+
+## Separate Frontend
+
+Deploy your frontend on Vercel, Netlify, or any hosting platform while agents run on Agentuity:
+
+```
+Frontend (e.g., Vercel) Agents (Agentuity)
+┌───────────────────────┐ ┌───────────────────────┐
+│ your-app.com │ ────────► │ project.cloud │
+│ React/Next.js │ │ Agent routes │
+└───────────────────────┘ └───────────────────────┘
+```
+
+```tsx
+// In your React app
+import { AgentuityProvider, useAPI } from '@agentuity/react';
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+**Best for:**
+- Existing projects adding AI agents
+- Teams with separate frontend and backend deployments
+
+## CORS Configuration
+
+When your frontend and agents are on different domains, configure CORS in `app.ts`:
+
+```typescript
+// app.ts
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ cors: {
+ origin: ['https://your-frontend.com', 'http://localhost:3000'],
+ allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
+ allowHeaders: ['Content-Type', 'Authorization'],
+ },
+});
+
+logger.debug('Running %s', server.url);
+```
+
+
+Without CORS configuration, browsers will block requests from your frontend to your agents when they're on different domains.
+
+
+## Comparison
+
+| Aspect | All-in-One | Separate Frontend |
+|--------|------------|-------------------|
+| Deployment | Single `agentuity deploy` | Deploy frontend and agents separately |
+| Configuration | Minimal | Requires `baseUrl` and CORS |
+| Scaling | Tied together | Independent scaling |
+| Best for | New projects | Existing frontends |
+
+## Next Steps
+
+- [React Hooks](/Build/Frontend/react-hooks): Call agents from your components
+- [Provider Setup](/Build/Frontend/provider-setup): Configure the provider for your environment
+- [App Configuration](/Get-Started/app-configuration): CORS and other app-level settings
diff --git a/content/Frontend/meta.json b/content/Frontend/meta.json
new file mode 100644
index 00000000..f11d0447
--- /dev/null
+++ b/content/Frontend/meta.json
@@ -0,0 +1,4 @@
+{
+ "title": "Frontend",
+ "pages": ["react-hooks", "rpc-client", "provider-setup", "authentication", "workbench", "deployment-scenarios", "advanced-hooks"]
+}
diff --git a/content/Frontend/provider-setup.mdx b/content/Frontend/provider-setup.mdx
new file mode 100644
index 00000000..1ed4b262
--- /dev/null
+++ b/content/Frontend/provider-setup.mdx
@@ -0,0 +1,109 @@
+---
+title: Provider Setup
+description: Configure AgentuityProvider for local development and production deployments
+---
+
+Wrap your app in `AgentuityProvider` to connect React hooks to your agents.
+
+## Basic Setup
+
+```tsx
+import { AgentuityProvider } from '@agentuity/react';
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+In development, the provider automatically connects to `http://localhost:3500` where your agents run.
+
+## Production Configuration
+
+For deployed applications, set the `baseUrl` to your Agentuity deployment:
+
+```tsx
+import { AgentuityProvider } from '@agentuity/react';
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+### Environment-Based Configuration
+
+Use environment variables to switch between development and production:
+
+```tsx
+import { AgentuityProvider } from '@agentuity/react';
+
+const baseUrl = process.env.NODE_ENV === 'production'
+ ? 'https://your-project.agentuity.cloud'
+ : undefined; // Falls back to localhost:3500
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+For production, set your deployment URL via your framework's environment variable pattern.
+
+## Provider Props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `baseUrl` | `string` | `http://localhost:3500` | Base URL for agent requests |
+| `children` | `ReactNode` | — | Your app components |
+
+## Authentication Integration
+
+For apps with user authentication, wrap `AgentuityProvider` with `AuthProvider` from `@agentuity/auth/react`:
+
+```tsx
+import { AgentuityProvider } from '@agentuity/react';
+import { AuthProvider, createAuthClient } from '@agentuity/auth/react';
+
+const authClient = createAuthClient();
+
+export default function App() {
+ return (
+
+
+
+
+
+ );
+}
+```
+
+Once configured, `useAPI` and `useWebsocket` automatically include auth tokens in requests. See [Adding Authentication](/Build/Frontend/authentication) for full setup.
+
+## Type Safety
+
+When you run `bun dev` or `agentuity dev`, the CLI generates TypeScript types for your agents at `.agentuity/types.d.ts`. This enables autocomplete and type checking for agent names and their input/output schemas.
+
+```tsx
+// TypeScript knows which routes exist and their types
+const { invoke } = useAPI('POST /api/chat'); // Autocomplete for routes
+await invoke({ message: 'Hello' }); // Type-checked input
+```
+
+
+Types are regenerated automatically when you add or modify agents. If types seem stale, restart the dev server.
+
+
+## Next Steps
+
+- [React Hooks](/Build/Frontend/react-hooks): Learn about `useAPI`, `useWebsocket`, and `useEventStream`
+- [Deployment Scenarios](/Build/Frontend/deployment-scenarios): Choose where your frontend lives
diff --git a/content/Frontend/react-hooks.mdx b/content/Frontend/react-hooks.mdx
new file mode 100644
index 00000000..5a15fe0f
--- /dev/null
+++ b/content/Frontend/react-hooks.mdx
@@ -0,0 +1,323 @@
+---
+title: React Hooks
+description: Call your API routes from React with useAPI, useWebsocket, and useEventStream
+---
+
+Call your API routes from React components using type-safe hooks from `@agentuity/react`.
+
+
+For non-React apps (Vue, Svelte, vanilla JS) or server-side code, use the [RPC Client](/Build/Frontend/rpc-client) from `@agentuity/frontend` instead.
+
+
+## Installation
+
+```bash
+bun add @agentuity/react
+```
+
+## Basic Usage with useAPI
+
+The `useAPI` hook calls your API routes with full type safety:
+
+```tsx
+import { AgentuityProvider, useAPI } from '@agentuity/react';
+
+function ChatForm() {
+ const { invoke, isLoading, data, error } = useAPI('POST /api/chat');
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ const formData = new FormData(e.currentTarget);
+ const message = formData.get('message') as string;
+
+ try {
+ await invoke({ message });
+ } catch (err) {
+ // Error is also available via the error state
+ console.error('API call failed:', err);
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+**Return values:**
+
+| Property | Type | Description | Methods |
+|----------|------|-------------|---------|
+| `invoke` | `(input) => Promise` | Execute the request | POST, PUT, PATCH, DELETE |
+| `refetch` | `() => Promise` | Manually refetch data | GET |
+| `data` | `TOutput \| undefined` | Last successful response | All |
+| `error` | `Error \| null` | Last error, if any | All |
+| `isLoading` | `boolean` | True during initial load | All |
+| `isFetching` | `boolean` | True during any fetch (including refetches) | All |
+| `isSuccess` | `boolean` | True after successful completion | All |
+| `isError` | `boolean` | True if request failed | All |
+| `reset` | `() => void` | Reset state to initial values | All |
+
+GET requests auto-fetch on mount. POST/PUT/PATCH/DELETE require calling `invoke()`.
+
+### useAPI Options
+
+Pass an options object instead of a route string for advanced configuration:
+
+```tsx
+const { data, refetch } = useAPI({
+ route: 'GET /api/users',
+ staleTime: 30000, // Data stays fresh for 30 seconds
+ refetchInterval: 60000, // Auto-refetch every 60 seconds
+ enabled: isReady, // Only fetch when condition is true
+ onSuccess: (data) => console.log('Fetched:', data),
+ onError: (err) => console.error('Failed:', err),
+});
+```
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `route` | `string` | - | Route key (e.g., `'GET /api/users'`) |
+| `query` | `URLSearchParams \| Record` | - | Query parameters |
+| `headers` | `Record` | - | Additional request headers |
+| `enabled` | `boolean` | `true` (GET), `false` (others) | Control when request executes |
+| `staleTime` | `number` | `0` | Milliseconds data stays fresh before refetching |
+| `refetchInterval` | `number` | - | Auto-refetch interval in milliseconds |
+| `onSuccess` | `(data) => void` | - | Callback on successful request |
+| `onError` | `(error) => void` | - | Callback on failed request |
+
+### Streaming with useAPI
+
+For streaming routes, `useAPI` accumulates chunks and provides transform callbacks:
+
+```tsx
+const { data, isLoading } = useAPI({
+ route: 'POST /api/stream',
+ input: { prompt: 'Hello' },
+ delimiter: '\n', // Split chunks by newline (default)
+ onChunk: (chunk) => {
+ console.log('Received chunk:', chunk);
+ return chunk; // Can transform before accumulation
+ },
+});
+
+// data is TOutput[] - array of all received chunks
+```
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `delimiter` | `string` | Delimiter for splitting stream chunks (default: `\n`) |
+| `onChunk` | `(chunk) => chunk` | Transform each chunk before accumulation |
+
+## Real-Time with useWebsocket
+
+For bidirectional real-time communication, use `useWebsocket`:
+
+```tsx
+import { useWebsocket } from '@agentuity/react';
+
+function RealtimeChat() {
+ const { isConnected, send, messages, clearMessages } = useWebsocket('/api/chat', {
+ maxMessages: 100, // Keep last 100 messages
+ });
+
+ return (
+
+
Status: {isConnected ? 'Connected' : 'Connecting...'}
+
+ {messages.map((msg, i) => (
+ {JSON.stringify(msg)}
+ ))}
+
+
send({ message: 'Hello!' })}>Send Hello
+
Clear
+
+ );
+}
+```
+
+You can also use `data` for only the most recent message:
+
+```tsx
+import { useWebsocket } from '@agentuity/react';
+import { useEffect } from 'react';
+
+function LatestUpdate() {
+ const { isConnected, send, data } = useWebsocket('/api/updates');
+
+ useEffect(() => {
+ if (data) {
+ console.log('Latest update:', data);
+ }
+ }, [data]);
+
+ return Latest: {data ? JSON.stringify(data) : 'Waiting...'}
;
+}
+```
+
+
+WebSocket connections automatically reconnect with exponential backoff if the connection drops. Messages sent while disconnected are queued and sent when the connection is restored.
+
+
+**Return values:**
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isConnected` | `boolean` | True when WebSocket is open |
+| `send` | `(data: TInput) => void` | Send a message |
+| `data` | `TOutput \| undefined` | Last received message |
+| `messages` | `TOutput[]` | Array of all received messages |
+| `clearMessages` | `() => void` | Clear the messages array |
+| `error` | `Error \| null` | Connection or message error |
+| `isError` | `boolean` | True if an error occurred |
+| `readyState` | `number` | WebSocket state (0=connecting, 1=open, 2=closing, 3=closed) |
+| `close` | `() => void` | Close the connection |
+| `reset` | `() => void` | Clear error state |
+
+**Options:**
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `query` | `URLSearchParams` | Query parameters to append to the WebSocket URL |
+| `subpath` | `string` | Subpath to append to the WebSocket path |
+| `signal` | `AbortSignal` | AbortSignal to cancel the connection |
+| `maxMessages` | `number` | Maximum messages to keep in `messages` array (oldest removed when exceeded) |
+
+## Streaming with useEventStream
+
+For one-way streaming from server to client, use Server-Sent Events:
+
+```tsx
+import { useEventStream } from '@agentuity/react';
+
+function LiveStatus() {
+ const { isConnected, data, error } = useEventStream('/api/status');
+
+ if (!isConnected) {
+ return Connecting to status feed...
;
+ }
+
+ if (error) {
+ return Error: {error.message}
;
+ }
+
+ return (
+
+
Live Status: {data?.status ?? 'Waiting for update...'}
+
Last updated: {data?.timestamp ?? '-'}
+
+ );
+}
+```
+
+
+Use `useEventStream` when you only need server-to-client updates (e.g., progress indicators, live dashboards, notifications). For bidirectional communication, use `useWebsocket`.
+
+
+**Return values:**
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isConnected` | `boolean` | True when EventStream is open |
+| `data` | `TOutput \| undefined` | Last received event data |
+| `error` | `Error \| null` | Connection error |
+| `isError` | `boolean` | True if an error occurred |
+| `readyState` | `number` | EventSource state (0=connecting, 1=open, 2=closed) |
+| `close` | `() => void` | Close the connection |
+| `reset` | `() => void` | Clear error state |
+
+**Options:** Accepts `query`, `subpath`, and `signal` options, same as `useWebsocket`.
+
+## Choosing the Right Hook
+
+| Hook | Use Case | Direction | Examples |
+|------|----------|-----------|---------|
+| `useAPI` | Request/response | One-time | Send a message, fetch user data, submit a form |
+| `useWebsocket` | Bidirectional streaming | Client ↔ Server | Live chat, multiplayer sync, shared editing |
+| `useEventStream` | Server push | Server → Client | AI token streaming, build logs, live metrics |
+
+## Request Options
+
+Pass options to the hook for customizing requests. Options like `query` and `headers` are set when calling the hook, not when invoking:
+
+```tsx
+// Options are passed to useAPI, not invoke
+const { invoke } = useAPI({
+ route: 'POST /api/chat',
+ query: new URLSearchParams({ version: '2' }),
+ headers: { 'X-Custom-Header': 'value' },
+});
+
+// invoke only takes the input data
+await invoke({ message: 'Hello' });
+```
+
+For dynamic query parameters, create a new hook instance:
+
+```tsx
+function SearchResults({ query }: { query: string }) {
+ const { data, isLoading } = useAPI({
+ route: 'GET /api/search',
+ query: { q: query },
+ });
+
+ return {isLoading ? 'Searching...' : JSON.stringify(data)}
;
+}
+```
+
+## Auth State with useAuth
+
+Access authentication state for protected components or custom auth logic:
+
+```tsx
+import { useAuth } from '@agentuity/react';
+
+function ProtectedContent() {
+ const { isAuthenticated, authLoading } = useAuth();
+
+ if (authLoading) {
+ return Loading...
;
+ }
+
+ if (!isAuthenticated) {
+ return Please sign in to continue.
;
+ }
+
+ return Welcome! You have access.
;
+}
+```
+
+**Return values:**
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isAuthenticated` | `boolean` | True when auth token is set and not loading |
+| `authLoading` | `boolean` | True while auth state is initializing |
+| `authHeader` | `string \| null` | The current Authorization header value |
+| `setAuthHeader` | `(token: string \| null) => void` | Manually set the auth header |
+| `setAuthLoading` | `(loading: boolean) => void` | Control the loading state |
+
+
+`useAuth` provides auth-specific state. For non-auth context like `baseUrl`, use `useAgentuity()` instead. See [Authentication](/Build/Frontend/authentication) for integrating with identity providers.
+
+
+## Next Steps
+
+- [Provider Setup](/Build/Frontend/provider-setup): Configure `AgentuityProvider` for deployments
+- [Advanced Hooks](/Build/Frontend/advanced-hooks): Custom handlers for WebSocket and SSE
+- [Deployment Scenarios](/Build/Frontend/deployment-scenarios): Choose where your frontend lives
diff --git a/content/Frontend/rpc-client.mdx b/content/Frontend/rpc-client.mdx
new file mode 100644
index 00000000..09bf8485
--- /dev/null
+++ b/content/Frontend/rpc-client.mdx
@@ -0,0 +1,241 @@
+---
+title: RPC Client
+description: Type-safe API calls from any JavaScript environment using createAPIClient
+---
+
+Call your API routes with full type safety. The SDK auto-generates a typed client based on your route definitions.
+
+## Basic Usage
+
+For non-React apps, import `createAPIClient` from the generated routes:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+
+// Type-safe API call - types are inferred from your route schemas
+const result = await api.chat.post({ message: 'Hello' });
+console.log(result.response);
+```
+
+For React apps, import from `@agentuity/react`:
+
+```typescript
+import { createAPIClient } from '@agentuity/react';
+
+const api = createAPIClient();
+const result = await api.chat.post({ message: 'Hello' });
+```
+
+
+When imported from `@agentuity/react`, the client automatically includes auth headers if you've configured authentication with `AgentuityProvider`. Use `./generated/routes` when you need a client without automatic auth injection.
+
+
+
+For React components, consider using [React Hooks](/Build/Frontend/react-hooks) instead. They provide built-in state management, loading states, and automatic cleanup.
+
+
+## HTTP Methods
+
+All standard HTTP methods are supported:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+
+const users = await api.users.get();
+const created = await api.users.post({ name: 'Alice', email: 'alice@example.com' });
+await api.users.alice.put({ name: 'Alice Smith' });
+await api.users.alice.delete();
+```
+
+## WebSocket Connections
+
+Connect to WebSocket routes with `.websocket()`:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+const ws = api.chat.websocket();
+
+ws.on('open', () => {
+ console.log('Connected');
+ ws.send({ message: 'Hello!' });
+});
+
+ws.on('message', (data) => {
+ console.log('Received:', data);
+});
+
+ws.on('error', (error) => {
+ console.error('WebSocket error:', error);
+});
+
+ws.close();
+```
+
+## Server-Sent Events
+
+Subscribe to SSE streams with `.eventstream()`:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+const events = api.notifications.eventstream();
+
+events.on('message', (event) => {
+ const data = JSON.parse(event.data);
+ console.log('Event:', data);
+});
+
+events.on('error', (error) => {
+ console.error('Stream error:', error);
+});
+
+events.close();
+```
+
+## Streaming Responses
+
+For streaming HTTP responses, use `.stream()`:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+const stream = await api.generate.stream({ prompt: 'Write a story' });
+
+stream.on('chunk', (chunk) => {
+ const text = new TextDecoder().decode(chunk);
+ process.stdout.write(text);
+});
+
+stream.on('close', () => {
+ console.log('\nStream complete');
+});
+```
+
+## Client Options
+
+Configure the client with custom options:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+// With custom headers
+const api = createAPIClient({
+ headers: {
+ 'X-Custom-Header': 'value',
+ },
+});
+
+// With dynamic headers (called on each request)
+const authenticatedApi = createAPIClient({
+ headers: () => ({
+ 'Authorization': `Bearer ${getToken()}`,
+ }),
+});
+```
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `baseUrl` | `string \| () => string` | `''` (relative) | Base URL for requests |
+| `headers` | `Record \| () => Record` | `{}` | Request headers |
+| `contentType` | `string` | `application/json` | Content-Type header |
+| `signal` | `AbortSignal` | — | For request cancellation |
+
+## Request Cancellation
+
+Cancel in-flight requests using `AbortController`:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const controller = new AbortController();
+
+const api = createAPIClient({
+ signal: controller.signal,
+});
+
+const resultPromise = api.longProcess.post({ data: 'large payload' });
+
+// Cancel if needed
+setTimeout(() => controller.abort(), 5000);
+
+try {
+ const result = await resultPromise;
+} catch (error) {
+ if (error.name === 'AbortError') {
+ console.log('Request cancelled');
+ }
+}
+```
+
+## Error Handling
+
+The client throws on HTTP errors:
+
+```typescript
+import { createAPIClient } from './generated/routes';
+
+const api = createAPIClient();
+
+try {
+ const result = await api.users.post({ name: 'Alice' });
+ console.log('Created:', result);
+} catch (error) {
+ if (error.message.startsWith('HTTP 4')) {
+ console.error('Client error:', error.message);
+ } else if (error.message.startsWith('HTTP 5')) {
+ console.error('Server error:', error.message);
+ } else {
+ console.error('Network error:', error);
+ }
+}
+```
+
+## Type Generation
+
+Types are generated automatically when you run `agentuity dev`. The generated `RPCRouteRegistry` maps your route paths to their input/output types:
+
+```typescript
+// Generated at src/generated/routes.ts
+export type RPCRouteRegistry = {
+ chat: {
+ post: { input: { message: string }; output: { response: string } };
+ };
+ users: {
+ get: { input: void; output: User[] };
+ post: { input: CreateUserInput; output: User };
+ };
+};
+```
+
+
+Generated types live in `src/generated/`. Don't edit these files directly as they're regenerated on each build.
+
+
+## RPC Client vs React Hooks
+
+| Use Case | Recommended |
+|----------|-------------|
+| React components | [React Hooks](/Build/Frontend/react-hooks) |
+| Non-React apps (Vue, Svelte, vanilla JS) | `createAPIClient` from `./generated/routes` |
+| Server-side JavaScript | `createAPIClient` from `./generated/routes` |
+| CLI tools or scripts | `createAPIClient` from `./generated/routes` |
+
+## Calling Routes from External Backends
+
+External backends like Next.js or Express can use HTTP to call Agentuity routes that access storage services. See [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities) for the complete pattern.
+
+## Next Steps
+
+- [React Hooks](/Build/Frontend/react-hooks): State-managed hooks for React apps
+- [Provider Setup](/Build/Frontend/provider-setup): Configure `AgentuityProvider` for React
+- [Adding Authentication](/Build/Frontend/authentication): Protect routes with Agentuity Auth
+- [WebSockets](/Build/Routes/websockets): Create WebSocket routes
+- [Server-Sent Events](/Build/Routes/sse): Create SSE routes
diff --git a/content/Frontend/workbench.mdx b/content/Frontend/workbench.mdx
new file mode 100644
index 00000000..1b93d5f2
--- /dev/null
+++ b/content/Frontend/workbench.mdx
@@ -0,0 +1,92 @@
+---
+title: Workbench Configuration
+description: Configure routes, authentication, and embed Workbench in custom frontends
+---
+
+This page covers advanced Workbench configuration and embedding. For basic setup and testing agents, see [Testing with Workbench](/Build/Agents/workbench).
+
+## Configuration
+
+Configure Workbench in your `agentuity.config.ts`:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/workbench',
+ headers: {},
+ },
+} satisfies AgentuityConfig;
+```
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `route` | `string` | Custom route path (default: `/workbench`) |
+| `headers` | `Record` | Custom headers for API requests |
+
+### Custom Route
+
+Serve Workbench at a different path:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/dev',
+ },
+} satisfies AgentuityConfig;
+```
+
+### Authentication
+
+Protect Workbench with an API key by setting the `AGENTUITY_WORKBENCH_APIKEY` environment variable:
+
+```bash
+# .env
+AGENTUITY_WORKBENCH_APIKEY=your-secret-key
+```
+
+When set, requests to Workbench without a valid Bearer token will be rejected.
+
+## Embedding in Your Frontend
+
+Workbench exports React components you can embed in your own application:
+
+```typescript
+import { App } from '@agentuity/workbench';
+import '@agentuity/workbench/styles';
+import { encodeWorkbenchConfig } from '@agentuity/core/workbench';
+
+const config = encodeWorkbenchConfig({
+ route: '/workbench',
+ headers: {},
+});
+
+function MyApp() {
+ return ;
+}
+```
+
+For custom layouts, the package also exports individual components:
+
+- `Chat` - The conversation area
+- `Schema` - Schema viewer panel
+- `WorkbenchProvider` + `useWorkbench` - Context and hooks for full control
+
+## Debug Logging
+
+Enable debug logging in the browser console:
+
+```javascript
+localStorage.setItem('AGENTUITY_LOG_LEVEL', 'debug');
+```
+
+Valid levels: `debug`, `info`, `warn`, `error`. Refresh the page after setting.
+
+## Next Steps
+
+- [Testing with Workbench](/Build/Agents/workbench): Basic setup and test prompts
+- [React Hooks](/Build/Frontend/react-hooks): Build custom agent UIs
+- [Local Development](/Reference/CLI/development): Dev server options
diff --git a/content/Get-Started/app-configuration.mdx b/content/Get-Started/app-configuration.mdx
new file mode 100644
index 00000000..6bd564f9
--- /dev/null
+++ b/content/Get-Started/app-configuration.mdx
@@ -0,0 +1,200 @@
+---
+title: App Configuration
+description: Configure your Agentuity project
+---
+
+Agentuity projects use minimal configuration. Most setup happens in code, not config files.
+
+## agentuity.json
+
+The project configuration file:
+
+```json
+{
+ "name": "my-project",
+ "orgId": "org_...",
+ "projectId": "proj_..."
+}
+```
+
+No agent definitions, no trigger configurations. Those live in your code.
+
+## app.ts
+
+The app entry point configures your application:
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp();
+
+logger.debug('Running %s', server.url);
+```
+
+### With Lifecycle Hooks
+
+Use `setup` to initialize resources (databases, clients) and `shutdown` to clean up:
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ setup: async () => {
+ // Initialize resources, return app state
+ // Available in agents via ctx.app
+ const db = await connectDatabase();
+ return { db };
+ },
+ shutdown: async (state) => {
+ // Clean up resources
+ await state.db.close();
+ },
+});
+
+logger.debug('Running %s', server.url);
+```
+
+### With Custom Services
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ // CORS configuration
+ cors: {
+ origin: ['https://myapp.com'],
+ credentials: true,
+ },
+
+ // Response compression (gzip/deflate)
+ compression: {
+ threshold: 1024, // Compress responses larger than 1KB (default)
+ },
+
+ // Custom storage implementations (optional)
+ services: {
+ keyvalue: myCustomKV,
+ vector: myCustomVector,
+ },
+});
+```
+
+#### Compression Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `enabled` | `boolean` | `true` | Enable/disable compression |
+| `threshold` | `number` | `1024` | Minimum response size (bytes) to compress |
+| `filter` | `(c) => boolean` | - | Custom filter function |
+
+Compression automatically bypasses WebSocket upgrades and requests without `Accept-Encoding` headers.
+
+### Event Listeners
+
+Listen for agent and session lifecycle events:
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const app = await createApp();
+
+app.addEventListener('agent.started', (event, agent, ctx) => {
+ app.logger.info('Agent started', { name: agent.metadata.name });
+});
+
+app.addEventListener('agent.completed', (event, agent, ctx) => {
+ app.logger.info('Agent completed', { session: ctx.sessionId });
+});
+```
+
+## Build Configuration
+
+For advanced build customization, create an `agentuity.config.ts` file in your project root:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ // Configuration options here
+} satisfies AgentuityConfig;
+```
+
+
+Use build configuration to add Vite plugins (like Tailwind CSS), exclude packages from server bundling, or define build-time constants.
+
+
+See the [reference page](/Reference/CLI/build-configuration) for all options and examples.
+
+## Environment Variables
+
+```bash
+# Required
+AGENTUITY_SDK_KEY=... # API key for Agentuity services
+
+# Optional
+AGENTUITY_LOG_LEVEL=info # trace, debug, info, warn, error
+AGENTUITY_PORT=3500 # Dev server port (default: 3500)
+
+# Resource Credentials (auto-added by CLI when creating resources)
+DATABASE_URL=postgresql://... # Added by: agentuity cloud db create
+# S3 credentials # Added by: agentuity cloud s3 create
+# REDIS_URL=redis://... # From: agentuity cloud redis show
+
+# LLM Provider Keys (optional; if using your own API keys instead of the AI Gateway)
+OPENAI_API_KEY=sk-...
+ANTHROPIC_API_KEY=sk-ant-...
+
+# Frontend-accessible (exposed to browser)
+AGENTUITY_PUBLIC_API_URL=... # Any of these prefixes work:
+VITE_MY_VAR=... # - AGENTUITY_PUBLIC_*
+PUBLIC_MY_VAR=... # - VITE_*
+ # - PUBLIC_*
+```
+
+
+If you don't set provider API keys, LLM requests are routed through the Agentuity AI Gateway using your SDK key. This provides unified billing and monitoring.
+
+
+
+Environment variables prefixed with `AGENTUITY_PUBLIC_`, `VITE_`, or `PUBLIC_` are exposed to the frontend bundle and visible in the browser. Never put secrets or API keys in these variables.
+
+
+## Infrastructure as Code
+
+Unlike traditional platforms, Agentuity defines infrastructure in your route files:
+
+```typescript
+// src/api/index.ts
+import { createRouter, cron, websocket } from '@agentuity/runtime';
+import scheduler from '@agent/scheduler';
+import chatHandler from '@agent/chat';
+
+const router = createRouter();
+
+// Cron job - runs every hour
+router.post('/cleanup', cron('0 * * * *', async (c) => {
+ await scheduler.run({ task: 'cleanup' });
+ return c.text('OK');
+}));
+
+// WebSocket endpoint
+router.get('/chat', websocket((c, ws) => {
+ ws.onMessage(async (event) => {
+ const response = await chatHandler.run({ message: event.data as string });
+ ws.send(response);
+ });
+}));
+
+export default router;
+```
+
+This approach means:
+- **Deployments are self-contained**: rolling back restores exact configuration
+- **Version control**: your infrastructure changes are tracked in Git
+- **No config drift**: what's in code is what runs
+
+## Next Steps
+
+- [HTTP Routes](/Build/Routes/http): Define HTTP endpoints
+- [Cron Jobs](/Build/Routes/cron): Schedule recurring tasks
+- [AI Gateway](/Build/Agents/ai-gateway): Configure LLM providers
diff --git a/content/Get-Started/installation.mdx b/content/Get-Started/installation.mdx
new file mode 100644
index 00000000..16589347
--- /dev/null
+++ b/content/Get-Started/installation.mdx
@@ -0,0 +1,60 @@
+---
+title: Installation
+description: Set up your development environment
+---
+
+## Install the CLI
+
+```bash
+curl -sSL https://v1.agentuity.sh | sh
+```
+
+This installs the `agentuity` CLI globally on your system.
+
+
+If you prefer package managers: `bun add -g @agentuity/cli`
+
+
+## Create a Project
+
+```bash
+agentuity create my-app
+```
+
+The CLI will prompt you to select a [template](/Reference/CLI/getting-started#available-templates). Or specify one directly:
+
+```bash
+agentuity create my-app --template default
+```
+
+## Start the Dev Server
+
+```bash
+agentuity dev
+# or
+bun run dev
+```
+
+Your project is now running at `http://localhost:3500`. The dev server uses Vite for instant frontend updates and Bun for fast server rebuilds, so changes are reflected immediately.
+
+
+Agentuity projects run on [Bun](https://bun.sh). If you don't have Bun installed, the CLI will prompt you to install it when you create your first project.
+
+
+### CLI Shortcuts
+
+While the dev server is running, use these shortcuts:
+
+| Key | Action |
+|-----|--------|
+| `h` | Show help |
+| `c` | Clear console |
+| `r` | Restart server |
+| `o` | Show API routes |
+| `a` | Show agents |
+| `q` | Quit |
+
+## Next Steps
+
+- [Quickstart](/Get-Started/quickstart): Build your first agent
+- [Project Structure](/Get-Started/project-structure): Understand the file layout
diff --git a/content/Get-Started/meta.json b/content/Get-Started/meta.json
new file mode 100644
index 00000000..67c02f2b
--- /dev/null
+++ b/content/Get-Started/meta.json
@@ -0,0 +1,10 @@
+{
+ "title": "Get Started",
+ "pages": [
+ "what-is-agentuity",
+ "installation",
+ "quickstart",
+ "project-structure",
+ "app-configuration"
+ ]
+}
diff --git a/content/Get-Started/project-structure.mdx b/content/Get-Started/project-structure.mdx
new file mode 100644
index 00000000..de3c88f4
--- /dev/null
+++ b/content/Get-Started/project-structure.mdx
@@ -0,0 +1,128 @@
+---
+title: Project Structure
+description: Understand how Agentuity projects are organized
+---
+
+Agentuity projects follow a convention-based structure that enables automatic discovery and deployment.
+
+
+Creating a new agent is as simple as adding a folder to `src/agent/` with an `agent.ts` file. No CLI commands, no manual registration: agents are auto-discovered both locally and when deployed.
+
+
+## Directory Layout
+
+```
+my-project/
+├── agentuity.json # Project configuration
+├── .env # Environment variables
+├── package.json # Dependencies
+├── app.ts # App entry point
+└── src/
+ ├── agent/ # Agent code (required)
+ │ └── chat/
+ │ └── agent.ts # Agent logic
+ ├── api/ # HTTP routes (optional)
+ │ └── index.ts # All routes, imports agents
+ └── web/ # Frontend code (scaffolded by default)
+ └── App.tsx
+```
+
+Agent names come from their directory. Each agent has one file: `agent.ts` with your logic and schema.
+
+
+You can add helper files (like `types.ts`, `helpers.ts`, `utils.ts`) alongside your agents and routes. The build system only processes files that export agents or routers.
+
+
+## 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, 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.
+
+### 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/api/index.ts
+
+Routes import agents directly and call them:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chat.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await chat.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+The `chat.validator()` middleware 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 & Evals** | 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 currently supported via `@agentuity/react`, with a framework-agnostic approach that enables support for Next.js, Svelte, and others.
+
+```tsx
+// src/web/App.tsx
+import { useAPI } from '@agentuity/react';
+
+function App() {
+ const { data, invoke, isLoading } = useAPI('POST /api/hello');
+
+ return (
+ invoke({ name: 'World' })}>
+ {isLoading ? 'Loading...' : 'Say Hello'}
+
+ );
+}
+```
+
+
+You can also deploy your frontend elsewhere (e.g., Vercel, Netlify) and call your Agentuity agents via the React hooks with a configured `baseUrl`.
+
+
+## Next Steps
+
+- [App Configuration](/Get-Started/app-configuration): Configure `app.ts` and `agentuity.json`
+- [Creating Agents](/Build/Agents/creating-agents): Deep dive into agent creation
+- [Routes](/Build/Routes): Learn about HTTP, cron, and other triggers
diff --git a/content/Get-Started/quickstart.mdx b/content/Get-Started/quickstart.mdx
new file mode 100644
index 00000000..0f2bc6bb
--- /dev/null
+++ b/content/Get-Started/quickstart.mdx
@@ -0,0 +1,229 @@
+---
+title: Quickstart
+description: Build your first agent in 5 minutes
+---
+
+import { Card } from 'fumadocs-ui/components/card';
+import { Lightbulb } from 'lucide-react';
+
+This guide walks you through building a chat agent from scratch using OpenAI.
+
+
+Use a template to get a working project instantly:
+
+```bash
+agentuity create my-app --template vercel-openai
+```
+
+See [available templates](/Reference/CLI/getting-started#available-templates) for options.
+
+
+ }
+>
+ Learn how agents use tools and run in loops to complete tasks autonomously.
+
+
+## 1. Create the Agent
+
+Create `src/agent/chat/agent.ts`:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+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) => {
+ ctx.logger.info('Received message', { message: input.message });
+
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: input.message,
+ });
+
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+## 2. Add a Route
+
+Create `src/api/index.ts`:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chat.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await chat.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+## 3. Run Your Agent
+
+Start the dev server:
+
+```bash
+agentuity dev
+# or: bun run dev
+```
+
+Test your agent via curl:
+
+```bash
+curl -X POST http://localhost:3500/api/chat \
+ -H "Content-Type: application/json" \
+ -d '{"message": "What is the capital of France?"}'
+```
+
+Response:
+
+```json
+{
+ "response": "The capital of France is Paris."
+}
+```
+
+## 4. Test Locally with Workbench
+
+Workbench is a built-in UI for testing agents directly, without going through your frontend. Enable it by adding a `workbench` section to your `agentuity.config.ts`:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/workbench',
+ },
+} satisfies AgentuityConfig;
+```
+
+Open [http://localhost:3500/workbench](http://localhost:3500/workbench) to test your agents with raw JSON input. See [Testing with Workbench](/Build/Agents/workbench) for adding test prompts and configuration options.
+
+## 5. Add a Frontend
+
+Add a React UI in `src/web/` to call your agent. Here's a simple example:
+
+```tsx
+import { useAPI } from '@agentuity/react';
+import { useState } from 'react';
+
+export function App() {
+ const [message, setMessage] = useState('');
+ const { data, invoke, isLoading } = useAPI('POST /api/chat');
+
+ return (
+
+
setMessage(e.target.value)}
+ placeholder="Ask something..."
+ disabled={isLoading}
+ />
+
invoke({ message })} disabled={isLoading}>
+ {isLoading ? 'Thinking...' : 'Send'}
+
+ {data &&
{data.response}
}
+
+ );
+}
+```
+
+The `useAPI` hook provides type-safe access to your routes. It infers types from your agent's schema, so `data.response` is fully typed.
+
+## 6. Add Streaming
+
+For real-time responses, return a stream instead:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { s } from '@agentuity/schema';
+
+const agent = createAgent('Chat', {
+ schema: {
+ input: s.object({ message: s.string() }),
+ stream: true,
+ },
+ handler: async (ctx, input) => {
+ const { textStream } = streamText({
+ model: openai('gpt-5-mini'),
+ prompt: input.message,
+ });
+
+ return textStream;
+ },
+});
+
+export default agent;
+```
+
+Update the route to use the `stream()` middleware:
+
+```typescript
+import { createRouter, stream } from '@agentuity/runtime';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chat.validator(), stream(async (c) => {
+ const data = c.req.valid('json');
+ return chat.run(data);
+}));
+
+export default router;
+```
+
+## 7. Deploy
+
+When you're ready, deploy to Agentuity:
+
+```bash
+agentuity deploy
+# or: bun run deploy
+```
+
+Your agent is now live with a public URL. View deployments, logs, and more in the [App](https://app-v1.agentuity.com).
+
+
+After your first deployment, the App populates with:
+- **Agents**: Your deployed agents with their endpoints
+- **Routes**: Registered HTTP, cron, and other routes
+- **Sessions**: Request history and logs as traffic flows
+- **Deployments**: Version history with rollback options
+
+
+## What's Next?
+
+**Learn the concepts:**
+
+- [Understanding How Agents Work](/Learn/Cookbook/Tutorials/understanding-agents): Tools, loops, and autonomous behavior
+
+**Build something more:**
+
+- [Build a multi-agent system](/Build/Agents/calling-other-agents): Routing, RAG, workflows
+- [Persist data](/Build/Agents/state-management): Use thread and session state
+- [Explore React Hooks](/Build/Frontend/react-hooks): WebSocket, SSE, and more patterns
+
+**Understand the platform:**
+
+- [Project Structure](/Get-Started/project-structure): Agents, routes, and frontend
+- [App Configuration](/Get-Started/app-configuration): Configure your project
+- [Local Development](/Reference/CLI/development): Dev server, hot reload, and debugging
diff --git a/content/Get-Started/what-is-agentuity.mdx b/content/Get-Started/what-is-agentuity.mdx
new file mode 100644
index 00000000..af86f691
--- /dev/null
+++ b/content/Get-Started/what-is-agentuity.mdx
@@ -0,0 +1,65 @@
+---
+title: What is Agentuity?
+description: The full-stack platform for building, deploying, and operating AI agents
+---
+
+Write TypeScript, define routes, and deploy with a single command. We handle the infrastructure, from automatic scaling to built-in observability and more.
+
+Here's a basic example:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+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) => {
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: input.message,
+ });
+ return { response: text };
+ },
+});
+
+export default agent;
+```
+
+This agent uses the AI SDK to call OpenAI and respond to messages. Deploy with `agentuity deploy` and it scales automatically. Call it from web apps, other agents, or any HTTP client.
+
+## What You Get
+
+- **Routes & Triggers**: HTTP, WebSocket, SSE, cron
+- **Storage**: Key-value, vector, object storage, durable streams
+- **[Sandbox](/Build/Sandbox)**: Execute code in isolated containers with controlled resources and network access
+- **[Evaluations](/Build/Agents/evaluations)**: Automated quality checks that run after each agent execution
+- **[AI Gateway](/Build/Agents/ai-gateway)**: Route LLM calls through OpenAI, Anthropic, Google, and more
+- **Type Safety**: Built-in schema validation with `@agentuity/schema`, Zod, or Valibot
+- **Observability**: Logging, tracing, real-time analytics
+- **[App](https://app-v1.agentuity.com)**: Visual dashboard for deployments, logs, and more
+- **Frontend**: Deploy React apps alongside your agents
+
+## How It Works
+
+Each agent lives in its own file under `src/agent/`. Routes are defined separately in `src/api/index.ts`:
+
+| File | Purpose |
+|------|---------|
+| `agent.ts` | Agent logic with schema validation |
+| `api/index.ts` | HTTP endpoints that call your agents |
+
+Infrastructure like cron schedules is defined in route code, not config. Rolling back a deployment restores the exact configuration from that version.
+
+---
+
+We're building for a future where agents are the primary way to build and operate software, and where infrastructure is purpose-built for this new paradigm.
+
+## Next Steps
+
+- [Installation](/Get-Started/installation): Set up your environment
+- [Quickstart](/Get-Started/quickstart): Build your first agent in 5 minutes
diff --git a/content/Guides/.agent-patterns.mdx b/content/Guides/.agent-patterns.mdx
deleted file mode 100644
index db975f3a..00000000
--- a/content/Guides/.agent-patterns.mdx
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Agent Patterns
-description: Agent architectural patterns and best practices
----
diff --git a/content/Guides/.security.mdx b/content/Guides/.security.mdx
deleted file mode 100644
index 6afb1e15..00000000
--- a/content/Guides/.security.mdx
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Security Guide
-description: Security Guide and Best Practices for using Agentuity
----
diff --git a/content/Guides/agent-communication.mdx b/content/Guides/agent-communication.mdx
deleted file mode 100644
index 186dafad..00000000
--- a/content/Guides/agent-communication.mdx
+++ /dev/null
@@ -1,249 +0,0 @@
----
-title: Agent Communication
-description: Agent-to-Agent communication patterns, usage and best practices
----
-
-import Image from "next/image";
-
-
-
-## Overview
-
-In most advanced agentic scenarios, agents need to communicate with other agents to achieve their goals. In fact, our recommendation is that you build agents with highly specialized roles and skills and use agent-to-agent communication to achieve the overall goal.
-
-There are a number of ways to achieve agent-to-agent communication natively in Agentuity.
-
-## Communication Types
-
-Agents can communicate with each other in a number of ways in the Agentuity platform. The following are the different types of communication that are supported:
-
-| Type | Description |
-|-----------|-------------|
-| **Intra Project** | Agents within the same project can communicate with each other locally without leaving the local network |
-| **Inter Project** | Agents can communicate with each other across projects within the same organization across the internal network |
-| **Inter Organization** | Agents can communicate with each other across organizations across the internal network |
-
-### Intra Project
-
-Intra project communication is the simplest form of agent-to-agent communication. Agents within the same project can communicate with each other locally without leaving the local network.
-
-### Inter Project
-
-Inter project communication is a more advanced form of agent-to-agent communication. Agents can communicate with each other across projects within the same organization but will communicate over the internal network.
-
-### Inter Organization
-
-Inter organization communication is the most advanced form of agent-to-agent communication. Agents can communicate with each other across organizations. Currently, Agentuity only supports inter organization agent communication if the target agent is public and the source agent has been given the agent ID by the other organization. For inter organization communication, the source agent will communicate over the internal network.
-
-## Communication Methods
-
-Agents have two primary methods of communication with other agents:
-
-| Type | Description |
-|-----------|-------------|
-| Handoff | Agents can handoff a request to another agent to complete |
-| Invocation | Agents can invoke another agent to complete a task and wait for the result |
-
-### Handoff
-
-When an agent needs to handoff a request to another agent, it can do so by using the SDK `handoff` method. The `handoff` method will send the request to another agent and the other agent will be responsible for completing the request.
-
-For handoff, the source agent can modify the original request data or simply pass the request as is. The target agent will receive the request and can complete the request as if it was the original request.
-
-A trivial example of a handoff:
-
-
-
-In the above example, the source agent is sending a request to the `My Other Agent` agent. The `My Other Agent` agent will receive the request and can complete the request as if it was the original request.
-
-Calling another agent is a common pattern in agentic workflows. It is often used to delegate a task to another agent or to get the result of a task from another agent.
-
-In another trivial example, the source agent is sending a request to the `My Other Agent` agent and passing a message to the other agent. The `My Other Agent` agent will receive the request and can complete the request as if it was the original request. Since we are passing a String type, the other agent will receive the message as a string and with content type `text/plain`.
-
-
-
-### Invocation
-
-When an agent needs to invoke another agent to complete a task and wants to wait for the result, it can do so by using the SDK `getAgent` method on `AgentContext`. The `getAgent` will perform resolution to determine the target agent location and return a handle to the target agent that can be used to `run` the target agent.
-
-If the target agent is local (intra project), the `getAgent` method will return a handle to an internal agent which can be used to `run` the target agent.
-
-If the target agent is remote (inter project or inter organization), the `getAgent` method will return a handle to an external agent which can be used to `run` the target agent. In addition, the SDK internally will use the authorization token to authenticate the source agent to the target agent.
-
-
-
-A trivial example of an invocation:
-
-
-
-> **Note:** JavaScript uses `{ data, contentType }` format while Python infers content type from the raw payload passed directly.
-
-In this trivial example above, the functionality is similar to the handoff example above. The source agent is sending a request to the `My Other Agent` agent and passing a message to the other agent. The `My Other Agent` agent will receive the request, perform an operation and return the result to the source agent. The source agent will simply return the result as a text result.
-
-In a real life scenario, you'll likely want to pass the appropriate data types to the target agent and wait for the result and then use the result in your own agent to perform additional tasks.
-
-#### Parallel Execution
-
-Sometimes you want to send a request to multiple agents at the same time. This is an example of parallel execution.
-
-
-
-In this example, the source agent is sending a request to two different agents at the same time. The source agent will wait for both agents to complete their tasks before returning.
-
-In a real life scenario, you'll likely want to pass the appropriate data types to the target agents and wait for the results and process them before continuing.
-
-
-
-## Agent Resolution
-
-How do we resolve the target agent? There are three main ways to do this:
-
-| Type | Description |
-|-----------|-------------|
-| Agent ID | The agent ID is a unique identifier for an agent. It is a string that is assigned to an agent when it is created. |
-| Agent Name | The agent name is a human readable name for an agent. It is a string that was used for the agent's name. |
-| Project ID | The agent project ID is specified to disambiguate agents with the same name in different projects. |
-
-### Intra Project Resolution
-
-When calling an agent within the same project, the agent name is usually the easiest way to resolve the target agent. The agent name is a human readable name for an agent. It is a string that was used for the agent's name.
-
-### Inter Project Resolution
-
-When calling an agent across projects within the same organization, the agent ID is typically the most reliable way to resolve the target agent. The agent ID is a unique identifier for an agent.
-
-However, if the agent name is not unique across projects, the agent project ID can be used to disambiguate the target agent. The agent project ID is a unique identifier for an agent's project.
-
-A trivial example of a handoff:
-
-
-
-### Inter Organization Resolution
-
-Currently, Agentuity only supports inter organization agent communication if the target agent is public and the source agent has been given the agent ID by the other organization. When using inter organization communication, only the agent ID is required to resolve the target agent.
-
-## Communication Authorization
-
-When communicating with other agents outside the local project, Agentuity will automatically generate a one-time use authorization token with a short expiration. This token is used to authenticate the source agent to the target agent automatically without the need for the source agent to pass the token to the target agent.
diff --git a/content/Guides/agent-data-handling.mdx b/content/Guides/agent-data-handling.mdx
deleted file mode 100644
index de491e2f..00000000
--- a/content/Guides/agent-data-handling.mdx
+++ /dev/null
@@ -1,474 +0,0 @@
----
-title: Agent Data Handling
-description: How to handle data formats in your agents
----
-
-## Overview
-
-We provide a few different ways to handle data formats in your agents to make it easier to work with different data types. Of course, your agent can always perform its own data handling by using the raw data and the content type property. However, most common data types are supported out of the box.
-
-## How it works
-
-Data that is sent to your agent is transferred as raw binary data and the content type is provided to the agent. The agent can then use the content type to determine how to handle the data. The `AgentRequest` object provides a `data` property that contains the `Data` object. The `Data` object provides a `contentType` property that contains the content type of the data. The `Data` object also provides a number of helper methods to help you handle the data.
-
-When you send data to your agent using the HTTP protocol, for example, the `Content-Type` HTTP header is used to determine the content type of the data. If you are sending binary type data, make sure that you use raw binary data and set the `Content-Type` HTTP header to the appropriate value. When using Agent-to-Agent communication, the Agentuity SDK will automatically determine the content type of the data based on the data that is sent. You can override the content type by passing the content type.
-
-Often, your agent will need to handle different formats dynamically. In this case, you can use the `contentType` property to determine the format of the data.
-
-
-
-## Request Data Formats
-
-The following request data formats are supported out of the box:
-
-### Text
-
-You can use the `text` method on the `Data` object to get the raw text data.
-
-
-
-You must await the `text` method to get the raw text data since the data could be a stream. In the case the data is streamed to the agent, the agent will wait for the data to be fully streamed before returning the text data.
-
-In the case the data is another content type that isn't text, the `text` method will return the raw data as a string. For example, if the content type is `application/json`, the `text` method will return the raw JSON data as a string.
-
-### JSON
-
-You can use the `json` method on the `Data` object to get the raw JSON data.
-
-
-
-You must await the `json` method to get the raw JSON data since the data could be a stream. In the case the data is streamed to the agent, the agent will wait for the data to be fully streamed before returning the JSON data.
-
-In the case the data is another content type that isn't JSON, the `json` method will attempt to parse the data as JSON. If the data is not valid JSON, the `json` method will throw an error.
-
-### Object
-
-You can use the `object` method on the `Data` object to get the JSON data as an object cast to the type you provide. This currently only works for JSON data and the JavaScript SDK.
-
-();
-}`} />
-
-### Binary
-
-If you want to get the raw binary data, you can use the `binary` method on the `Data` object.
-
-
-
-You must await the `binary` method to get the raw binary data since the data could be a stream. In the case the data is streamed to the agent, the agent will wait for the data to be fully streamed before returning the binary data.
-
-For JavaScript, the `binary` method returns a `Uint8Array` object. For Python, the `binary` method returns a `bytes` object.
-
-### Stream
-
-If you want to get the raw binary data as a stream, you can use the `stream` method on the `Data` object.
-
-
-
-You must await the `stream` method to get a stream of the raw binary data. The stream will be a `ReadableStream` object for JavaScript and a `IO[bytes]` object for Python.
-
-See the [Streaming](/Guides/agent-streaming) guide for more information on how Agent Streaming works.
-
-### Base64
-
-If you want to get the raw binary data as a base64 encoded string, you can use the `base64` method on the `Data` object.
-
-
-
-You must await the `base64` method to get the base64 encoded string.
-
-### Email
-
-If you want to get the raw binary data as an email object, you can use the `email` method on the `Data` object. This assumes that the request payload was an RFC822 encoded email.
-
-
-
-
- The email object is only supported when you setup your agent to receive emails.
-
-
-You must await the `email` method to get the email object. The email object will be a `Email` object. The Email object has the following properties:
-
-- `date`: The date of the email.
-- `messageId`: The message ID of the email.
-- `fromEmail`: The sender of the email.
-- `fromName`: The sender name (if provided).
-- `subject`: The subject of the email.
-- `attachments`: The attachments of the email as an array of `Attachment` objects.
-- `headers`: The headers of the email as an array of `Header` objects.
-- `text`: The text body of the email.
-- `html`: The HTML body of the email.
-
-The `Attachment` object has the following properties:
-
-- `filename`: The filename of the attachment.
-- `contentDisposition`: The content disposition of the attachment which is either `inline` or `attachment`. Defaults to `attachment`.
-- `data`: The `DataType` of the attachment.
-
-#### Sending Email Replies
-
-Both SDKs support sending replies to incoming emails using the `sendReply` method. This requires the email-auth-token to be present in the request metadata.
-
-Thank you for your message. We'll respond within 24 hours .",
- attachments: [attachment]
- }, {
- name: "Support Team",
- email: "support@yourcompany.com"
- });
-
- ctx.logger.info("Reply sent successfully");
-
- return resp.json({
- status: "Reply sent"
- });
-}`}py={`from agentuity import AgentRequest, AgentResponse, AgentContext
-from agentuity.io.email import EmailAttachment
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- email = await request.data.email()
-
- attachment = EmailAttachment(
- filename="response.pdf",
- data=pdf_data,
- content_type="application/pdf"
- )
-
- await email.sendReply(
- request=request,
- context=context,
- subject="Re: Your inquiry",
- text="Thank you for your message. We'll respond within 24 hours.",
- html="Thank you for your message. We'll respond within 24 hours .
",
- attachments=[attachment],
- from_email="support@yourcompany.com",
- from_name="Support Team"
- )
-
- context.logger.info("Reply sent successfully")
-
- return response.json({"status": "Reply sent"})
-`} />
-
-
-Using a custom email address in the reply requires organizational email domain setup. Please contact us if you would like to configure for your organization.
-
-
-#### Large Attachment Support
-
-Both SDKs now support large email attachments through streaming mechanisms:
-
-- **Incoming attachments**: Use the `data()` method which returns a Promise/async Data object that streams the content
-- **Outgoing attachments**: Can handle large files efficiently through the attachment data handling
-- **OpenTelemetry tracing**: Automatic tracing is included for attachment operations to monitor performance
-
-## Response Data Formats
-
-The following response data formats are supported out of the box. Use these methods on the `AgentResponse` object to send data in the desired format from your agent.
-
-### Text
-
-You can use the `text` method to send a plain text response.
-
-
-
-### JSON
-
-You can use the `json` method to send a JSON response.
-
-
-
-### Binary
-
-You can use the `binary` method to send raw binary data.
-
-
-
-### Media Types (Images, Audio, Video, PDF, etc.)
-
-The SDK provides helpers for common media types. Use the corresponding method for the type you want to return (e.g., `png`, `jpeg`, `pdf`, `mp3`, etc.).
-
-
-
-### Markdown
-
-You can use the `markdown` method to return markdown content.
-
-
-
-### HTML
-
-You can use the `html` method to return HTML content.
-
-Hello, world!This is an HTML response.
');
-}`} py={`from agentuity import AgentRequest, AgentResponse, AgentContext
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- return response.html("Hello, world! This is an HTML response.
")
-`} />
-
-### Streaming
-
-For large or real-time responses, you can stream data using the `stream` method. The source can be an async iterator, a stream, or another agent's stream.
-
-
-
-### Custom Response
-
-For advanced use cases, you can return a native Response object from your agent.
-
-
-
-For JavaScript, the `Response` object follows the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Response) interface.
-For Python, the `Response` object follows the [aiohttp.ClientResponse](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientResponse) interface.
diff --git a/content/Guides/agent-engineering.mdx b/content/Guides/agent-engineering.mdx
deleted file mode 100644
index fb3be917..00000000
--- a/content/Guides/agent-engineering.mdx
+++ /dev/null
@@ -1,132 +0,0 @@
----
-title: Agent Engineering
-description: Effective software engineering in an agentic future
----
-
-## Thinking Like an Agent Builder: A Shift for Software Engineers
-
-Traditional software engineering is built around deterministic logic, tightly scoped inputs and outputs, and rigid control flows. When you start building agents, you're no longer programming every behavior—you're designing systems that can interpret goals, reason about context, and act autonomously.
-
-> 🤔 Not sure what an agent is? Check out [What is an Agent?](/Guides/what-is-an-agent)
-
-Building agents isn't just about writing code—it's about shaping intelligent behavior.
-
-This shift requires a new mindset:
-
-### Key Mindset Shifts and Tips for Engineers
-
-1. Design for Intent, Not Implementation
-
-Old way: Define every step in a process explicitly.
-
-New way: Focus on what outcome you want the agent to achieve, and give it the tools and context to figure out how.
-
-> ✅ Tip: Practice writing clear prompts and goal descriptions instead of hard-coded workflows.
-
-2. Embrace Non-Determinism
-
-Agents may behave differently based on context, input phrasing, or new knowledge.
-
-This variability isn't a bug — it's a feature that enables adaptation and learning.
-
-> ✅ Tip: Use guardrails, feedback loops, and observability tools to manage unpredictability rather than eliminate it.
-
-3. Think in Terms of Capabilities, Not Functions
-
-Agents aren't bound by one task — they're modular, extensible entities that can take on roles.
-
-You compose capabilities (retrieval, summarization, API calls, etc.) instead of defining one static purpose.
-
-> ✅ Tip: Start building with reusable "skills" or tools that agents can invoke as needed.
-
-4. Develop and Debug Through Simulation and Prompt Testing
-
-You won't always have step-by-step logic to trace. You'll be tuning prompts, memory, and planning behavior.
-
-> ✅ Tip: Set up scenarios to simulate tasks, iterate on prompt engineering, and observe agent decisions.
-
-5. Trust the Model — But Verify
-
-Leverage the power of foundation models, but don't assume perfection.
-
-Validation, fallback logic, and human-in-the-loop design are still critical.
-
-> ✅ Tip: Use confidence scoring, output evaluation, and error-handling strategies just like you would for user input in traditional apps.
-
-----
-
-### Can you show me a practical example of the difference?
-
-In traditional software engineering, you might build a function that takes a user's input in a specific format and data shape and then sends that data to another system (say a database or CRM system).
-
-For example, let's say you have input JSON and your API takes a specific data shape such as:
-
-```json
-{"firstName":"Jeff","lastName":"Bezos"}
-```
-
-Traditionally, you would build a function that takes this input, parses it, transforms it and then invokes the other system with the transformed data. _There are significant products that have been built to tackle this sole problem_.
-
-In an agentic approach, you could just ask the AI to do this for you with a prompt like this:
-
-```xml title="AI Prompt"
-
-convert the input to an output using the JSON schema
-
-
-
-{"firstName":"Jeff","lastName":"Bezos"}
-
-
-
-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "title": "Person",
- "type": "object",
- "properties": {
- "first_name": {
- "type": "string",
- "description": "The person's first name"
- },
- "last_name": {
- "type": "string",
- "description": "The person's last name"
- }
- },
- "required": ["first_name", "last_name"]
-}
-
-
-
-- The output should be in a JSON format that validates against the JSON schema.
-- If the input is not valid, the output should be an error message.
-
-```
-
-The AI would respond with something like this:
-
-```ansi title="AI Response"
-To convert the given JSON input to match the specified JSON schema, you need to change
-the keys from firstName and lastName to first_name and last_name, respectively.
-
-{"first_name": "Jeff","last_name": "Bezos"}
-
-This output adheres to the schema by:
-
-- Using snake_case property names (first_name and last_name)
-- Providing required string values
-- Avoiding any additional properties beyond those defined in the schema
-
-```
-
-As you can see, the AI has not only converted the JSON to the correct format, but it has also validated that the output matches the schema for you.
-
-> 💫 **Agentic software engineering requires you to approach tasks with a much different mindset than you have before!**
-
-Modern AI can also not only return output, it can return structured output too (such as providing a JSON for the AI to conform). In addition, AIs can now use tool calling to call back to your agent to ask it to perform a specific task that you define to help the AI further reason about the task at hand.
-
-----
-
-Agents represent a new abstraction layer — between human goals and system actions. As an engineer, your job shifts from building every bridge to empowering an intelligent system to build those bridges for you. That's not just a technical challenge—it's a creative one.
-
-Make sure you understand the differences between today's cloud computing paradigm and the [Agent-Native Cloud](/Guides/agent-native-cloud).
\ No newline at end of file
diff --git a/content/Guides/agent-io.mdx b/content/Guides/agent-io.mdx
deleted file mode 100644
index 0f4497f6..00000000
--- a/content/Guides/agent-io.mdx
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Agent Input and Output
-description: How to handle agent input and output
----
-
-## Overview
-
-Agent IO enables your agents to communicate with external platforms through two types of connections: Sources (inbound) and Destinations (outbound). Understanding the distinction between these connection types is essential for properly configuring your AI agents on the Agentuity platform.
-
-## Sources vs Destinations
-
-### Sources (Inbound Connections)
-
-Sources enable bidirectional communication between a platform and your agent. When configured, the platform can trigger your agent and receive responses within the same conversation context.
-
-**How Sources Work:**
-1. Platform triggers agent (e.g., @mention in Slack)
-2. Agent processes the request
-3. Agent responds directly within the same platform conversation
-
-**Example:** When someone @mentions your agent in Discord, the agent can respond back in the same Discord channel.
-
-### Destinations (Outbound Connections)
-
-Destinations allow your agent to send messages to a platform when triggered by *external sources*. These are one-way connections for delivering agent output to specified channels.
-
-**How Destinations Work:**
-1. External source triggers agent (webhook, API, schedule, etc.)
-2. Agent processes the request
-3. Agent sends output to configured destination platforms
-
-**Example:** Your GitHub repository triggers your agent on each commit, and the agent sends a formatted summary to your team's Discord channel.
-
-## Choosing Your Configuration
-
-| Use Case | Configuration Needed |
-|---------------------|---------------------|
-| Chat bot that responds to @mentions | **Source only** |
-| Send notifications when something happens | **Destination only** |
-| Forward messages between platforms | **Source** for receiving, **Destination** for sending |
-| Full assistant with chat and notifications | **Both** Source and Destination |
-
-### Sources Only
-Perfect for conversational bots that respond to user questions, @mentions, or direct messages.
-
-**Example:** Your team wants a Slack bot that answers questions about your documentation. You only need a Slack Source - users @mention the bot, and it replies in the thread.
-
-### Destinations Only
-Ideal for automated notifications, scheduled updates, or forwarding alerts from monitoring systems.
-
-**Example:** You want GitHub commit notifications in Discord. Configure a webhook to trigger your agent, then add Discord as a Destination. No Discord Source needed since the bot doesn't respond to Discord messages.
-
-### Both Sources and Destinations
-Required when your agent needs conversations AND notifications, connecting multiple platforms, or building a full-featured assistant.
-
-**Example:** You're building a team assistant that answers questions in Slack (Source) but also posts daily standup reminders (Destination) and forwards important emails to the channel (Email Source → Slack Destination).
-
-## Key Considerations
-
-- **Sources** provide complete conversational capability - you don't need a destination to reply
-- **Destinations** work independently - perfect for one-way notifications
-- A single agent can have multiple sources and destinations configured
-
-## Video Tutorials
-
-{/* ### Configuring Slack Inbound
- */}
-
-### Email Destination Configuration
-VIDEO
-
-## Next Steps
-
-- Review the [Agents](/Cloud/agents) documentation for platform-specific configuration
-- Configure *sources* for platforms where users will interact with your agent
-- Set up *destinations* for platforms where your agent will send notifications
diff --git a/content/Guides/agent-logging.mdx b/content/Guides/agent-logging.mdx
deleted file mode 100644
index fec1553b..00000000
--- a/content/Guides/agent-logging.mdx
+++ /dev/null
@@ -1,253 +0,0 @@
----
-title: Agent Logging
-description: How to use logging in your agents
----
-
-## What is Agent Logging?
-
-Agent logging provides structured, real-time insights into your agent's execution. Effective logging helps you debug issues, monitor behavior, and understand agent decision-making.
-
-## Logging Interface
-
-The Agentuity platform provides persistent, searchable logs with real-time streaming for all deployed agents.
-
-
-
-### Log Overview
-
-The Logs dashboard displays:
-
-- **Timestamps**: Precise timing for each log entry
-- **Severity levels**: INFO, WARN, ERROR for categorization
-- **Source identification**: Which component generated the log
-- **Detailed messages**: Context about agent actions
-
-### Search and Filtering
-
-**AI-Powered Search:**
-Use natural language queries to find log entries. Click the purple sparkle icon and enter your search:
-
-
-
-**Filtering Options:**
-- **Severity**: Filter by log level (INFO, WARN, ERROR, etc.)
-- **Project**: Scope logs to specific projects
-- **Agent**: View logs from specific agents
-- **Session ID**: Filter logs for a particular session
-- **Deployment ID**: View logs from specific deployments
-- **Time Range**: Focus on specific time periods
-
-### Detailed Log Analysis
-
-Each log entry provides comprehensive context and can be expanded for full details:
-
-
-
-## Logging Best Practices
-
-
-**Language Differences:** JavaScript supports structured data objects directly, while Python uses the standard `logging.Logger` interface (with structured data via `extra` parameters).
-
-
-### 1. Use Appropriate Log Levels
-
-
-
-### 2. Use Structured Data
-
-Use structured data to provide context and make logs easier to parse and analyze:
-
-
-
-### 3. Include Relevant Context
-
-Log enough information to understand what happened without re-running:
-
-
-
-### 4. Include Agentuity-Specific Information
-
-Add Agentuity-specific information to help with debugging and monitoring:
-
-
-
-### 5. Log Decision Points
-
-Help future debugging by logging key decisions:
-
-
-
-### 6. Avoid Logging Sensitive Data
-
-Never log passwords, tokens, or personal information:
-
-
-
-### 7. Use Child Loggers for Different Tasks
-
-Create child loggers to organize logging for different parts of your workflow:
-
-
-
-For more observability features, see [Agent Telemetry](/Guides/agent-telemetry) and [Agent Tracing](/Guides/agent-tracing).
\ No newline at end of file
diff --git a/content/Guides/agent-native-cloud.mdx b/content/Guides/agent-native-cloud.mdx
deleted file mode 100644
index db7a481c..00000000
--- a/content/Guides/agent-native-cloud.mdx
+++ /dev/null
@@ -1,117 +0,0 @@
----
-title: Agent Native-Cloud
-description: The Agent-Native Cloud and what makes it different from other cloud platforms
----
-
-## What Is an Agent-Native Cloud?
-
-**Agent-Native** means the cloud itself is designed for AI agents as the *primary* citizens — not retro-fitted for them. Instead of asking agents to squeeze into workflows that were built for humans or stateless micro-services, an agent-native cloud gives them native abilities to collaborate, reason, persist state, and evolve.
-
-In short, an agent-native platform is to AI agents what *cloud-native* was to containers: the right environment, abstractions, and tooling built in from day one.
-
-This is our vision for the future of cloud computing, the Agentic-Native Cloud. The cloud reimagined, for agents. We call it Agentuity .
-
-> 💡 For a deeper narrative, read our blog post [The Agent-Native Cloud](https://agentuity.com/blog/agent-native).
-
-## Agentuity in One Sentence
-
-**Agentuity is the first *Agent-Native Cloud*** — an ecosystem engineered from first principles for the full lifecycle of autonomous AI agents.
-
-## Why a New Kind of Cloud?
-
-
-
-
# Traditional Cloud
-
- Stateless by default
- Human-centric UIs & APIs
- Manual ops & dashboards
- One-off deployments
-
-
-
-
@ Agent-Native Cloud
-
- Stateful & memory-aware
- Agent collaboration protocols
- Self-healing *agentic* operations
- Continuous learning & evolution
-
-
-
-
-If your infrastructure can't help agents learn, adapt, and coordinate at machine-speed, it isn't truly agent-native.
-
-## The Three Pillars of Agentuity
-
-
-
-
[1] Agent-First Design
-
-
- ▸ Native Agent Lifecycle
- Define, deploy, version, and retire agents with tooling that understands goals and capabilities, not just containers.
-
-
- ▸ Structured Inter-Agent Communication
- Built-in support for protocols like MCP/A2A so agents exchange durable, machine-readable messages instead of fragile prompts.
-
-
- ▸ Composable Architectures
- Assemble complex multi-agent systems quickly from reusable modules and roles.
-
-
-
-
-
-
[2] Agentic Operations
-
-
- ▸ Stateful, Persistent Runtimes
- Agents retain long-term context and memory without hitting serverless timeouts.
-
-
- ▸ Autopilot-Style Observability
- Platform agents monitor, remediate, and audit themselves under your guard-rails.
-
-
- ▸ Elastic Swarms & Scaling
- Scale from a single helper agent to thousands of specialised workers automatically.
-
-
-
-
-
-
[3] Agentic Learning & Evolution
-
-
- ▸ Rich Memory Primitives
- Working, episodic, and semantic memory layers are built-in.
-
-
- ▸ Reflection & Reinforcement Loops
- Agents introspect, gather feedback, and self-tune via managed RL pipelines.
-
-
- ▸ Collective Intelligence
- Securely share learnings across agent teams or organisations for compounding gains.
-
-
-
-
-
-## Who Benefits?
-
-• **Agents** – Gain a native environment with memory, collaboration protocols, and learning loops so they can act reliably, adapt, and continuously improve.
-
-• **Developers** – Focus on behaviour, not boiler-plate. Agentuity gives you SDKs, simulators, and debugging tailored to agent logic.
-
-• **Ops & SRE** – Fewer 3 AM pages. Self-healing routines fix issues in seconds and leave an explainable audit trail.
-
-• **Leadership** – Faster time-to-value, lower TCO, and infrastructure that *gets better with age*.
-
-If you're in software engineering, you need to think like an [Agent Builder](/Guides/agent-engineering).
-
----
-
-Need something that's built *for* agents? Welcome to Agentuity.
diff --git a/content/Guides/agent-streaming.mdx b/content/Guides/agent-streaming.mdx
deleted file mode 100644
index c518cd22..00000000
--- a/content/Guides/agent-streaming.mdx
+++ /dev/null
@@ -1,520 +0,0 @@
----
-title: Agent Streaming
-description: How to use streaming in your agents
----
-
-> **Streaming lets your users read the response before the AI finishes thinking.** Nothing feels faster than already happening.
-
-## Why Streaming?
-
-- **Latency hiding** by showing results instantly instead of after the whole response is ready.
-- **Large inputs and outputs** without hitting payload limits.
-- **Agent chains** can forward chunks to the next agent as soon as they arrive.
-- **Snappier UX** so users see progress in milliseconds instead of waiting for the full payload.
-- **Resource efficiency** by not holding entire responses in memory; chunks flow straight through.
-- **Composable pipelines** by allowing agents, functions, and external services to hand off work in a continuous stream.
-
-**A simple visualization of the difference between traditional request/response and streaming:**
-
-```bash
-┌─────────────────────────── traditional request/response ───────────────────────────────────┐
-| client waiting ... ██████████████████████████████████████████ full payload display |
-└────────────────────────────────────────────────────────────────────────────────────────────┘
-
-┌─────────────────────────── streaming request/response ─────────────────────────────────────┐
-| c l i e n t r e a d s c h u n k 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 … |
-└────────────────────────────────────────────────────────────────────────────────────────────┘
-```
-
-### Real-World Use Cases
-
-- **Live chat / customer support.** Stream the assistant's words as they are generated for a more natural feel.
-- **Speech-to-text.** Pipe microphone audio into a transcription agent and forward captions to the UI in real time.
-- **Streaming search results.** Show the first relevant hits immediately while the rest are still processing.
-- **Agent chains.** One agent can translate, the next can summarize, the third can analyze – all in a single flowing stream.
-
-## How Streaming Works in Agentuity
-
-Agentuity provides multiple approaches for streaming data:
-
-1. **High-level Streaming:** `resp.stream(source)` – where `source` can be:
- - An async iterator (e.g. OpenAI SDK stream)
- - A ReadableStream
- - Another agent's stream
-2. **Low-level Stream Control:** `context.stream.create(name, props)` – create and manage server-side streams directly
-3. **Inbound:** `await request.data.stream()` – consume the client's incoming stream.
-
-Under the hood Agentuity handles the details of the streaming input and output for you.
-
-### OpenAI Streaming Example
-
-In this example, we use the OpenAI SDK to stream the response from the OpenAI API back to the caller.
-
-
-
-### Structured Object Streaming with Vercel AI SDK
-
-The stream method now supports transformer functions that can filter and transform stream items. This is particularly useful when working with structured data from AI SDKs like Vercel AI SDK's `streamObject`.
-
-
-
-The SDK automatically detects object streams and converts them to JSON newline format with the appropriate `application/json` content type.
-
-### Stream Transformers
-
-You can provide transformer functions to filter and transform stream data:
-
- {
- // Filter out items (return null/undefined to skip)
- if (!item.active) return null;
-
- // Transform the item
- return {
- id: item.id,
- name: item.name.toUpperCase(),
- timestamp: Date.now()
- };
- };
-
- return resp.stream(dataStream, undefined, {}, transformer);
-}`} />
-
-You can also use generator functions for more complex transformations:
-
-
-
-### Agent-to-Agent Streaming
-
-In this example, we use the Agentuity SDK to stream the response from one agent to another.
-
-```ts
-import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
-
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- // [1] Call another agent
- const expert = await ctx.getAgent({ name: "HistoryExpert" });
- const expertResp = await expert.run({ prompt: "What engine did a P-51D Mustang use?" });
-
- // [2] Grab its stream
- const stream = await expertResp.data.stream();
-
- // [3] Pipe straight through
- return resp.stream(stream);
-}
-```
-
-Chain as many agents as you like; each one can inspect, transform, or just relay the chunks.
-
-## Low-Level Stream Control
-
-For advanced use cases, you can create and manage streams directly with `context.stream.create()`, giving you fine-grained control over stream creation, data flow, and background processing.
-
-### Creating Streams with `context.stream.create`
-
-This method returns a Promise that resolves to a named, writable stream. The stream is created immediately, enabling background data processing without blocking the response:
-
-```ts
-import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const { prompt } = await req.data.json();
-
- // Create a stream
- const stream = await ctx.stream.create('llm-response', {
- contentType: 'text/plain',
- metadata: {
- requestId: ctx.sessionId,
- type: 'llm-generation',
- model: 'gpt-4o'
- }
- });
-
- // Use waitUntil to handle streaming in the background
- ctx.waitUntil(async () => {
- const { textStream } = streamText({
- model: openai('gpt-4o'),
- prompt
- });
-
- // Pipe the LLM stream to our created stream
- await textStream.pipeTo(stream);
- });
-
- // Return stream information immediately
- return resp.json({
- streamId: stream.id,
- streamUrl: stream.url,
- status: 'streaming'
- });
-}
-```
-
-### Manual Stream Writing
-
-You can write to streams manually for complete control over the data flow. The Stream API provides a simple `write()` method that handles writer management automatically:
-
-```ts
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const stream = await ctx.stream.create('progress-updates', {
- contentType: 'application/json',
- metadata: { type: 'progress-tracking' }
- });
-
- ctx.waitUntil(async () => {
- try {
- // Send progress updates
- const steps = ['Initializing', 'Processing', 'Analyzing', 'Finalizing'];
-
- for (let i = 0; i < steps.length; i++) {
- await stream.write(JSON.stringify({
- step: i + 1,
- total: steps.length,
- message: steps[i],
- progress: ((i + 1) / steps.length) * 100,
- timestamp: new Date().toISOString()
- }) + '\n');
-
- // Simulate work
- await new Promise(resolve => setTimeout(resolve, 1000));
- }
-
- // Track progress with bytesWritten
- ctx.logger.info(`Stream complete: ${stream.bytesWritten} bytes written`);
- } finally {
- await stream.close();
- }
- });
-
- return resp.json({
- streamId: stream.id,
- streamUrl: stream.url
- });
-}
-```
-
-**Writing Patterns**
-
-The Stream API supports two writing patterns:
-
-- **`stream.write()`** - Simplified API that handles writer acquisition and locking automatically. Recommended for most use cases.
-- **`stream.getWriter()`** - Direct access to the underlying WritableStream writer for scenarios requiring precise control over the writer lifecycle (e.g., sharing a single writer across multiple operations or custom error handling).
-
-**Tracking Stream Progress**
-
-The `bytesWritten` property provides real-time visibility into stream progress:
-
-```ts
-await stream.write(chunk1);
-ctx.logger.info(`Progress: ${stream.bytesWritten} bytes`); // e.g., "Progress: 1024 bytes"
-
-await stream.write(chunk2);
-ctx.logger.info(`Progress: ${stream.bytesWritten} bytes`); // e.g., "Progress: 2048 bytes"
-```
-
-### Stream Compression
-
-Stream compression reduces bandwidth usage by automatically applying gzip encoding to outbound data (defaults to disabled):
-
-```ts
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const { dataset } = await req.data.json();
-
- const stream = await ctx.stream.create('dataset-export', {
- contentType: 'application/json',
- compress: true, // Automatic gzip compression
- metadata: {
- type: 'data-export',
- recordCount: String(dataset.length),
- timestamp: String(Date.now())
- }
- });
-
- ctx.waitUntil(async () => {
- try {
- for (const record of dataset) {
- await stream.write(JSON.stringify(record) + '\n');
-
- // Log progress periodically
- if (stream.bytesWritten % 100000 < 1000) {
- ctx.logger.info(`Export progress: ${stream.bytesWritten} bytes written`);
- }
- }
-
- ctx.logger.info(
- `Export complete: ${stream.bytesWritten} bytes (uncompressed), ` +
- `compression: ${stream.compressed ? 'enabled' : 'disabled'}`
- );
- } finally {
- await stream.close();
- }
- });
-
- return resp.json({
- streamUrl: stream.url,
- compressed: stream.compressed,
- totalBytes: stream.bytesWritten
- });
-}
-```
-
-**When to Use Compression**
-
-Enable compression for highly compressible data formats:
-- JSON APIs and structured data streams
-- Text-based logs and documents
-- CSV files and tabular data
-
-The `bytesWritten` property tracks uncompressed bytes, while clients receive gzip-encoded responses that are automatically decompressed by standard HTTP clients.
-
-### Stream as Direct Response
-
-You can return a stream directly from your agent handler, which will automatically redirect clients to the stream URL:
-
-```ts
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const { prompt } = await req.data.json();
-
- const stream = await ctx.stream.create('direct-stream', {
- contentType: 'text/plain'
- });
-
- ctx.waitUntil(async () => {
- const { textStream } = streamText({
- model: openai('gpt-4o'),
- prompt
- });
- await textStream.pipeTo(stream);
- });
-
- // Return the stream directly - client gets redirected to stream URL
- return stream;
-}
-```
-
-### Benefits of Low-Level Stream Control
-
-- **Non-blocking**: Stream creation returns immediately, allowing instant responses
-- **Background Processing**: Use `ctx.waitUntil()` to handle data streaming without blocking
-- **Rich Metadata**: Associate custom metadata with streams for tracking and debugging
-- **Direct Access**: Clients can access streams via direct URLs
-- **Flexible Content Types**: Support any content type (text, JSON, binary, etc.)
-- **Direct Writing**: Use `stream.write()` for simple data writing without manual lock management
-- **Progress Monitoring**: Track bytes written in real-time with `stream.bytesWritten`
-- **Automatic Compression**: Enable optional compression to reduce bandwidth for compressible content
-
-## Managing Streams
-
-Beyond creating streams, you can list and delete streams to manage your stream lifecycle.
-
-### Listing Streams
-
-Use `context.stream.list()` to search and filter through your streams:
-
-```typescript
-const handler: AgentHandler = async (req, resp, ctx) => {
- // List all streams
- const allStreams = await ctx.stream.list();
- console.log(`Total streams: ${allStreams.total}`);
-
- // Filter by name
- const llmStreams = await ctx.stream.list({
- name: 'llm-response'
- });
-
- // Filter by metadata
- const userStreams = await ctx.stream.list({
- metadata: { userId: 'user-123', sessionId: 'session-456' }
- });
-
- // Paginate results
- const page1 = await ctx.stream.list({ limit: 10, offset: 0 });
- const page2 = await ctx.stream.list({ limit: 10, offset: 10 });
-
- return resp.json({ streams: userStreams.streams });
-}
-```
-
-### Deleting Streams
-
-Clean up streams when they're no longer needed:
-
-```typescript
-const handler: AgentHandler = async (req, resp, ctx) => {
- const { streamId } = await req.data.json();
-
- try {
- await ctx.stream.delete(streamId);
- return resp.json({ success: true });
- } catch (error) {
- if (error.message.includes('not found')) {
- return resp.json({ error: 'Stream not found' }, { status: 404 });
- }
- throw error;
- }
-}
-```
-
-### Complete Stream Lifecycle
-
-Here's a complete example showing stream creation, listing, and cleanup:
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const handler: AgentHandler = async (req, resp, ctx) => {
- const { prompt, userId } = await req.data.json();
-
- // Create a new stream with metadata
- const stream = await ctx.stream.create('llm-response', {
- contentType: 'text/plain',
- metadata: {
- userId,
- sessionId: ctx.sessionId,
- timestamp: Date.now(),
- type: 'llm-generation'
- }
- });
-
- // Stream LLM response in the background
- ctx.waitUntil(async () => {
- const { textStream } = streamText({
- model: openai('gpt-4o'),
- prompt
- });
- await textStream.pipeTo(stream);
- });
-
- // List all streams for this user
- const userStreams = await ctx.stream.list({
- metadata: { userId }
- });
-
- // Clean up old streams (older than 24 hours)
- const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
- ctx.waitUntil(async () => {
- for (const oldStream of userStreams.streams) {
- const timestamp = Number(oldStream.metadata?.timestamp);
- if (timestamp && timestamp < oneDayAgo) {
- await ctx.stream.delete(oldStream.id);
- ctx.logger.info(`Deleted old stream: ${oldStream.id}`);
- }
- }
- });
-
- return resp.json({
- streamId: stream.id,
- streamUrl: stream.url,
- totalStreams: userStreams.total
- });
-}
-```
-
----
-
-## Further Reading
-
-- Blog Post: [Agents just want to have streams](https://agentuity.com/blog/agent-streaming)
-- SDK Examples: [JavaScript](/SDKs/javascript/examples#openai-streaming-example) · [Python](/SDKs/python/examples#streaming-responses-from-openai)
-- Streaming Video Demo: [Watch on YouTube](https://youtu.be/HN_ElBfsWtE)
-
diff --git a/content/Guides/agent-telemetry.mdx b/content/Guides/agent-telemetry.mdx
deleted file mode 100644
index 86b8e3f2..00000000
--- a/content/Guides/agent-telemetry.mdx
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: Agent Telemetry
-description: How to use telemetry in your agents
----
-
-## What is Agent Telemetry?
-
-Agent telemetry provides performance metrics and execution traces for your agents through OpenTelemetry integration. Monitor how your agents perform, where time is spent, and identify optimization opportunities.
-
-## Production Sessions and Analytics
-
-The Agentuity platform provides comprehensive telemetry for deployed agents through the Sessions interface. All production agent executions are automatically tracked and persist for analysis and troubleshooting.
-
-
-
-### Session Overview
-
-The Sessions dashboard displays:
-
-- **Status indicators**: Success, failure, and execution state
-- **Agent identification**: Which agent handled each request
-- **Performance metrics**: Duration and cost per session
-- **Timeline data**: When sessions occurred with precise timestamps
-
-### Detailed Session Analysis
-
-Each session provides detailed execution traces with comprehensive telemetry data:
-
-
-
-## Understanding Spans
-
-Telemetry data is organized into spans representing units of work. The timeline visualization uses color coding:
-
-- **Root** (Black): Overall agent execution
-- **API/HTTP** (Teal): External service calls
-- **AI Services** (Purple): Language model interactions
-- **Vector** (Light Blue): Vector database operations
-- **KV** (Orange): Key-value storage operations
-- **LLM** (Pink): LLM-specific operations
-- **Other** (Gray): Miscellaneous operations
-
-Each span includes:
-- Start and end timestamps
-- Duration in milliseconds
-- Relevant attributes (model used, tokens consumed, etc.)
-- Parent-child relationships
-
-### Viewing Span Details
-
-Click on any span in the timeline to view detailed information in the sidebar:
-
-
-
-## Performance Analysis
-
-Use telemetry to identify bottlenecks:
-
-1. **Long-running spans**: Operations taking excessive time
-2. **Sequential operations**: Tasks that could run in parallel
-3. **Repeated calls**: Opportunities for caching
-4. **Token usage patterns**: Optimize prompt efficiency
-
-## OpenTelemetry Integration
-
-Agentuity uses OpenTelemetry standards, enabling:
-- Export to external observability platforms
-- Custom span creation for business logic
-- Correlation across distributed systems
-- Industry-standard tooling compatibility
-
-For implementation details and code examples, see our SDK documentation for [JavaScript](/SDKs/javascript) and [Python](/SDKs/python).
\ No newline at end of file
diff --git a/content/Guides/agent-tracing.mdx b/content/Guides/agent-tracing.mdx
deleted file mode 100644
index 5b42ff62..00000000
--- a/content/Guides/agent-tracing.mdx
+++ /dev/null
@@ -1,291 +0,0 @@
----
-title: Agent Tracing
-description: Understanding how to use tracing in your agents
----
-
-## Overview
-
-Agent tracing provides deep visibility into your agent's execution flow, performance, and behavior using OpenTelemetry. This enables debugging, performance monitoring, and understanding complex agent workflows.
-
-**Key benefits:**
-- **Track execution flow** through agent operations
-- **Identify performance bottlenecks** and slow operations
-- **Debug errors** with detailed context and stack traces
-- **Monitor agent performance** and resource usage
-- Understand complex **multi-agent interactions**
-
-## OpenTelemetry Integration
-
-Agentuity integrates with OpenTelemetry, the industry-standard observability framework. The SDK provides access to tracing capabilities through the `context.tracer` object, allowing you to create spans that track your agent's operations.
-
-Traces consist of spans that represent individual operations. Spans can be nested to show parent-child relationships and include attributes, events, and timing information.
-
-## Basic Tracing
-
-### Creating Spans
-
-Create spans to track specific operations in your agent:
-
- {
- return context.tracer.startActiveSpan('process-request', async (span) => {
- try {
- // Add attributes to identify the span
- span.setAttribute('userId', '123');
- span.setAttribute('requestType', 'data-processing');
-
- // Perform work
- const result = await processData();
-
- // Add events to mark important moments
- span.addEvent('data-processed', {
- itemCount: result.length
- });
-
- return response.json(result);
- } catch (error) {
- // Record errors in the span
- span.recordException(error);
- span.setStatus({ code: SpanStatusCode.ERROR });
- throw error;
- }
- // Span automatically ends when async callback completes
- });
-};
-
-export default handler;`} py={`from agentuity import AgentRequest, AgentResponse, AgentContext
-from opentelemetry.trace.status import Status, StatusCode
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- with context.tracer.start_as_current_span("process-request") as span:
- try:
- # Add attributes to identify the span
- span.set_attribute("userId", "123")
- span.set_attribute("requestType", "data-processing")
-
- # Perform work
- result = await process_data()
-
- # Add events to mark important moments
- span.add_event("data-processed", {
- "itemCount": len(result)
- })
-
- return response.json(result)
- except Exception as error:
- # Record errors in the span
- span.record_exception(error)
- span.set_status(Status(StatusCode.ERROR))
- context.logger.error(f"Error processing: {str(error)}")
- raise error`}/>
-
-### Span Attributes and Events
-
-**Attributes** provide metadata about the span (user IDs, operation types, parameters)
-**Events** mark specific moments in time with additional context (milestones, state changes)
-
-## Language-Specific Patterns
-
-OpenTelemetry uses different patterns per language, but both achieve the same tracing results.
-
-**JavaScript/TypeScript** uses a callback-based pattern:
-```typescript
-context.tracer.startActiveSpan('span-name', async (span) => {
- // Automatic span lifecycle management through callback scope
- const result = await someAsyncWork();
- return result;
-});
-```
-
-**Python** uses a context manager pattern:
-```python
-with context.tracer.start_as_current_span("span-name") as span:
- # Automatic span lifecycle management through with statement
- result = await some_async_work()
- return result
-```
-
-### Working with Async Operations
-
-In Python, **span creation is synchronous, but the work inside can be async**:
-
-- The `with context.tracer.start_as_current_span()` line itself is synchronous
-- Inside the `with` block, you can have async operations (`await`)
-- The span automatically closes when the `with` block exits
-- This is different from `async with` (which would be for async context managers)
-
-Here's how to properly handle async operations within spans:
-
-```python
-from agentuity import AgentRequest, AgentResponse, AgentContext
-from opentelemetry.trace.status import Status, StatusCode
-
-async def process_user_data(request: AgentRequest, response: AgentResponse, context: AgentContext):
- with context.tracer.start_as_current_span("process-user-data") as span:
- try:
- # Set attributes using semantic conventions
- span.set_attribute("enduser.id", "123")
- span.set_attribute("operation.type", "data-processing")
-
- # Async operations work perfectly inside the sync span
- user_data = await fetch_user_data()
- processed_result = await process_data(user_data)
-
- # Add events to mark progress
- span.add_event("data-processed", {
- "itemCount": len(processed_result),
- "processingTimeMs": 150
- })
-
- return response.json(processed_result)
- except Exception as error:
- # Enhanced error handling
- span.record_exception(error)
- span.set_status(Status(StatusCode.ERROR, str(error)))
- context.logger.error(f"Error processing data: {error}")
- raise
-```
-
-## Advanced Tracing Patterns
-
-### Nested Spans
-
-Create nested spans to trace complex operations with multiple steps:
-
- {
- return context.tracer.startActiveSpan('agent-request', async (parentSpan) => {
- try {
- parentSpan.setAttribute('trigger', request.trigger);
- const data = await request.data.json();
-
- // Create child span for data processing
- return await context.tracer.startActiveSpan('process-data', async (childSpan) => {
- try {
- childSpan.addEvent('processing-started', {
- timestamp: Date.now()
- });
-
- const result = await complexDataProcessing(data);
-
- childSpan.addEvent('processing-completed', {
- timestamp: Date.now(),
- resultSize: JSON.stringify(result).length
- });
-
- childSpan.setStatus({ code: SpanStatusCode.OK });
- return response.json(result);
- } catch (error) {
- childSpan.recordException(error);
- childSpan.setStatus({
- code: SpanStatusCode.ERROR,
- message: error.message
- });
- throw error;
- }
- // Span automatically ends when async callback completes
- });
- } catch (error) {
- parentSpan.recordException(error);
- parentSpan.setStatus({
- code: SpanStatusCode.ERROR,
- message: error.message
- });
-
- context.logger.error('Request failed', error);
- return response.json({
- error: 'Request failed',
- message: error.message
- });
- }
- // Span automatically ends when async callback completes
- });
-};
-
-export default handler;`} py={`import time
-from agentuity import AgentRequest, AgentResponse, AgentContext
-from opentelemetry.trace.status import Status, StatusCode
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- with context.tracer.start_as_current_span("agent-request") as parent_span:
- try:
- parent_span.set_attribute("trigger", request.trigger())
- data = await request.data.json()
-
- # Create child span for data processing
- with context.tracer.start_as_current_span("process-data") as child_span:
- try:
- child_span.add_event("processing-started", {
- "timestamp": time.time()
- })
-
- result = await complex_data_processing(data)
-
- child_span.add_event("processing-completed", {
- "timestamp": time.time(),
- "resultSize": len(str(result))
- })
-
- child_span.set_status(Status(StatusCode.OK))
- return response.json(result)
- except Exception as error:
- child_span.record_exception(error)
- child_span.set_status(Status(StatusCode.ERROR))
- raise error
- except Exception as error:
- parent_span.record_exception(error)
- parent_span.set_status(Status(StatusCode.ERROR))
-
- context.logger.error(f"Request failed: {str(error)}")
- return response.json({
- "error": "Request failed",
- "message": str(error)
- })`}/>
-
-## Best Practices
-
-### When to Use Tracing
-- **Complex operations**: Multi-step processes that could fail at various points
-- **Performance monitoring**: Operations that might have performance issues
-- **External calls**: API calls, database queries, or agent-to-agent communication
-- **Error debugging**: Operations where you need detailed error context
-
-### Optimization Tips
-- **Meaningful span names**: Use descriptive names that indicate the operation
-- **Relevant attributes**: Include contextual information like user IDs, operation types
-- **Strategic events**: Mark important milestones, not every small step
-- **Error handling**: Always record exceptions and set appropriate status codes
-- **Resource cleanup**: Ensure spans are properly ended (automatic in most cases)
-
-### Common Attributes
-- `userId`: Identify which user triggered the operation
-- `requestId`: Link related operations across agents
-- `operationType`: Categorize different types of operations
-- `resourceId`: Track operations on specific resources
-
-## Integration with Agent Operations
-
-Tracing works seamlessly with other Agentuity features:
-
-- **Storage operations**: Trace vector searches, key-value operations
-- **Agent communication**: Track calls between agents
-- **External integrations**: Monitor API calls and third-party services
-- **Streaming responses**: Trace streaming operations and chunks
-
-## Other Considerations
-
-- **Semantic conventions**: Use standardized attribute names like `enduser.id`, `operation.type` for better consistency across your traces
-- **Enhanced error handling**: The `Status(StatusCode.ERROR, message)` pattern provides more detailed error information than basic status codes
-- **Performance optimization**: Be mindful of span overhead in high-frequency operations. Focus tracing on meaningful operations rather than every small function call
-
-## Viewing Traces
-
-You can view traces in the session timeline visualization:
-
-
-
-For more details on observability, see [Agent Logging](/Guides/agent-logging) for application logs and [Agent Telemetry](/Guides/agent-telemetry) for metrics and monitoring.
diff --git a/content/Guides/ai-gateway.mdx b/content/Guides/ai-gateway.mdx
deleted file mode 100644
index 8d1cbbb8..00000000
--- a/content/Guides/ai-gateway.mdx
+++ /dev/null
@@ -1,131 +0,0 @@
----
-title: Using AI Gateway
-description: Using the AI Gateway in your Agents
----
-
-## What is the AI Gateway?
-
-The AI Gateway provides seamless access to multiple AI providers through a single interface. It automatically routes your LLM requests, tracks usage and costs, and eliminates the need to manage individual API keys for each provider.
-
-## Supported Providers
-
-The AI Gateway supports the following providers out of the box:
-
-- **OpenAI**
-- **Anthropic**
-- **Google**
-- **Cohere**
-- **DeepSeek**
-- **Grok**
-- **Groq**
-- **Mistral**
-- **Perplexity**
-
-
-[Purchase credits and manage billing](https://app.agentuity.com/billing) in the Cloud Console.
-
-
-## How It Works
-
-### Automatic Detection
-
-When you use supported LLM SDKs without providing API keys, Agentuity automatically routes requests through the AI Gateway:
-
-
-
-### Using Your Own API Keys
-
-To bypass the AI Gateway and use your own API keys, simply provide them:
-
-
-
-## Cost Tracking and Monitoring
-
-### Session Overview
-
-Navigate to **Services > AI Gateway** in the Cloud Console to view:
-
-- **Agent**: Which agent made the request
-- **Provider**: AI provider used (OpenAI, Anthropic, etc.)
-- **Model**: Specific model used
-- **LLM Cost**: Cost per request
-- **Timestamp**: When the request was made
-
-
-
-### Detailed Session Analysis
-
-Click any session to view comprehensive details:
-
-
-
-- **Token usage**: Input and output token counts
-- **Cost breakdown**: Per-token pricing and total cost
-- **Request metadata**: Model, provider, and performance metrics
-- **Trace information**: Full span details for debugging
-
-## Filtering and Search
-
-Use the filter options to analyze your AI usage:
-
-- **By Provider**: Compare costs across different AI providers
-- **By Model**: Track usage of specific models
-- **By Agent**: See which agents consume the most tokens
-- **By Time Range**: Analyze usage patterns over time
-
-
-
-## Framework Integration
-
-AI Gateway works seamlessly with popular AI frameworks:
-
-### JavaScript
-- OpenAI SDK
-- Anthropic SDK
-- Langchain.js
-- Vercel AI SDK
-
-### Python
-- OpenAI SDK
-- Anthropic SDK
-- LangChain
-- LiteLLM
-
-The Agentuity CLI provides templates with these frameworks already configured. Since these frameworks use the underlying LLM SDKs, requests are routed through the AI Gateway when no API keys are provided.
-
-## Telemetry Integration
-
-AI Gateway spans appear in your [agent telemetry](/Guides/agent-telemetry) with:
-- Request duration
-- Token counts
-- Cost information
-- Provider details
-
-This integration enables you to track costs, monitor usage patterns, and understand the full performance impact of AI calls in your agent workflows.
\ No newline at end of file
diff --git a/content/Guides/devmode.mdx b/content/Guides/devmode.mdx
deleted file mode 100644
index 5c45b890..00000000
--- a/content/Guides/devmode.mdx
+++ /dev/null
@@ -1,203 +0,0 @@
----
-title: Agent DevMode
-description: Developing agents locally with DevMode
----
-
-## What is DevMode?
-
-DevMode is Agentuity's local development environment that lets you test and debug your agents before deploying them to the cloud. It provides the exact same interface and capabilities you'll have in production.
-
-**Key benefits:**
-- **Instant feedback** on agent behavior and responses
-- **Complete observability** with real-time logs, sessions, and detailed traces
-- **Cost visibility** to monitor token usage and LLM costs
-- **Performance insights** to identify potential bottlenecks
-
-## Starting DevMode
-
-Run the following command in your project directory:
-
-
-Agentuity DevMode
-
-DevMode https://app.agentuity.com/devmode/[agent-id]
-Port http://127.0.0.1:3500
-Public https://dev-[hash].agentuity.run/
-
-[INFO] Loading config from /path/to/your/project/agentuity/config.json
-[INFO] Starting server on port 3500
- Listening on http://127.0.0.1:3500 =======>
-(Press Ctrl+C to exit)
-[INFO] 🚀 DevMode ready
-
-
-DevMode provides:
-- **Local development server** on port 3500 (configurable)
-- **Web interface** for testing and monitoring at the provided URL
-- **Public URL** for external access while the server is running
-
-## The DevMode Interface
-
-### CLI Input Section
-
-The CLI Input section is where you test your agents with various input types and scenarios. This interface is powered by your agent's `welcome()` function configuration.
-
-
-
-**Input Types Available:**
-- **JSON**: Structured data for API-like interactions
-- **HTML**: Rich content and web-based inputs
-- **Markdown**: Documentation and formatted text
-- **Text**: Plain text for conversational interfaces
-
-**Key Features:**
-- **Agent Selection**: Choose which agent to test from the dropdown
-- **Pre-configured Prompts**: Sample inputs defined in the `welcome()` function
-- **Custom Inputs**: Write your own test scenarios
-- **Run Button**: Execute tests instantly and see results
-
-### Configuring the Welcome Function
-
-Your agent's `welcome()` function defines the test scenarios available in DevMode:
-
- {
- return {
- "welcome": "Welcome to your agent! Send a message to get started.",
- "prompts": [
- {
- "data": "Hello, how can you help me?",
- "contentType": "text/plain"
- },
- {
- "data": JSON.stringify({"query": "What is AI?", "format": "brief"}),
- "contentType": "application/json"
- },
- {
- "data": "# Research Request\\n\\nPlease analyze current market trends",
- "contentType": "text/markdown"
- },
- {
- "data": "HTML Content Process this HTML document
",
- "contentType": "text/html"
- }
- ]
- };
-};`} py={`def welcome():
- return {
- "welcome": "Welcome to your agent! Send a message to get started.",
- "prompts": [
- {
- "data": "Hello, how can you help me?",
- "contentType": "text/plain"
- },
- {
- "data": '{"query": "What is AI?", "format": "brief"}',
- "contentType": "application/json"
- },
- {
- "data": "# Research Request\\n\\nPlease analyze current market trends",
- "contentType": "text/markdown"
- },
- {
- "data": "HTML Content Process this HTML document
",
- "contentType": "text/html"
- }
- ]
- }
-`} />
-
-These prompts appear as clickable examples in the DevMode interface, making it easy to test common scenarios and edge cases.
-
-## Monitoring and Debugging
-
-### Sessions Tab
-
-Track your test runs with details on status, duration, costs, and performance metrics.
-
-
-
-
-DevMode sessions are temporary and cleared when you exit DevMode. For persistent production analytics, see [Agent Telemetry](/Guides/agent-telemetry).
-
-
-### Logs Tab
-
-Watch your agent's execution logs in real-time with structured timestamps, severity levels, and debug information.
-
-
-
-
-DevMode logs are temporary and cleared when you exit DevMode. For persistent production logs, see [Agent Logging](/Guides/agent-logging).
-
-
-## Best Practices
-
-### 1. Design Comprehensive Test Scenarios
-
-Create a robust `welcome()` function that covers various use cases:
-
- {
- return {
- "welcome": "Welcome to your agent! Send a message to get started.",
- "prompts": [
- // Happy path
- {
- "data": "Normal user request",
- "contentType": "text/plain"
- },
- // Edge cases
- {
- "data": "",
- "contentType": "text/plain"
- },
- // Structured data
- {
- "data": JSON.stringify({"query": "structured request"}),
- "contentType": "application/json"
- },
- // Complex scenarios
- {
- "data": "Multi-step task with specific requirements",
- "contentType": "text/plain"
- }
- ]
- };
-};`} py={`def welcome():
- return {
- "welcome": "Welcome to your agent! Send a message to get started.",
- "prompts": [
- # Happy path
- {
- "data": "Normal user request",
- "contentType": "text/plain"
- },
- # Edge cases
- {
- "data": "",
- "contentType": "text/plain"
- },
- # Structured data
- {
- "data": '{"query": "structured request"}',
- "contentType": "application/json"
- },
- # Complex scenarios
- {
- "data": "Multi-step task with specific requirements",
- "contentType": "text/plain"
- }
- ]
- }
-`} />
-
-### 2. Test Thoroughly Before Production
-
-- **Monitor costs** during development to avoid surprises
-- **Check performance** using the session timeline views
-- **Validate edge cases** with your comprehensive test scenarios
-
-### 3. Remember DevMode Limitations
-
-- **Sessions and logs are temporary** - they won't persist after stopping DevMode
-- **Use production deployments** for persistent monitoring and analytics
-- **Test with realistic data** to ensure production readiness
diff --git a/content/Guides/key-value.mdx b/content/Guides/key-value.mdx
deleted file mode 100644
index ed8ea58d..00000000
--- a/content/Guides/key-value.mdx
+++ /dev/null
@@ -1,225 +0,0 @@
----
-title: Using Key Value
-description: Using Key Value storage in your Agents
----
-
-## When to Use Key-Value Storage
-
-Key-value storage is your go-to solution for fast, ephemeral data that agents need to access quickly. Think of it as your agent's short-term memory — perfect for session state, configuration, caching, and temporary data.
-
-Choose the right storage for your use case:
-
-- **Key-Value**: Fast lookups, simple data, temporary state
-- **[Vector Storage](/Cloud/vector-memory)**: Semantic search, embeddings, similarity matching
-- **[Object Storage](/Cloud/object-storage)**: Large files, media, backups
-
-## Common Use Cases
-
-- **Session Management**: Store user sessions, authentication tokens, and temporary state between agent interactions
-- **Configuration Storage**: Keep agent-specific settings, feature flags, and runtime configuration that can be updated without redeployment
-- **Caching**: Cache expensive computation results, API responses, or frequently accessed data to improve agent performance
-- **Inter-Agent Communication**: Share state between agents working together on complex workflows
-- **Rate Limiting**: Track API usage, request counts, and implement throttling mechanisms
-
-## Creating Key-Value Storage
-
-You can create key-value storage either through the Cloud Console or programmatically in your agent code.
-
-### Via Cloud Console
-
-Navigate to **Services > Key Value** and click **Create Storage**. Choose a descriptive name that reflects the storage purpose (e.g., `user-sessions`, `agent-config`, `api-cache`).
-
-
-
-### Via SDK
-
-Both JavaScript and Python SDKs automatically create key-value storage when you first access it:
-
- {
- // Buckets are auto-created if they don't exist
- await ctx.kv.set('user-sessions', 'user-123', {
- lastSeen: new Date().toISOString(),
- preferences: { theme: 'dark' }
- });
-
- return resp.json({ message: 'Session stored' });
-};
-
-export default handler;`} py={`# Python
-from agentuity import AgentRequest, AgentResponse, AgentContext
-from datetime import datetime
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- # Storage is created automatically on first use
- await context.kv.set("user-sessions", "user-123", {
- "lastSeen": datetime.now().isoformat(),
- "preferences": {"theme": "dark"}
- })
-
- return response.json({"message": "Session stored"})
-`} />
-
-## Working with Key-Value Storage
-
-The key-value API provides three core operations: `get`, `set`, and `delete`. All operations are asynchronous and support various data types.
-
-The first parameter in all operations is the storage bucket name (also called "name" or "namespace"). Buckets are automatically created when you first use them.
-
-### Storing Data
-
-Store strings, objects, or binary data. Keys persist indefinitely by default, or you can set a TTL (time-to-live) for automatic expiration:
-
-
-
-### Retrieving Data
-
-Retrieve stored values with automatic deserialization:
-
-
-
-### Deleting Data
-
-Remove keys when they're no longer needed:
-
-
-
-## Best Practices
-
-### Key Naming Conventions
-
-Use hierarchical, descriptive keys to organize your data:
-- `user:{userId}:preferences`
-- `session:{sessionId}:data`
-- `cache:api:{endpoint}:{params}`
-
-### Error Handling
-
-Always handle potential storage errors gracefully:
-
-
-
-### TTL Strategy
-
-Keys persist indefinitely by default unless you specify a TTL (time-to-live) value. When you do specify a TTL, the minimum allowed value is 60 seconds.
-
-Use TTL for temporary data to prevent storage bloat:
-- **Session data**: 24-48 hours
-- **API cache**: 5-60 minutes
-- **Rate-limiting counters**: Until period reset
-- **Permanent config**: No TTL (keys persist forever)
-
-### Data Size Considerations
-
-Key-value storage is optimized for small to medium-sized values. For large files or documents, consider using [Object Storage](/Cloud/object-storage) instead.
-
-## Monitoring Usage
-
-Track your key-value storage usage through the Cloud Console:
-
-1. Navigate to **Services > Key Value**
-2. View storage size and record count for each instance
-3. Click on an instance to browse stored keys and values
-4. Monitor [agent telemetry](/Guides/agent-telemetry) for KV operation performance
-
-
-
-For more complex data relationships or query needs, consider combining storage types or using external databases through your agent.
-
-## Storage Types Overview
-
-VIDEO
\ No newline at end of file
diff --git a/content/Guides/meta.json b/content/Guides/meta.json
deleted file mode 100644
index bcdd7314..00000000
--- a/content/Guides/meta.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "title": "Guides",
- "pages": [
- "what-is-an-agent",
- "agent-native-cloud",
- "agent-engineering",
- "devmode",
- "agent-logging",
- "agent-telemetry",
- "...",
- "ai-gateway",
- "key-value",
- "vector-db",
- "object-storage",
- "security"
- ]
-}
diff --git a/content/Guides/object-storage.mdx b/content/Guides/object-storage.mdx
deleted file mode 100644
index f4639c1e..00000000
--- a/content/Guides/object-storage.mdx
+++ /dev/null
@@ -1,422 +0,0 @@
----
-title: Using Object Storage
-description: Using Object Storage for files and media in your Agents
----
-
-## When to Use Object Storage
-
-Object storage is your solution for storing files, media, and large unstructured data that agents need to manage. Think of it as your agent's file system — perfect for documents, images, videos, backups, and any binary content.
-
-Choose the right storage for your use case:
-
-- **Object Storage**: Files, media, documents, backups
-- **[Key-Value Storage](/Cloud/key-value-memory)**: Fast lookups, session data, configuration
-- **[Vector Storage](/Cloud/vector-memory)**: Semantic search, embeddings, AI context
-
-## Common Use Cases
-
-- **File Management**: Store user uploads, generated documents, and processed files
-- **Media Storage**: Keep images, videos, audio files, and other media assets
-- **Document Processing**: Store PDFs, spreadsheets, and documents for agent processing
-- **Backup and Archive**: Maintain backups of agent-generated content or historical data
-- **Static Asset Serving**: Host files that can be accessed via public URLs
-- **Data Export**: Store generated reports, exports, and downloadable content
-
-## Creating Object Storage
-
-You can create object storage buckets either through the Cloud Console or programmatically in your agent code.
-
-### Via Cloud Console
-
-Navigate to **Services > Object Store** and click **Create Storage**. Choose a descriptive bucket name that reflects its purpose (e.g., `user-uploads`, `processed-documents`, `media-assets`).
-
-
-
-### Via SDK
-
-Both JavaScript and Python SDKs automatically create buckets when you first access them:
-
- {
- // Bucket is created automatically on first use
- const imageData = Buffer.from(await request.data.binary());
-
- // Auto-detect content type (simplest approach)
- await context.objectstore.put('user-uploads', 'profile-123.jpg', imageData)
-
- return response.json({ message: 'Image uploaded successfully' });
-};
-
-export default handler;`} py={`# Python
-from agentuity import AgentRequest, AgentResponse, AgentContext
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- # Bucket is created automatically on first use
- image_data = await request.data.binary()
-
- # Auto-detect content type (simplest approach)
- await context.objectstore.put("user-uploads", "profile-123.jpg", image_data)
-
- return response.json({"message": "Image uploaded successfully"})
-`} />
-
-## Working with Object Storage
-
-The object storage API provides four core operations: `get`, `put`, `delete`, and `createPublicURL`. All operations are asynchronous and support various content types.
-
-### Storing Objects
-
-Object storage supports two approaches for storing files:
-
-1. **Automatic content type detection** (recommended for most cases) - The SDK detects the content type from the data
-2. **Explicit parameters** - Specify content type, metadata, and other options manually
-
-
-
-### Retrieving Objects
-
-Retrieve stored objects with automatic format handling:
-
-
-
-### Generating Public URLs
-
-Create time-limited public URLs for direct access to objects:
-
-
-
-### Deleting Objects
-
-Remove objects when they're no longer needed:
-
-
-
-## Best Practices
-
-### Bucket Organization
-
-Structure your buckets by purpose and access patterns:
-- `user-uploads`: User-submitted content
-- `processed-output`: Agent-generated results
-- `public-assets`: Files meant for public access
-- `temp-storage`: Short-lived processing files
-
-### Key Naming Conventions
-
-Use hierarchical paths for better organization:
-- `users/{userId}/profile.jpg`
-- `documents/{year}/{month}/report-{id}.pdf`
-- `exports/{timestamp}/data.csv`
-
-### Content Type Management
-
-Always set appropriate content types for better browser handling:
-
-
-
-### Public URL Security
-
-Use appropriate expiration times for public URLs:
-- **Temporary downloads**: 5-15 minutes
-- **Shared documents**: 1-24 hours
-- **Never**: Create permanent public URLs for sensitive data
-
-### Error Handling
-
-Handle storage operations gracefully:
-
-
-
-## File Processing Patterns
-
-### Upload Handler
-
-Create a robust file upload handler:
-
- {
- const contentType = request.headers.get('content-type') || '';
- const fileName = request.headers.get('x-filename') || 'upload';
-
- // Store the uploaded file
- const fileData = await request.data.binary();
- const key = \`uploads/\${Date.now()}-\${fileName}\`;
-
- await context.objectstore.put('user-files', key, fileData, {
- contentType,
- metadata: {
- 'original-name': fileName,
- 'upload-time': new Date().toISOString()
- }
- });
-
- // Generate access URL
- const url = await context.objectstore.createPublicURL(
- 'user-files',
- key,
- 3600000
- );
-
- return response.json({
- message: 'File uploaded successfully',
- key,
- url
- });
-};`} py={`async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- content_type = request.headers.get("content-type", "")
- file_name = request.headers.get("x-filename", "upload")
-
- # Store the uploaded file
- file_data = await request.data.binary()
- key = f"uploads/{int(time.time())}-{file_name}"
-
- # Using explicit params for metadata
- from agentuity.server.objectstore import ObjectStorePutParams
-
- params = ObjectStorePutParams(
- content_type=content_type,
- metadata={
- "original-name": file_name,
- "upload-time": datetime.now().isoformat()
- }
- )
- await context.objectstore.put("user-files", key, file_data, params)
-
- # Generate access URL
- url = await context.objectstore.create_public_url(
- "user-files",
- key,
- 3600000
- )
-
- return response.json({
- "message": "File uploaded successfully",
- "key": key,
- "url": url
- })`} />
-
-## Monitoring Usage
-
-Track your object storage usage through the Cloud Console:
-
-1. Navigate to **Services > Object Store**
-2. View storage size and object count for each bucket
-3. Monitor provider information and creation dates
-4. Use [agent telemetry](/Guides/agent-telemetry) to track storage operations
-
-For structured data with complex queries, consider using object storage to store data exports while maintaining indexes in key-value or vector storage.
-
-## Storage Types Overview
-
-VIDEO
\ No newline at end of file
diff --git a/content/Guides/vector-db.mdx b/content/Guides/vector-db.mdx
deleted file mode 100644
index 4ff49d1f..00000000
--- a/content/Guides/vector-db.mdx
+++ /dev/null
@@ -1,603 +0,0 @@
----
-title: Using Vector DB
-description: Using the Vector DB for search and retrieval
----
-
-## When to Use Vector Storage
-
-Vector storage enables semantic search for your agents, allowing them to find information by meaning rather than keywords. Ideal for knowledge bases, RAG systems, and persistent agent memory.
-
-Choose the right storage for your use case:
-
-- **Vector Storage**: Semantic search, embeddings, similarity matching
-- **[Key-Value Storage](/Cloud/key-value-memory)**: Fast lookups, simple data, temporary state
-- **[Object Storage](/Cloud/object-storage)**: Large files, media, backups
-
-## Understanding Vector Storage
-
-Vector storage works by converting text into high-dimensional numerical representations (embeddings) that capture semantic meaning. When you search, the system finds documents with similar meanings rather than just keyword matches.
-
-**Key use cases:**
-- Knowledge bases and documentation search
-- Long-term memory across agent sessions
-- RAG systems combining retrieval with AI generation
-- Semantic similarity search
-
-## Managing Vector Instances
-
-### Viewing Vector Storage in the Cloud Console
-
-Navigate to **Services > Vector** in the Agentuity Cloud Console to view all your vector storage instances. The interface shows:
-
-- **Database Name**: The identifier for your vector storage
-- **Projects**: Which projects are using this storage
-- **Agents**: Which agents have access
-- **Size**: Storage utilization
-
-You can filter instances by name using the search box and create new vector storage instances with the **Create Storage** button.
-
-
-
-### Creating Vector Storage
-
-You can create vector storage either through the Cloud Console or programmatically in your agent code.
-
-#### Via Cloud Console
-
-Navigate to **Services > Vector** and click **Create Storage**. Choose a descriptive name that reflects the storage purpose (e.g., `knowledge-base`, `agent-memory`, `product-catalog`).
-
-#### Via SDK
-
-Vector storage is created automatically when your agent first calls `context.vector.upsert()` with an instance name:
-
-## Vector Storage API
-
-For complete API documentation, see:
-- [JavaScript SDK Vector API Reference](/SDKs/javascript/api-reference#vector-storage)
-- [Python SDK Vector API Reference](/SDKs/python/api-reference#vector-storage)
-
-### Upserting Documents
-
-The `upsert` operation inserts new documents or updates existing ones. You can provide either text (which gets automatically converted to embeddings) or pre-computed embeddings.
-
-**SDK Requirements:**
-- **Both SDKs**: Require a `key` field for each document
-
-**Idempotent Behavior:**
-The upsert operation is idempotent - upserting with an existing key updates the existing vector rather than creating a duplicate. The same internal vector ID is reused, ensuring your vector storage remains clean and efficient.
-
-
-
-### Searching Vector Storage
-
-Search operations find semantically similar documents based on a text query. You can control the number of results, similarity threshold, and filter by metadata.
-
- {
- console.log(\`Found: \${result.metadata.source}\`);
- console.log(\`Similarity: \${result.similarity}\`);
-});`} py={`# Python
-# Semantic search with parameters
-results = await context.vector.search(
- "knowledge-base",
- query="What is an agent platform?",
- limit=5,
- similarity=0.7,
- metadata={"category": "platform"}
-)
-
-# Process results
-for result in results:
- print(f"Found: {result.metadata['source']}")
- print(f"Similarity: {result.similarity}")`} />
-
-**Search Parameters:**
-- `query` (required): Text query to search for
-- `limit` (optional): Maximum number of results to return
-- `similarity` (optional): Minimum similarity threshold (0.0-1.0)
-- `metadata` (optional): Filter results by metadata key-value pairs
-
-**Search Results:**
-- **Both SDKs**: Return results with `similarity` field (1.0 = perfect match, 0.0 = no match)
-- **Note**: The JavaScript SDK also returns a `distance` field for backward compatibility; prefer `similarity`
-
-### Retrieving Vectors by Key
-
-The `get` method retrieves a specific vector directly using its key, without performing a similarity search.
-
-
-
-**When to use `get` vs `search`:**
-- Use `get` when you know the exact key (like a database primary key lookup)
-- Use `search` when finding vectors by semantic similarity
-- `get` is faster for single lookups since it doesn't compute similarities
-- `get` returns `null` (JS) / `None` (Python) if the key is not found, but may throw errors for other failures
-
-### Deleting Vectors
-
-Remove specific vectors from storage using their keys.
-
-
-
-## Practical Examples
-
-For more code examples, see:
-- [JavaScript SDK Examples](/SDKs/javascript/examples#vector-storage-usage)
-- [Python SDK Examples](/SDKs/python/examples#vector-storage)
-
-### Building a Simple RAG System
-
-This example demonstrates a complete Retrieval-Augmented Generation (RAG) pattern - searching for relevant context and using it to generate informed responses.
-
- {
- const { question } = await request.data.json();
-
- try {
- // 1. Search for relevant context (top 5 results)
- const searchResults = await context.vector.search('knowledge-base', {
- query: question,
- limit: 5,
- similarity: 0.7
- });
-
- // 2. Handle no results gracefully
- if (searchResults.length === 0) {
- return response.json({
- answer: "I couldn't find relevant information to answer your question.",
- sources: []
- });
- }
-
- // 3. Assemble context from search results (defensive handling)
- const contextTexts = searchResults.map(result =>
- result.metadata?.content ?? result.metadata?.text ?? ''
- );
- const assembledContext = contextTexts.join('\\n\\n');
-
- // 4. Generate response using context (example with AI Gateway)
- const prompt = \`Answer the question based on the following context:
-
-Context: \${assembledContext}
-
-Question: \${question}
-
-Answer:\`;
-
- // Use your preferred LLM here (OpenAI, Anthropic, etc.)
- const llmResponse = await generateAnswer(prompt);
-
- // 5. Return answer with sources
- return response.json({
- answer: llmResponse,
- sources: searchResults.map(r => ({
- id: r.id,
- key: r.key,
- title: r.metadata?.title,
- similarity: r.similarity
- }))
- });
-
- } catch (error) {
- context.logger.error('RAG query failed:', error);
- return response.json({
- error: 'Failed to process your question',
- details: error.message
- });
- }
-};
-
-export default handler;`} py={`# Python - Simple RAG implementation
-from agentuity import AgentRequest, AgentResponse, AgentContext
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- data = await request.data.json()
- question = data.get("question")
-
- try:
- # 1. Search for relevant context (top 5 results)
- search_results = await context.vector.search(
- "knowledge-base",
- query=question,
- limit=5,
- similarity=0.7
- )
-
- # 2. Handle no results gracefully
- if not search_results:
- return response.json({
- "answer": "I couldn't find relevant information to answer your question.",
- "sources": []
- })
-
- # 3. Assemble context from search results
- context_texts = [
- result.metadata.get("content", result.metadata.get("text", ""))
- for result in search_results
- ]
- assembled_context = "\\n\\n".join(context_texts)
-
- # 4. Generate response using context (example with AI Gateway)
- prompt = f"""Answer the question based on the following context:
-
-Context: {assembled_context}
-
-Question: {question}
-
-Answer:"""
-
- # Use your preferred LLM here (OpenAI, Anthropic, etc.)
- llm_response = await generate_answer(prompt)
-
- # 5. Return answer with sources
- return response.json({
- "answer": llm_response,
- "sources": [
- {
- "id": result.id,
- "key": result.key,
- "title": result.metadata.get("title"),
- "similarity": result.similarity
- }
- for result in search_results
- ]
- })
-
- except Exception as e:
- context.logger.error(f"RAG query failed: {e}")
- return response.json({
- "error": "Failed to process your question",
- "details": str(e)
- })`} />
-
-**Key Points:**
-- **Semantic search** finds relevant documents based on meaning, not keywords
-- **Similarity threshold** of 0.7 balances relevance with recall
-- **Context assembly** combines multiple sources for comprehensive answers
-- **Error handling** ensures graceful failures with helpful messages
-- **Source attribution** provides transparency about where information came from
-
-### Semantic Search with Metadata Filtering
-
-This example shows how to combine semantic similarity with metadata filters for precise results - like finding products that match both meaning and business criteria.
-
- {
- const { query, maxPrice, category, inStock } = await request.data.json();
-
- try {
- // Build metadata filters based on criteria
- const metadataFilters = {};
- if (category) metadataFilters.category = category;
- if (inStock !== undefined) metadataFilters.inStock = inStock;
-
- // Search with semantic similarity + metadata filters
- const searchResults = await context.vector.search('products', {
- query,
- limit: 10,
- similarity: 0.65, // Lower threshold for broader results
- metadata: metadataFilters
- });
-
- // Post-process: Apply price filter and sort by relevance
- const filteredResults = searchResults
- .filter(result => !maxPrice || result.metadata.price <= maxPrice)
- .map(result => ({
- ...result.metadata,
- similarity: result.similarity
- }))
- .sort((a, b) => b.similarity - a.similarity);
-
- return response.json({
- query,
- filters: { maxPrice, category, inStock },
- resultCount: filteredResults.length,
- products: filteredResults.slice(0, 5) // Top 5 results
- });
-
- } catch (error) {
- context.logger.error('Product search failed:', error);
- return response.json({
- error: 'Search failed',
- products: []
- });
- }
-};
-
-export default handler;`} py={`# Python - Product search with filters
-from agentuity import AgentRequest, AgentResponse, AgentContext
-
-async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
- data = await request.data.json()
- query = data.get("query")
- max_price = data.get("maxPrice")
- category = data.get("category")
- in_stock = data.get("inStock")
-
- try:
- # Build metadata filters based on criteria
- metadata_filters = {}
- if category:
- metadata_filters["category"] = category
- if in_stock is not None:
- metadata_filters["inStock"] = in_stock
-
- # Search with semantic similarity + metadata filters
- search_results = await context.vector.search(
- "products",
- query=query,
- limit=10,
- similarity=0.65, # Lower threshold for broader results
- metadata=metadata_filters
- )
-
- # Post-process: Apply price filter and sort by relevance
- filtered_results = []
- for result in search_results:
- # Apply price filter
- if max_price and result.metadata.get("price", 0) > max_price:
- continue
-
- product = dict(result.metadata)
- product["similarity"] = result.similarity
- filtered_results.append(product)
-
- # Sort by similarity score
- filtered_results.sort(key=lambda x: x["similarity"], reverse=True)
-
- return response.json({
- "query": query,
- "filters": {"maxPrice": max_price, "category": category, "inStock": in_stock},
- "resultCount": len(filtered_results),
- "products": filtered_results[:5] # Top 5 results
- })
-
- except Exception as e:
- context.logger.error(f"Product search failed: {e}")
- return response.json({
- "error": "Search failed",
- "products": []
- })`} />
-
-**Key Techniques:**
-- **Metadata filters** are applied at the vector search level for efficiency
-- **Post-processing** handles filters that can't be done at search time (like price ranges)
-- **Lower similarity threshold** (0.65) catches more potential matches when using strict filters
-
-## Common Pitfalls & Solutions
-
-### Empty Search Results
-**Problem**: Your search returns empty results even though relevant data exists.
-
-**Solutions**:
-- **Lower the similarity threshold**: Start at 0.5 and increase gradually
-- **Check your metadata filters**: They use exact matching, not fuzzy matching
-- **Verify document format**: Ensure documents were upserted with text content
-
-```javascript
-// Adaptive threshold example
-let results = await context.vector.search('kb', {
- query,
- similarity: 0.8
-});
-
-if (results.length === 0) {
- // Try again with lower threshold
- results = await context.vector.search('kb', {
- query,
- similarity: 0.5
- });
-}
-```
-
-### Duplicate Documents
-**Problem**: Same content appears multiple times in search results.
-
-**Solution**: Vector upsert is idempotent when using the same key:
-- Always use consistent `key` values for your documents
-- Upserting with an existing key updates the vector rather than creating a duplicate
-- The same internal vector ID is reused, keeping your storage clean
-
-### Performance Issues
-**Problem**: Vector operations take too long.
-
-**Solutions**:
-- **Batch operations**: Upsert 100-500 documents at once, not one by one
-- **Limit search results**: Use `limit: 10` instead of retrieving all matches
-- **Optimize metadata**: Keep metadata objects small and focused
-
-### Irrelevant Search Results
-**Problem**: Search returns irrelevant or unexpected documents.
-
-**Solutions**:
-- **Check similarity scores**: Results with similarity < 0.7 may be poor matches
-- **Review metadata filters**: Remember they're AND conditions, not OR
-- **Verify embeddings**: Ensure consistent text preprocessing before upserting
-
-## Best Practices
-
-### Document Structure
-- **Include context in documents**: Store enough context so documents are meaningful when retrieved
-- **Use descriptive metadata**: Include relevant metadata for filtering and identification
-- **Consistent formatting**: Use consistent document formatting for better embeddings
-
-### Search Optimization
-- **Adjust similarity thresholds**: Start with 0.7 and adjust based on result quality
-- **Use metadata filtering**: Combine semantic search with metadata filters for precise results
-- **Limit result sets**: Use appropriate limits to balance performance and relevance
-
-### Performance Considerations
-- **Batch upsert operations**: Use bulk upsert instead of individual calls
-- **Monitor storage usage**: Track vector storage size in the Cloud Console
-- **Consider document chunking**: Break large documents into smaller, focused chunks
-
-## Integration with Agent Memory
-
-Vector storage serves as long-term memory for agents, enabling them to:
-
-- Remember past conversations and context across sessions
-- Access organizational knowledge bases
-- Retrieve relevant examples for few-shot learning
-- Build and maintain agent-specific knowledge repositories
-
-For more information on memory patterns, see the [Key-Value Storage guide](/Guides/key-value) for short-term memory or explore [Agent Communication](/Guides/agent-communication) for sharing knowledge between agents.
-
-## Storage Types Overview
-
-VIDEO
diff --git a/content/Guides/what-is-an-agent.mdx b/content/Guides/what-is-an-agent.mdx
deleted file mode 100644
index 61f2532e..00000000
--- a/content/Guides/what-is-an-agent.mdx
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: What is an Agent?
-description: How we define an Agent
----
-
-> But aren't agents just smart chat bots? 🤖
-
-## Understanding the Difference Between an API and an Agent
-
-APIs (Application Programming Interfaces) are like vending machines — you make a specific request, and they return exactly what you asked for. They're great for performing defined tasks, but you have to know exactly what you want and when to ask.
-
-Agents, on the other hand, are more like smart assistants. Instead of just waiting for instructions, agents can reason, plan, and act independently. They understand goals, adapt to changing conditions, and even decide what to do next based on context — not just what you explicitly told them. They don't just respond to commands; they can proactively get things done.
-
-While APIs are passive and require constant human coordination, agents are active participants in your digital world. They orchestrate actions, learn over time, and collaborate with other systems or agents to solve complex problems — automatically.
-
-## What makes building Agents different?
-
-APIs and agents may both act as intermediaries between users and systems, but the way they operate — and what they enable — are profoundly different.
-
-1. **Passive Interfaces vs. Autonomous Actors**
-
-APIs are passive. They expose a fixed set of functions or data. You must explicitly tell them what to do, how to do it, and when to do it — often in exact, rigid terms. There is no built-in understanding or reasoning.
-
-Agents, by contrast, are autonomous actors. They have the ability to decide how to achieve a goal, not just execute a specific instruction. They can operate continuously, respond to changing context, and coordinate complex tasks — without being told every step.
-
-2. **Determinism vs. Non-Determinism**
-
-Traditional APIs are deterministic: given the same input, they always return the same output. This predictability is useful for low-level tasks but limits flexibility and adaptability.
-
-Agents exhibit non-deterministic behavior. This isn't randomness — it's contextual decision-making. Given a broad prompt or task, an agent might take different actions based on what it knows, what it's learned, or what it perceives in real time. That's what gives agents the power to handle complexity and nuance.
-
-3. **Logic-Driven vs. Intent-Driven**
-
-In API-driven development, every behavior is explicitly programmed. Developers must anticipate every possible use case and encode it in logic. If you want to add a new feature, you need to modify the code. If the user is trying to perform a task that was not anticipated, the API will not be able to handle it.
-
-Agents, especially those built on language models, operate in an intent-driven paradigm. Instead of encoding every rule, you use natural language prompts to guide behavior. The agent interprets these prompts and autonomously figures out what to do and how to do it. This allows you to build flexible systems with far less code and far more adaptability.
-
-4. **Data Pipelines vs. Prompt-Orchestrated Workflows**
-
-APIs typically act on structured data passed through predefined pipelines — data in, response out.
-
-Agents can transform unstructured inputs into structured actions using prompts, models, and memory. For example, you can prompt an agent to “summarize this customer support thread and update the CRM” without hard-coding every transformation step. The agent parses, reasons, and executes — like a junior team member, not a tool.
-
-## The Agent Paradigm Shift
-The emergence of agents marks a shift from programming behavior to designing intent and outcomes. With the Agentuity platform, you're not building step-by-step logic — you're defining objectives and letting agents determine how best to fulfill them. This unlocks:
-
-- **Adaptive workflows** that evolve in real-time
-
-- **Conversational interfaces** that feel truly intelligent
-
-- **Less brittle systems** that aren't tied to rigid, pre-defined rules
-
-Agents aren't just a new abstraction — they're a new operational model for software. They bring reasoning, flexibility, and decision-making into the core of your systems.
-
-## Why a Traditional Chatbot isn't an AI Agent
-
-A traditional chatbot is like a scripted receptionist — it follows predefined rules, matches keywords, and responds with canned answers. It can handle simple, repetitive tasks, but it doesn't understand context, adapt to new situations, or make decisions.
-
-An AI agent, on the other hand, is more like a smart collaborator. It can interpret intent, reason through complex tasks, take independent actions, and adapt in real time. It's not limited to conversation — it can plan, orchestrate workflows, and interact with systems to get things done autonomously.
-
-In short: a chatbot talks; an agent thinks and acts.
-
-## Why do Agents need an Agent-Native Cloud?
-
-**Think about today's cloud computing paradigm:**
-
-We have optimized cloud computing largely by moving the compute to the edge, focusing on horizontal scaling and cost efficiency through serverless or virtualized workloads. We are obsessed with low latency and sessionless architectures that deliver apps and APIs to our users as fast as possible, often distributed globally.
-
-**Enter agents:**
-
-Agents demands a new paradigm. Agents aren't focused on low latency, they are focused on long-running, complex tasks that require a lot of context and coordination. They are not sessionless, they are stateful and both short and long term memory is required. They are not distributed, they are centralized — often close to the data resources or as close to low latency, high bandwith GPU clusters.
-
-Learn more details about the differences in today's cloud computing paradigm and the [Agent-Native Cloud](/Guides/agent-native-cloud).
-
-If you're a software engineer and you need to build agents, you need to think like an [Agent Builder](/Guides/agent-engineering).
-
-## Video Overview
-
-VIDEO
\ No newline at end of file
diff --git a/content/Introduction/architecture.mdx b/content/Introduction/architecture.mdx
deleted file mode 100644
index bf54e134..00000000
--- a/content/Introduction/architecture.mdx
+++ /dev/null
@@ -1,187 +0,0 @@
----
-title: Overview
-description: Understanding Agentuity
----
-
-## Agentuity Overview
-
-Agentuity is a cloud platform designed to run and scale AI agents with enterprise-grade reliability.
-Our architecture follows a container-based approach, where each agent operates in its own specialized
-environment.
-
-Unlike traditional serverless platforms, Agentuity ensures agents run for as long as needed,
-maintaining state and context throughout agent lifecycles. This long-running approach is
-optimal for complex agent workloads that may require extended processing time, access to storage, or other resources.
-
-The platform is fundamentally cross-platform, allowing you to run different agent frameworks
-(CrewAI, Langchain, custom agents) side by side in the same ecosystem, with built-in communication
-channels between them.
-
-## Core Components
-
-Agentuity consists of five primary components:
-
-1. **Agent Platform** - The cloud platform for providing agent services, providing:
- - Agent communication and routing
- - Agent monitoring, logging, telemetry and troubleshooting
- - Agent usage analytics and performance insights
- - Automatic scaling on-demand based on workload
- - Agent services such as KeyValue, Vector storage, AI Gateway and more
-
-2. **Agent Runtime** - The execution environment where your agents run, providing:
- - Isolated, secure virtualized environment for each agent project
- - Resource management and optimization
- - Long-running support for persistent agents
- - Dynamic Storage, Compute and Networking resources
-
-3. **Command Line Interface (CLI)** - A developer tool that enables:
- - Quick agent creation and initialization
- - Local development and testing
- - Deployment management to the Agentuity cloud
- - Integration with external Agentic code tools via MCP
-
-4. **Software Development Kits (SDKs)** - Libraries that provide:
- - Agent-native tools and services integration with the Agent Platform
- - Runtime-specific optimizations for Python and JavaScript (Node and Bun)
- - Integration capabilities with external systems
- - Enhanced agent capabilities and extensions which work cross-framework and cross-runtime
-
-4. **Web Console** - A management interface offering:
- - Real-time agent monitoring and metrics
- - Deployment and configuration management
- - Usage analytics, logging, monitoring and performance insights
- - Team collaboration features
-
-## Data Flow
-
-Agent communication and data flow in Agentuity follow secure, encrypted channels:
-
-1. **Agent-to-Agent Communication** - Agents can communicate with each other through authenticated, encrypted routing,
-regardless of the underlying frameworks or runtimes used.
-
-2. **External Integrations** - Agents can connect to external systems and data sources through managed
-integration points.
-
-3. **Deployment Pipeline** - Your project code is packaged, containerized, and deployed to the Agentuity
-cloud infrastructure with appropriate networking and routing configured automatically. Built-in support for GitHub Actions.
-
-## Scalability
-
-Agentuity is designed for enterprise-scale agent deployments:
-
-- **Horizontal Scaling** - Automatically provision additional resources as demand increases
-- **Framework Agnostic** - Scale any type of agent regardless of the underlying framework
-- **Load Balancing** - Distribute agent workloads efficiently across available resources
-- **Resource Optimization** - Intelligently allocate compute resources based on agent requirements
-
-## Security Architecture
-
-Security is foundational to Agentuity's design:
-
-- **Agent Isolation** - Each agent project operates in its own isolated environment
-- **Encrypted Communications** - All agent-to-agent communication is encrypted
-- **Secure Deployment** - Protected deployment pipeline from development to production
-
-## Project Conventions
-
-Agentuity projects follow specific conventions in order to take advantage of the deployment and cloud platform Agentuity offers. While we don't dictate which framework to use, we do have a few things you have to follow in your file system. Understanding these conventions are important.
-
-### Project Structure
-
-Every Agentuity project requires the following core components:
-
-1. **agentuity.yaml** - The central configuration file that defines:
- - Project metadata (name, ID, description)
- - Development settings (port, watch patterns)
- - Deployment configuration (resources, scaling)
- - Bundler settings (language, runtime)
- - Agent definitions and routing
-
-2. **Environment Variables** - Stored in a `.env` file:
- - `AGENTUITY_SDK_KEY` - Identifies the SDK level API Key (only used in development to access the Agentuity Cloud)
- - `AGENTUITY_PROJECT_KEY` - Identifies the project level API Key
- - Additional provider-specific keys (OpenAI, Anthropic, etc.)
-
-3. **Agent Directory** - Specified in `bundler.agents.dir` (determined by the runtime):
- - Each agent has its own subdirectory
- - Language-specific entry points (index.ts/js for JavaScript, agent.py for Python)
- - Agent-specific configuration and dependencies
-
-### Language-Specific Conventions
-
-#### JavaScript/TypeScript Projects
-
-```
-my-project/
-├── agentuity.yaml # Project configuration
-├── .env # Environment variables
-├── package.json # Dependencies and scripts
-└── src/
- └── agents/ # Agent directory
- └── my-agent/ # Individual agent
- └── index.ts # Agent entry point
-```
-
-- Each agent must export a handler function that processes requests
-- TypeScript is recommended but JavaScript is fully supported
-- Supported runtimes: Node.js and Bun
-
-#### Python Projects
-
-```
-my-project/
-├── agentuity.yaml # Project configuration
-├── .env # Environment variables
-├── pyproject.toml # Dependencies and configuration
-└── agentuity_agents/ # Agents directory
- └── my-agent/ # Individual agent
- └── agent.py # Agent entry point
-```
-
-- Each agent must define a `run()` function that processes requests
-- Supported runtimes: Python and uv (for dependency management)
-
-### Configuration File (agentuity.yaml)
-
-The `agentuity.yaml` file is the heart of your project, defining how it behaves in development and production:
-
-```yaml
-version: ">=0.0.0" # Minimum CLI version required
-project_id: "proj_..." # Unique project identifier
-name: "My Project" # Human-readable project name
-description: "..." # Optional project description
-
-# Development configuration
-development:
- port: 3000 # Local development server port
- watch:
- enabled: true # Auto-reload on file changes
- files: ["src/**/*.ts"] # Files to watch
-
-# Deployment configuration
-deployment:
- resources:
- memory: "1Gi" # Memory allocation
- cpu: "1000m" # CPU allocation
-
-# Bundler configuration
-bundler:
- language: "javascript" # Programming language (javascript or python)
- runtime: "nodejs" # Runtime environment (nodejs, bunjs, python, uv)
- agents:
- dir: "src/agents" # Directory where agents are located
-
-# Agents configuration
-agents:
- - id: "agent_..." # Unique agent identifier
- name: "My Agent" # Human-readable agent name
- description: "..." # Optional agent description
-```
-
-### Why These Conventions Matter
-
-These conventions enable several key capabilities:
-
-1. **Consistent Development Experience** - Standardized structure makes it easier to work across projects
-2. **Automated Deployment** - The CLI can package and deploy your project without additional configuration
-3. **Framework Flexibility** - Use any agent framework while maintaining compatibility with the platform
diff --git a/content/Introduction/getting-started.mdx b/content/Introduction/getting-started.mdx
deleted file mode 100644
index ed760006..00000000
--- a/content/Introduction/getting-started.mdx
+++ /dev/null
@@ -1,117 +0,0 @@
----
-title: Getting Started
-description: Get started with Agentuity in minutes
----
-
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-
-
-
-### Create a Free Account
-[Create a free Agentuity account](https://app.agentuity.com/sign-up) or [Sign in](https://app.agentuity.com/sign-in) to the cloud portal.
-
-If you already have the Agentuity CLI installed, you can skip this step and signup using the CLI.
-
-
-
-### Install the CLI
-
-The [Agentuity CLI](/CLI/installation) is a cross-platform command-line tool for working with Agentuity Cloud. It supports Windows (using WSL), MacOS, and Linux.
-
-
-
-
-
-### Sign up for an Account with the CLI
-
-You can sign up for a free account using the CLI or skip this step if you already have an account.
-
-
-
-
-
-### Login to Agentuity
-
-You can skip this step if you used the CLI to sign up for an account, otherwise you must login to your account using the CLI.
-
-
-
-
-
-### Create Your First Project
-
-You can select a template to get started quickly.
-
-
-
-
-
-### Run Your Agent Locally
-
-You can run your agent locally to test it out before you deploy it to the cloud.
-
-
-
-
-
-### Deploy Your Project to the Cloud
-
-Deploy your agent to the cloud and start using it! 🚀
-
-
-
-
-If you're using an Agentic Code Editor such as [Cursor](https://www.cursor.com), just tell your agent to deploy your project to the cloud such as "Deploy my project to the cloud" and it will do it for you.
-
-
-
-
-
-
-## Recommended Reading
-
-
-
-
-
-
-
-
-
-
-## Video Tutorial
-
-VIDEO
-
diff --git a/content/Introduction/index.mdx b/content/Introduction/index.mdx
deleted file mode 100644
index 8ff34b42..00000000
--- a/content/Introduction/index.mdx
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: What is Agentuity?
-description: Agentuity is rebuilding the cloud for AI Agents
----
-
-{/* Empty PR 6 - minimal change for testing purposes */}
-
-
- Build agents, not infrastructure
-
-
-[Agentuity](https://agentuity.com) is a cloud platform designed specifically to make it easy to build, deploy, and operate AI Agents at scale.
-
-Our mission is to provide a fully agentic infrastructure and tools necessary to build Agents that are fully operated by AI.
-
-
-If you're ready to dive in, skip to [Getting Started](/Introduction/getting-started) to get your first Agent up and running in minutes.
-
-
-
-With Agentuity, you or your agents can:
-
-- Deploy agents with a single command to a fully agentic infrastructure
-- Monitor real-time performance, analytics, metrics and logs
-- Auto scale agents effortlessly and on-demand
-- Connect agents to various input and output channels (API, chat, webhooks, email, SMS, voice, etc.)
-- Securely communicate between agents and build complex agentic workflows
-- Use any AI agent framework across Python, Node.js or Bun
-
-
-We see a near future where Agents are the primary way to build and operate software and where all the infrastructure is built uniquely for them.
-
-
-## Agentuity Platform Overview
-
-VIDEO
-
-If you're ready to have your own Agent, [Get Started](/Introduction/getting-started) in just a few minutes.
diff --git a/content/Introduction/kitchen-sink.mdx b/content/Introduction/kitchen-sink.mdx
deleted file mode 100644
index c857e39f..00000000
--- a/content/Introduction/kitchen-sink.mdx
+++ /dev/null
@@ -1,108 +0,0 @@
----
-title: Explore the Kitchen Sink
-description: The fastest way to see what's possible with Agentuity
----
-
-## Overview
-
-New to Agentuity? The Kitchen Sink is the fastest way to see what's possible on the platform.
-
-## Interactive Learning
-
-Deploy 20+ working agents that demonstrate every SDK feature. Send messages, watch responses, and copy the patterns that work.
-
-**Why start here:**
-- See features in action before reading documentation
-- Test patterns in a live environment
-- Learn by doing with working code examples
-
-
-
-## What You'll Explore
-
-The Kitchen Sink covers the complete Agentuity platform:
-
-### Core SDK Features
-- **Request & Response Handling** - Access request data, return different content types
-- **Agent Context** - Session management and persistent state
-- **AI Gateway** - Multiple LLM providers with unified API
-
-### Agent Communication
-- **Agent-to-Agent** - Direct communication and handoffs between agents
-- **API Integration** - Synchronous request handling
-- **Webhooks** - Asynchronous event processing
-
-### Storage Solutions
-- **Key-Value Store** - Fast caching and session state
-- **Object Storage** - Files, images, and large data
-- **Vector Search** - Semantic search with embeddings
-
-### Scheduling & Messaging
-- **Cron Jobs** - Scheduled execution
-- **Email Processing** - Receive and respond to emails
-- **SMS Integration** - Messaging via Twilio
-
-### Observability
-- **Structured Logging** - Multiple log levels and formatting
-- **OpenTelemetry Tracing** - Distributed tracing with spans
-
-### Real-World Examples
-- **Chat Agent** - Conversational AI with history
-- **Slack Bot** - Thread support and workspace integration
-- **Discord Webhooks** - Notification system
-- **Composio Tools** - External service integrations
-
-## How It Works
-
-1. **Deploy instantly** - One-click deployment to your Agentuity account
-2. **Open DevMode** - Interactive testing environment in your browser
-3. **Send messages** - Talk to each agent to see features in action
-4. **Read the code** - Source code is available for every example
-5. **Copy patterns** - Use working implementations in your projects
-
-## Quick Start
-
-Once deployed, you'll have access to DevMode where you can:
-
-- **Ask the `kitchen-sink` agent** questions about any platform feature
-- **Try suggested prompts** from each agent to see capabilities
-- **Watch logs in real-time** to understand execution flow
-- **View responses** to see how each agent behaves
-
-
-Keep the GitHub repository open alongside DevMode to follow along with the source code as you test each feature.
-
-
-## Next Steps
-
-After exploring the Kitchen Sink:
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/content/Introduction/meta.json b/content/Introduction/meta.json
deleted file mode 100644
index a88b84c7..00000000
--- a/content/Introduction/meta.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "title": "Introduction",
- "pages": ["index", "getting-started", "kitchen-sink", "architecture", "templates"]
-}
diff --git a/content/Introduction/templates.mdx b/content/Introduction/templates.mdx
deleted file mode 100644
index a998d642..00000000
--- a/content/Introduction/templates.mdx
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: Agent Templates
-description: Pre-configured agent configurations
----
-
-## Overview
-
-Templates are pre-configured agent configurations that can be used to quickly deploy and configure Agentuity for popular agent frameworks, AI providers and runtimes.
-
-When you create a new Agent project, you can select a template to use as a starting point.
-
-## Python (uv tool)
-
-
-uv is a Python package manager and project runner, not a runtime. Unlike Python runtimes that execute code, uv manages dependencies, creates virtual environments, and runs Python applications. It's similar to pip + virtualenv but faster and more integrated.
-
-
-### Python Agent Frameworks
-
-| Framework | More Information |
-| ----------------- | ------------------------------------------------------- |
-| AutoGen | https://microsoft.github.io/autogen/ |
-| AWS Strands | https://strandsagents.com/latest/ |
-| CrewAI | https://www.crewai.com/ |
-| Haystack | https://haystack.deepset.ai/ |
-| LangChain | https://www.langchain.com/ |
-| LangGraph | https://www.langchain.com/langgraph |
-| LlamaIndex | https://www.llamaindex.ai/ |
-| OpenAI Agents | https://github.com/openai/openai-agents-python |
-| Praison AI | https://docs.praison.ai/docs/index |
-| Pydantic AI | https://ai.pydantic.dev/ |
-
-### Python AI Providers
-
-| Provider | More Information |
-| ------------- | ------------------------------- |
-| Anthropic | https://www.anthropic.com/ |
-| Google Gen AI | https://ai.google.com/ |
-| LiteLLM | https://www.litellm.ai/ |
-| OpenAI | https://openai.com/ |
-
-## JavaScript/TypeScript
-
-### JavaScript Agent Frameworks
-
-| Framework | More Information |
-| ------------- | --------------------------------------------- |
-| LangChain | https://js.langchain.com/ |
-| LangGraph | https://langchain-ai.github.io/langgraphjs/ |
-| Mastra | https://mastra.ai/ |
-| Praison AI | https://docs.praisonai.com/ |
-| VoltAgent | https://github.com/voltagentai/voltagent |
-| Vercel AI SDK | https://ai.vercel.com/ |
-
-### JavaScript AI Providers
-
-| Provider | More Information |
-| ------------- | ------------------------------- |
-| Anthropic | https://www.anthropic.com/ |
-| Google Gen AI | https://ai.google.com/ |
-| Groq | https://groq.com/ |
-| OpenAI | https://openai.com/ |
-
-
-For JavaScript/TypeScript, both the Bun and Node.js runtimes are supported.
-
-
-## Creating Templates
-
-The Agentuity Template system is fully open source and you can create your own templates by forking the [Agentuity Template repository](https://github.com/agentuity/templates) and making a pull request. Don't see your favorite framework? Fork the repository, add it and send us a pull request!
-
-Run the following command to test your template locally:
-
-
diff --git a/content/Learn/Cookbook/Patterns/background-tasks.mdx b/content/Learn/Cookbook/Patterns/background-tasks.mdx
new file mode 100644
index 00000000..a69972c7
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/background-tasks.mdx
@@ -0,0 +1,165 @@
+---
+title: Background Tasks
+description: Use waitUntil to run work after responding to the client
+---
+
+Run tasks after sending a response using `waitUntil`. This keeps response times fast while handling analytics, notifications, or other fire-and-forget work.
+
+## The Pattern
+
+`waitUntil` accepts an async function that runs after the response is sent. Multiple calls run concurrently.
+
+This example uses [ArkType](https://arktype.io) for schema validation:
+
+```typescript title="src/agent/order-processor/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { type } from 'arktype';
+
+const agent = createAgent('OrderProcessor', {
+ schema: {
+ input: type({
+ orderId: 'string',
+ userId: 'string',
+ }),
+ output: type({
+ status: 'string',
+ orderId: 'string',
+ }),
+ },
+ handler: async (ctx, input) => {
+ const { orderId, userId } = input;
+
+ // Process the order synchronously
+ const order = await processOrder(orderId);
+
+ // Background: send confirmation email
+ ctx.waitUntil(async () => { // [!code highlight]
+ await sendConfirmationEmail(userId, order);
+ ctx.logger.info('Confirmation email sent', { orderId });
+ });
+
+ // Background: update analytics
+ ctx.waitUntil(async () => { // [!code highlight]
+ await trackPurchase(userId, order);
+ });
+
+ // Background: notify warehouse
+ ctx.waitUntil(async () => { // [!code highlight]
+ await notifyWarehouse(order);
+ });
+
+ // Response sent immediately, background tasks continue
+ return {
+ status: 'confirmed',
+ orderId,
+ };
+ },
+});
+
+export default agent;
+```
+
+## With Durable Streams
+
+Create a stream for the client to poll, then populate it in the background:
+
+```typescript title="src/agent/async-generator/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { type } from 'arktype';
+
+const agent = createAgent('AsyncGenerator', {
+ schema: {
+ input: type({ prompt: 'string' }),
+ output: type({
+ streamId: 'string',
+ streamUrl: 'string',
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Create a durable stream the client can read from
+ const stream = await ctx.stream.create('generation', { // [!code highlight]
+ contentType: 'text/plain',
+ metadata: { sessionId: ctx.sessionId },
+ });
+
+ // Generate content in the background
+ ctx.waitUntil(async () => { // [!code highlight]
+ try {
+ const { textStream } = streamText({
+ model: openai('gpt-5-mini'),
+ prompt: input.prompt,
+ });
+
+ for await (const chunk of textStream) {
+ await stream.write(chunk);
+ }
+ } finally {
+ await stream.close(); // [!code highlight]
+ }
+ });
+
+ // Return stream URL immediately
+ return {
+ streamId: stream.id,
+ streamUrl: stream.url,
+ };
+ },
+});
+
+export default agent;
+```
+
+## Progress Reporting
+
+Write progress updates to a stream as background work proceeds:
+
+```typescript title="src/agent/batch-processor/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { type } from 'arktype';
+
+const agent = createAgent('BatchProcessor', {
+ schema: {
+ input: type({ items: 'string[]' }),
+ output: type({ progressUrl: 'string' }),
+ },
+ handler: async (ctx, input) => {
+ const progress = await ctx.stream.create('progress', {
+ contentType: 'application/x-ndjson',
+ });
+
+ ctx.waitUntil(async () => {
+ try {
+ for (let i = 0; i < input.items.length; i++) {
+ await processItem(input.items[i]);
+
+ await progress.write(JSON.stringify({
+ completed: i + 1,
+ total: input.items.length,
+ percent: Math.round(((i + 1) / input.items.length) * 100),
+ }) + '\n');
+ }
+
+ await progress.write(JSON.stringify({ done: true }) + '\n');
+ } finally {
+ await progress.close();
+ }
+ });
+
+ return { progressUrl: progress.url };
+ },
+});
+```
+
+## Key Points
+
+- **Non-blocking**: Response returns immediately, tasks run after
+- **Concurrent**: Multiple `waitUntil` calls run in parallel
+- **Error isolation**: Background task failures don't affect the response
+- **Always close streams**: Use `finally` blocks to ensure cleanup
+
+## See Also
+
+- [Durable Streams](/Build/Storage/durable-streams) for stream creation and management
+- [Webhook Handler](/Learn/Cookbook/Patterns/webhook-handler) for another `waitUntil` example
diff --git a/content/Learn/Cookbook/Patterns/chat-with-history.mdx b/content/Learn/Cookbook/Patterns/chat-with-history.mdx
new file mode 100644
index 00000000..bc115c78
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/chat-with-history.mdx
@@ -0,0 +1,203 @@
+---
+title: Chat with Conversation History
+description: Build a chat agent that remembers previous messages using thread state
+---
+
+Use thread state to maintain conversation history across multiple requests. The thread persists for up to 1 hour, making it ideal for chat sessions.
+
+## The Pattern
+
+Thread state stores conversation history automatically. Each browser session gets its own thread, and messages persist across requests.
+
+```typescript title="src/agent/chat/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { streamText } from 'ai';
+import { anthropic } from '@ai-sdk/anthropic';
+import { s } from '@agentuity/schema';
+
+interface Message {
+ role: 'user' | 'assistant';
+ content: string;
+}
+
+const agent = createAgent('Chat Agent', {
+ description: 'Conversational agent with memory',
+ schema: {
+ input: s.object({
+ message: s.string(),
+ }),
+ stream: true,
+ },
+ handler: async (ctx, input) => {
+ // Get or initialize conversation history (async)
+ const messages = (await ctx.thread.state.get('messages')) || []; // [!code highlight]
+
+ // Add user message
+ messages.push({ role: 'user', content: input.message });
+
+ // Generate streaming response
+ const { textStream, text } = streamText({
+ model: anthropic('claude-sonnet-4-5'),
+ system: 'You are a helpful assistant. Be concise but friendly.',
+ messages,
+ });
+
+ // Save assistant response after streaming completes
+ ctx.waitUntil(async () => { // [!code highlight]
+ const fullResponse = await text;
+ messages.push({ role: 'assistant', content: fullResponse });
+ await ctx.thread.state.set('messages', messages); // [!code highlight]
+ ctx.logger.info('Conversation updated', {
+ messageCount: messages.length,
+ threadId: ctx.thread.id,
+ });
+ });
+
+ return textStream;
+ },
+});
+
+export default agent;
+```
+
+## Route Example
+
+```typescript title="src/api/chat/route.ts"
+import { createRouter } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', chatAgent.validator(), async (c) => {
+ const { message } = c.req.valid('json');
+ return chatAgent.run({ message });
+});
+
+// Reset conversation
+router.delete('/chat', async (c) => {
+ await c.var.thread.destroy(); // [!code highlight]
+ return c.json({ reset: true });
+});
+
+export default router;
+```
+
+## Frontend
+
+A simple chat interface that displays streaming responses:
+
+```tsx title="src/web/App.tsx"
+import { useState, useRef, useEffect } from 'react';
+
+interface Message {
+ role: 'user' | 'assistant';
+ content: string;
+}
+
+export function App() {
+ const [messages, setMessages] = useState([]);
+ const [input, setInput] = useState('');
+ const [isStreaming, setIsStreaming] = useState(false);
+ const messagesEndRef = useRef(null);
+
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+ }, [messages]);
+
+ const sendMessage = async () => {
+ if (!input.trim() || isStreaming) return;
+
+ const userMessage = input.trim();
+ setInput('');
+ setMessages((prev) => [...prev, { role: 'user', content: userMessage }]);
+ setIsStreaming(true);
+
+ // Add placeholder for assistant response
+ setMessages((prev) => [...prev, { role: 'assistant', content: '' }]);
+
+ const response = await fetch('/chat', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ message: userMessage }),
+ });
+
+ // Stream the response
+ const reader = response.body?.getReader();
+ const decoder = new TextDecoder();
+
+ while (reader) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const chunk = decoder.decode(value);
+ setMessages((prev) => {
+ const updated = [...prev];
+ updated[updated.length - 1].content += chunk;
+ return updated;
+ });
+ }
+
+ setIsStreaming(false);
+ };
+
+ return (
+
+
+ {messages.map((msg, i) => (
+
+ {msg.content || '...'}
+
+ ))}
+
+
+
+
+ setInput(e.target.value)}
+ onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
+ placeholder="Type a message..."
+ disabled={isStreaming}
+ style={{ flex: 1, padding: '0.75rem' }}
+ />
+
+ {isStreaming ? '...' : 'Send'}
+
+
+
+ );
+}
+```
+
+The frontend reads the streaming response chunk by chunk and updates the UI in real-time.
+
+## Key Points
+
+- **Thread state** (`ctx.thread.state`) persists for up to 1 hour
+- **Async API**: All thread state methods are async (`await ctx.thread.state.get()`)
+- **Messages array** stores the full conversation history
+- **`waitUntil`** saves the response after streaming completes
+- **Thread ID** (`ctx.thread.id`) identifies the conversation
+
+
+For append-only patterns like chat history, use `push()` with `maxRecords` for automatic sliding window behavior:
+
+```typescript
+await ctx.thread.state.push('messages', newMessage, 100); // Keeps last 100
+```
+
+
+## See Also
+
+- [State Management](/Build/Agents/state-management) for all state scopes
+- [Streaming Responses](/Build/Agents/streaming-responses) for streaming patterns
diff --git a/content/Learn/Cookbook/Patterns/cron-with-storage.mdx b/content/Learn/Cookbook/Patterns/cron-with-storage.mdx
new file mode 100644
index 00000000..498b719f
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/cron-with-storage.mdx
@@ -0,0 +1,165 @@
+---
+title: Cron with Storage
+description: Cache scheduled task results in KV for later retrieval
+---
+
+Schedule tasks to run automatically and cache results for later retrieval. The platform triggers your endpoint on schedule, and KV storage persists the data between runs.
+
+## The Pattern
+
+Fetch external data on a schedule and store it in KV. A separate GET endpoint retrieves the cached results.
+
+```typescript title="src/api/hn/route.ts"
+import { createRouter, cron } from '@agentuity/runtime'; // [!code highlight]
+
+const router = createRouter();
+
+interface Story {
+ id: number;
+ title: string;
+ score: number;
+ by: string;
+ url: string;
+}
+
+// Runs every hour - fetches top HN stories and caches them
+router.post('/digest', cron('0 * * * *', async (c) => { // [!code highlight]
+ c.var.logger.info('Fetching HN stories');
+
+ // Get top story IDs
+ const idsRes = await fetch('https://hacker-news.firebaseio.com/v0/topstories.json');
+ const ids = (await idsRes.json()) as number[];
+
+ // Fetch details for top 5
+ const stories = await Promise.all(
+ ids.slice(0, 5).map(async (id) => {
+ const res = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
+ const story = (await res.json()) as Story;
+ return {
+ id: story.id,
+ title: story.title,
+ score: story.score,
+ by: story.by,
+ url: story.url || `https://news.ycombinator.com/item?id=${story.id}`,
+ };
+ })
+ );
+
+ // Cache in KV with 24-hour TTL
+ await c.var.kv.set('cache', 'hn-stories', { // [!code highlight]
+ stories,
+ fetchedAt: new Date().toISOString(),
+ }, { ttl: 86400 }); // [!code highlight]
+
+ c.var.logger.info('Stories cached', { count: stories.length });
+ return c.json({ success: true, count: stories.length });
+}));
+
+// Retrieve cached stories
+router.get('/stories', async (c) => {
+ const result = await c.var.kv.get<{ stories: Story[]; fetchedAt: string }>('cache', 'hn-stories'); // [!code highlight]
+
+ if (!result.exists) {
+ return c.json({ stories: [], fetchedAt: null });
+ }
+
+ return c.json(result.data);
+});
+
+export default router;
+```
+
+## Frontend
+
+A simple interface to trigger the cron job and display cached stories:
+
+```tsx title="src/web/App.tsx"
+import { useState, useEffect } from 'react';
+
+interface Story {
+ id: number;
+ title: string;
+ score: number;
+ by: string;
+ url: string;
+}
+
+export function App() {
+ const [stories, setStories] = useState([]);
+ const [fetchedAt, setFetchedAt] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const loadStories = async () => {
+ const res = await fetch('/api/hn/stories'); // [!code highlight]
+ const data = await res.json();
+ setStories(data.stories || []);
+ setFetchedAt(data.fetchedAt);
+ };
+
+ const triggerFetch = async () => {
+ setIsLoading(true);
+ await fetch('/api/hn/digest', { method: 'POST' }); // [!code highlight]
+ await loadStories();
+ setIsLoading(false);
+ };
+
+ useEffect(() => {
+ loadStories();
+ }, []);
+
+ return (
+
+
HN Top Stories
+
+
+
+ {isLoading ? 'Fetching...' : 'Fetch Latest'}
+
+ {fetchedAt && (
+
+ Last updated: {new Date(fetchedAt).toLocaleString()}
+
+ )}
+
+
+ {stories.length === 0 ? (
+
No stories cached. Click "Fetch Latest" to load.
+ ) : (
+
+ )}
+
+ );
+}
+```
+
+## Testing Locally
+
+Cron schedules only trigger in deployed environments. Use the "Fetch Latest" button in the UI to test locally. If you need to call the endpoints directly:
+
+```bash
+curl -X POST http://localhost:3500/api/hn/digest
+curl http://localhost:3500/api/hn/stories
+```
+
+## Key Points
+
+- **`cron()` middleware** wraps POST handlers with a schedule expression
+- **KV with TTL** automatically expires stale data (24 hours in this example)
+- **Separate GET endpoint** lets clients retrieve cached results anytime
+- **Local testing** requires manual triggers since schedules only run when deployed
+
+## See Also
+
+- [Cron Routes](/Build/Routes/cron) for schedule expressions and patterns
+- [Key-Value Storage](/Build/Storage/key-value) for KV operations and TTL options
diff --git a/content/Learn/Cookbook/Patterns/meta.json b/content/Learn/Cookbook/Patterns/meta.json
new file mode 100644
index 00000000..13f51da0
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/meta.json
@@ -0,0 +1,12 @@
+{
+ "title": "Patterns",
+ "pages": [
+ "background-tasks",
+ "chat-with-history",
+ "cron-with-storage",
+ "server-utilities",
+ "product-search",
+ "tailwind-setup",
+ "webhook-handler"
+ ]
+}
diff --git a/content/Learn/Cookbook/Patterns/product-search.mdx b/content/Learn/Cookbook/Patterns/product-search.mdx
new file mode 100644
index 00000000..a32c0780
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/product-search.mdx
@@ -0,0 +1,427 @@
+---
+title: Product Search with Vector
+description: Semantic product search with metadata filtering
+---
+
+Build a product search that understands natural language queries and filters by category, price, or other attributes.
+
+## The Pattern
+
+Vector search finds semantically similar products. Combine with metadata filtering for precise results.
+
+```typescript title="src/agent/product-search/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+interface ProductMetadata {
+ name: string;
+ price: number;
+ category: string;
+ inStock: boolean;
+}
+
+const agent = createAgent('Product Search', {
+ description: 'Semantic search for products',
+ schema: {
+ input: z.object({
+ query: z.string().describe('Natural language search query'),
+ category: z.string().optional().describe('Filter by category'),
+ maxPrice: z.number().optional().describe('Maximum price filter'),
+ limit: z.number().min(1).max(50).default(10),
+ }),
+ output: z.object({
+ products: z.array(z.object({
+ id: z.string(),
+ name: z.string(),
+ description: z.string(),
+ price: z.number(),
+ category: z.string(),
+ relevance: z.number(),
+ })),
+ total: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Searching products', {
+ query: input.query,
+ category: input.category,
+ maxPrice: input.maxPrice,
+ });
+
+ // Search with semantic similarity
+ const results = await ctx.vector.search('products', { // [!code highlight]
+ query: input.query,
+ limit: input.limit * 2, // Fetch extra for filtering
+ similarity: 0.6,
+ });
+
+ // Apply metadata filters
+ let filtered = results;
+
+ if (input.category) {
+ filtered = filtered.filter(r =>
+ r.metadata?.category?.toLowerCase() === input.category?.toLowerCase()
+ );
+ }
+
+ if (input.maxPrice) {
+ filtered = filtered.filter(r =>
+ (r.metadata?.price ?? Infinity) <= input.maxPrice!
+ );
+ }
+
+ // Only show in-stock items
+ filtered = filtered.filter(r => r.metadata?.inStock !== false);
+
+ // Limit to requested count
+ const products = filtered.slice(0, input.limit).map(r => ({
+ id: r.key,
+ name: r.metadata?.name || 'Unknown',
+ description: r.document || '',
+ price: r.metadata?.price || 0,
+ category: r.metadata?.category || 'Uncategorized',
+ relevance: r.similarity,
+ }));
+
+ ctx.logger.info('Search complete', {
+ found: results.length,
+ afterFilters: products.length,
+ });
+
+ return {
+ products,
+ total: products.length,
+ };
+ },
+});
+
+export default agent;
+```
+
+## Indexing Products
+
+Add products to the vector database. This example uses [Valibot](https://valibot.dev) for schema validation:
+
+```typescript title="src/agent/product-indexer/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import * as v from 'valibot';
+
+const ProductSchema = v.object({
+ id: v.string(),
+ name: v.string(),
+ description: v.string(),
+ price: v.number(),
+ category: v.string(),
+ inStock: v.optional(v.boolean(), true),
+});
+
+const agent = createAgent('ProductIndexer', {
+ schema: {
+ input: v.object({
+ products: v.array(ProductSchema),
+ }),
+ output: v.object({
+ indexed: v.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ for (const product of input.products) {
+ // Use description as the searchable document
+ await ctx.vector.upsert('products', {
+ key: product.id,
+ document: `${product.name}. ${product.description}`,
+ metadata: {
+ name: product.name,
+ price: product.price,
+ category: product.category,
+ inStock: product.inStock,
+ },
+ });
+ }
+
+ return { indexed: input.products.length };
+ },
+});
+
+export default agent;
+```
+
+## Route with Query Parameters
+
+```typescript title="src/api/products/route.ts"
+import { createRouter } from '@agentuity/runtime';
+import productSearch from '@agent/product-search';
+
+const router = createRouter();
+
+router.get('/search', async (c) => {
+ const query = c.req.query('q') || '';
+ const category = c.req.query('category');
+ const maxPrice = c.req.query('maxPrice');
+ const limit = parseInt(c.req.query('limit') || '10');
+
+ const result = await productSearch.run({
+ query,
+ category,
+ maxPrice: maxPrice ? parseFloat(maxPrice) : undefined,
+ limit,
+ });
+
+ return c.json(result);
+});
+
+export default router;
+```
+
+## AI-Powered Recommendations
+
+Enhance search results with AI-generated recommendations. Use `generateObject` to analyze matches and suggest the best option.
+
+```typescript title="src/agent/product-advisor/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { generateObject } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { s } from '@agentuity/schema';
+import { z } from 'zod';
+
+interface ProductMetadata {
+ sku: string;
+ name: string;
+ price: number;
+ rating: number;
+ description: string;
+ feedback: string;
+}
+
+const agent = createAgent('Product Advisor', {
+ description: 'Semantic search with AI recommendations',
+ schema: {
+ input: s.object({
+ query: s.string(),
+ }),
+ output: s.object({
+ matches: s.array(
+ s.object({
+ sku: s.string(),
+ name: s.string(),
+ price: s.number(),
+ rating: s.number(),
+ similarity: s.number(),
+ })
+ ),
+ recommendation: s.string(),
+ recommendedSKU: s.string(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Semantic search for matching products
+ const results = await ctx.vector.search('products', {
+ query: input.query,
+ limit: 3,
+ similarity: 0.3,
+ });
+
+ if (results.length === 0) {
+ return {
+ matches: [],
+ recommendation: 'No matching products found. Try a different search.',
+ recommendedSKU: '',
+ };
+ }
+
+ // Format matches for response
+ const matches = results.map((r) => ({
+ sku: r.metadata?.sku ?? '',
+ name: r.metadata?.name ?? '',
+ price: r.metadata?.price ?? 0,
+ rating: r.metadata?.rating ?? 0,
+ similarity: r.similarity,
+ }));
+
+ // Build context for AI recommendation
+ const context = results
+ .map((r) => {
+ const p = r.metadata;
+ return `${p?.name}: SKU ${p?.sku}, $${p?.price}, ${p?.rating} stars. "${p?.feedback}"`;
+ })
+ .join('\n');
+
+ // Generate personalized recommendation
+ const { object } = await generateObject({ // [!code highlight]
+ model: openai('gpt-5-mini'),
+ system: 'You are a product consultant. Provide a brief 2-3 sentence recommendation based on the search results. Reference customer feedback when relevant.',
+ prompt: `Customer searched for: "${input.query}"\n\nMatching products:\n${context}`,
+ schema: z.object({
+ summary: z.string().describe('Brief recommendation explaining the best choice'),
+ recommendedSKU: z.string().describe('SKU of the recommended product'),
+ }),
+ });
+
+ return {
+ matches,
+ recommendation: object.summary,
+ recommendedSKU: object.recommendedSKU,
+ };
+ },
+});
+
+export default agent;
+```
+
+
+Add AI recommendations when customers benefit from personalized guidance: comparing similar products, explaining trade-offs, or highlighting relevant features based on their search intent.
+
+
+### Example Response
+
+```json
+{
+ "matches": [
+ { "sku": "CHAIR-ERG-001", "name": "ErgoMax Pro", "price": 549, "rating": 4.8, "similarity": 0.89 },
+ { "sku": "CHAIR-BUD-002", "name": "ComfortBasic", "price": 129, "rating": 4.2, "similarity": 0.76 }
+ ],
+ "recommendation": "For a comfortable office chair, I recommend the ErgoMax Pro. Customers report significant back pain relief, and the premium lumbar support justifies the higher price for long work sessions.",
+ "recommendedSKU": "CHAIR-ERG-001"
+}
+```
+
+## Frontend
+
+A search interface that displays matches and the AI recommendation:
+
+```tsx title="src/web/App.tsx"
+import { useState } from 'react';
+
+interface Match {
+ sku: string;
+ name: string;
+ price: number;
+ rating: number;
+ similarity: number;
+}
+
+interface SearchResult {
+ matches: Match[];
+ recommendation: string;
+ recommendedSKU: string;
+}
+
+export function App() {
+ const [query, setQuery] = useState('');
+ const [result, setResult] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const search = async () => {
+ if (!query.trim()) return;
+ setLoading(true);
+
+ const response = await fetch('/api/products/search', { // [!code highlight]
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query }),
+ });
+ const data = await response.json();
+ setResult(data);
+ setLoading(false);
+ };
+
+ return (
+
+
Product Search
+
+
+ setQuery(e.target.value)}
+ onKeyDown={(e) => e.key === 'Enter' && search()}
+ placeholder="Search products..."
+ style={{ flex: 1, padding: '0.75rem' }}
+ />
+
+ {loading ? '...' : 'Search'}
+
+
+
+ {result && (
+ <>
+ {/* AI Recommendation */}
+ {result.recommendation && (
+
+
AI Recommendation
+
{result.recommendation}
+
+ )}
+
+ {/* Matches */}
+
+ {result.matches.map((match) => (
+
+
+
+
{match.name}
+ {match.sku === result.recommendedSKU && (
+
+ Recommended
+
+ )}
+
{match.sku}
+
+
+
${match.price}
+
+ {match.rating} stars · {Math.round(match.similarity * 100)}% match
+
+
+
+
+ ))}
+
+ >
+ )}
+
+ );
+}
+```
+
+## Testing
+
+Use the frontend to search interactively. If you need to call the endpoint directly:
+
+```bash
+curl "http://localhost:3500/products/search?q=comfortable%20office%20chair"
+curl "http://localhost:3500/products/search?q=laptop&category=electronics&maxPrice=1000"
+```
+
+## Key Points
+
+- **Semantic search** finds products by meaning, not just keywords
+- **Metadata filtering** narrows results by category, price, stock
+- **AI recommendations** add personalized guidance based on search context
+- **Customer feedback** in metadata helps AI make relevant suggestions
+- **Document field** should include searchable text (name + description)
+
+## See Also
+
+- [Vector Storage](/Build/Storage/vector) for all vector operations
+- [Build a RAG Agent](/Learn/Cookbook/Tutorials/rag-agent) for question-answering
+- [AI SDK Integration](/Build/Agents/ai-sdk-integration) for `generateObject` patterns
diff --git a/content/Learn/Cookbook/Patterns/server-utilities.mdx b/content/Learn/Cookbook/Patterns/server-utilities.mdx
new file mode 100644
index 00000000..cdd01ed6
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/server-utilities.mdx
@@ -0,0 +1,335 @@
+---
+title: SDK Utilities for External Apps
+description: Use storage, logging, error handling, and schema utilities from external backends like Next.js or Express
+---
+
+Use `@agentuity/server` and `@agentuity/core` utilities in external apps, scripts, or backends that integrate with Agentuity.
+
+## Storage Access
+
+Access Agentuity storage (KV, Vector, Stream) directly from your Next.js or Express backend using your SDK key.
+
+Add these environment variables to your `.env`:
+
+```bash title=".env.local"
+AGENTUITY_SDK_KEY=your_sdk_key # From Agentuity console or project .env
+AGENTUITY_REGION=use # From agentuity.json (region field)
+```
+
+
+Your region is in your Agentuity project's `agentuity.json` file. If you forget to set `AGENTUITY_REGION`, the SDK throws a helpful error telling you what's missing.
+
+
+```typescript title="lib/agentuity-storage.ts"
+import {
+ KeyValueStorageService,
+ VectorStorageService,
+ StreamStorageService,
+} from '@agentuity/core';
+import { createServerFetchAdapter, getServiceUrls, createLogger } from '@agentuity/server';
+
+const logger = createLogger('info');
+
+const adapter = createServerFetchAdapter({
+ headers: {
+ Authorization: `Bearer ${process.env.AGENTUITY_SDK_KEY}`,
+ },
+}, logger);
+
+const urls = getServiceUrls(process.env.AGENTUITY_REGION!);
+
+export const kv = new KeyValueStorageService(urls.catalyst, adapter);
+export const vector = new VectorStorageService(urls.catalyst, adapter);
+export const stream = new StreamStorageService(urls.stream, adapter);
+```
+
+Use the client in your Next.js backend:
+
+```typescript title="app/api/sessions/route.ts"
+import { type NextRequest } from 'next/server';
+import { kv } from '@/lib/agentuity-storage';
+
+interface ChatSession {
+ messages: Array<{ role: string; content: string }>;
+ createdAt: string;
+}
+
+export async function GET(request: NextRequest) {
+ const sessionId = request.nextUrl.searchParams.get('id');
+
+ if (!sessionId) {
+ return Response.json({ error: 'Missing session ID' }, { status: 400 });
+ }
+
+ const result = await kv.get('sessions', sessionId);
+
+ if (!result.exists) {
+ return Response.json({ error: 'Not found' }, { status: 404 });
+ }
+
+ return Response.json(result.data);
+}
+
+export async function POST(request: NextRequest) {
+ const { sessionId, messages } = await request.json();
+
+ await kv.set('sessions', sessionId, {
+ messages,
+ createdAt: new Date().toISOString(),
+ }, { ttl: 86400 });
+
+ return Response.json({ success: true });
+}
+```
+
+### Vector Storage
+
+```typescript title="app/api/search/route.ts"
+import { type NextRequest } from 'next/server';
+import { vector } from '@/lib/agentuity-storage';
+
+export async function POST(request: NextRequest) {
+ const { query, limit = 10 } = await request.json();
+
+ const results = await vector.search('documents', {
+ query,
+ limit,
+ });
+
+ return Response.json(results);
+}
+```
+
+### Stream Storage
+
+Use streams for large data exports or file transfers:
+
+```typescript title="app/api/export/route.ts"
+import { type NextRequest } from 'next/server';
+import { stream } from '@/lib/agentuity-storage';
+
+export async function GET(request: NextRequest) {
+ const id = request.nextUrl.searchParams.get('id');
+
+ if (!id) {
+ return Response.json({ error: 'Missing stream ID' }, { status: 400 });
+ }
+
+ const data = await stream.download(id);
+ return new Response(data, {
+ headers: { 'Content-Type': 'application/octet-stream' },
+ });
+}
+```
+
+## Alternative: HTTP Routes
+
+If you want to centralize storage logic in your Agentuity project (for [middleware](/Build/Routes/middleware), sharing across multiple apps, or avoiding SDK key distribution), use [HTTP routes](/Build/Routes/http) instead.
+
+```typescript title="src/api/sessions/route.ts"
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+interface ChatSession {
+ messages: Array<{ role: string; content: string }>;
+ createdAt: string;
+ updatedAt: string;
+}
+
+// Get a session by ID
+router.get('/:id', async (c) => {
+ const sessionId = c.req.param('id');
+ const result = await c.var.kv.get('sessions', sessionId); // [!code highlight]
+
+ if (!result.exists) {
+ return c.json({ error: 'Session not found' }, 404);
+ }
+
+ return c.json(result.data);
+});
+
+// Create or update a session
+router.post('/:id', async (c) => {
+ const sessionId = c.req.param('id');
+ const body = await c.req.json>();
+
+ const existing = await c.var.kv.get('sessions', sessionId);
+ const session: ChatSession = existing.exists
+ ? { ...existing.data, ...body, updatedAt: new Date().toISOString() }
+ : { messages: [], createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), ...body };
+
+ await c.var.kv.set('sessions', sessionId, session, { ttl: 86400 * 7 }); // [!code highlight]
+
+ c.var.logger.info('Session updated', { sessionId });
+ return c.json(session);
+});
+
+// Delete a session
+router.delete('/:id', async (c) => {
+ const sessionId = c.req.param('id');
+ await c.var.kv.delete('sessions', sessionId); // [!code highlight]
+
+ c.var.logger.info('Session deleted', { sessionId });
+ return c.json({ success: true });
+});
+
+export default router;
+```
+
+### Securing Storage Routes
+
+Add authentication middleware to protect storage endpoints:
+
+```typescript title="src/api/sessions/route.ts"
+import { createRouter, createMiddleware } from '@agentuity/runtime';
+
+const router = createRouter();
+
+const requireAuth = createMiddleware(async (c, next) => {
+ const apiKey = c.req.header('x-api-key');
+
+ if (!apiKey || apiKey !== process.env.STORAGE_API_KEY) {
+ c.var.logger.warn('Unauthorized storage access attempt');
+ return c.json({ error: 'Unauthorized' }, 401);
+ }
+
+ await next();
+});
+
+router.use('/*', requireAuth); // [!code highlight]
+
+// Routes now require x-api-key header
+router.get('/:id', async (c) => {
+ // ... same as above
+});
+
+export default router;
+```
+
+Routes also have access to `c.var.vector` and `c.var.stream` for Vector and Stream storage.
+
+## Logging with createLogger
+
+Create structured loggers for scripts or external services:
+
+```typescript
+import { createLogger } from '@agentuity/server';
+
+// Create a logger with info level, no timestamps, dark color scheme
+const logger = createLogger('info', false, 'dark');
+
+logger.info('Processing request', { userId: '123' });
+logger.error('Failed to connect', { error: err.message });
+
+// Child logger with persistent context
+const requestLogger = logger.child({ requestId: 'req_abc' });
+requestLogger.info('Starting'); // Includes requestId in all logs
+```
+
+**Parameters:**
+
+| Parameter | Type | Default | Description |
+|-----------|------|---------|-------------|
+| `level` | `'trace' \| 'debug' \| 'info' \| 'warn' \| 'error'` | `'info'` | Minimum log level |
+| `showTimestamp` | `boolean` | `false` | Include ISO timestamps |
+| `colorScheme` | `'light' \| 'dark'` | `'dark'` | Terminal color scheme |
+| `context` | `Record` | `{}` | Default context for all logs |
+
+## Safe JSON Serialization
+
+`safeStringify` handles circular references and BigInt values that break `JSON.stringify`:
+
+```typescript
+import { safeStringify } from '@agentuity/core';
+
+// Circular references become "[Circular]"
+const obj = { name: 'Alice' };
+obj.self = obj;
+safeStringify(obj); // '{"name":"Alice","self":"[Circular]"}'
+
+// BigInt converts to string
+safeStringify({ id: 9007199254740991n }); // '{"id":"9007199254740991"}'
+
+// Pretty-print with indentation
+safeStringify(data, 2);
+```
+
+## Error Handling Utilities
+
+### RichError
+
+Enhanced errors with context and pretty printing:
+
+```typescript
+import { RichError } from '@agentuity/core';
+
+const error = new RichError({
+ message: 'Request failed',
+ statusCode: 500,
+ endpoint: '/api/users',
+ cause: originalError,
+});
+
+error.plainArgs; // { statusCode: 500, endpoint: '/api/users' }
+error.cause; // originalError (the cause chain)
+error.prettyPrint(); // Formatted multi-line output with stack traces
+error.toJSON(); // Serializable object for logging
+error.toString(); // Same as prettyPrint()
+```
+
+### StructuredError
+
+Type-safe, discriminated errors with a `_tag` for pattern matching:
+
+```typescript
+import { StructuredError, isStructuredError } from '@agentuity/core';
+
+// Create error types
+const NotFoundError = StructuredError('NotFound');
+const ValidationError = StructuredError('ValidationError')<{
+ field: string;
+ code: string;
+}>();
+
+// With a default message (message is preset, cannot be overridden)
+const UpgradeRequired = StructuredError('UpgradeRequired', 'Upgrade required to access this feature');
+
+// Throw with context
+throw new ValidationError({
+ field: 'email',
+ code: 'INVALID_FORMAT',
+ message: 'Email format is invalid',
+});
+
+// Type-safe handling
+if (isStructuredError(err) && err._tag === 'ValidationError') {
+ logger.error('Validation failed', { field: err.field, code: err.code });
+}
+```
+
+## Schema Conversion
+
+Convert Zod or Agentuity schemas to JSON Schema for tooling or OpenAPI generation:
+
+```typescript
+import { toJSONSchema } from '@agentuity/server';
+import { z } from 'zod';
+
+const schema = z.object({ name: z.string(), age: z.number() });
+const jsonSchema = toJSONSchema(schema);
+// { type: 'object', properties: { name: { type: 'string' }, age: { type: 'number' } }, ... }
+```
+
+## Key Points
+
+- **Direct SDK** is the simplest way to access storage from external backends
+- **Required env vars**: `AGENTUITY_SDK_KEY` and `AGENTUITY_REGION` (from `agentuity.json`)
+- **HTTP routes** are an alternative for centralized logic, middleware, or sharing across apps
+- **Works with any framework**: Next.js, Express, Remix, etc.
+
+## See Also
+
+- [HTTP Routes](/Build/Routes/http): Route creation with `createRouter`
+- [Route Middleware](/Build/Routes/middleware): Authentication patterns
+- [RPC Client](/Build/Frontend/rpc-client): Typed client generation
diff --git a/content/Learn/Cookbook/Patterns/tailwind-setup.mdx b/content/Learn/Cookbook/Patterns/tailwind-setup.mdx
new file mode 100644
index 00000000..b9d6f011
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/tailwind-setup.mdx
@@ -0,0 +1,96 @@
+---
+title: Tailwind CSS Setup
+description: Add Tailwind CSS styling to your Agentuity frontend
+---
+
+Add [Tailwind CSS](https://tailwindcss.com) v4 to your Agentuity project using the official Tailwind Vite plugin.
+
+
+Use the Tailwind template for a pre-configured setup:
+
+```bash
+agentuity create my-app --template tailwind
+```
+
+
+## Prerequisites
+
+- An Agentuity project with a `src/web/` directory
+- Bun runtime (included with Agentuity CLI)
+
+## Step 1: Install Dependencies
+
+```bash
+bun add -D tailwindcss @tailwindcss/vite
+```
+
+## Step 2: Create Build Configuration
+
+Create `agentuity.config.ts` in your project root:
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+import tailwindcss from '@tailwindcss/vite';
+
+export default {
+ plugins: [tailwindcss()],
+} satisfies AgentuityConfig;
+```
+
+## Step 3: Import Tailwind in Your CSS
+
+Create or update your main CSS file (`src/web/styles.css`):
+
+```css
+@import 'tailwindcss';
+```
+
+Then import it in your entry point (`src/web/frontend.tsx`):
+
+```typescript
+import './styles.css';
+```
+
+## Step 4: Use Tailwind Classes
+
+Add utility classes to your React components:
+
+```tsx
+// src/web/App.tsx
+export function App() {
+ return (
+
+
+
+ Hello, Tailwind!
+
+
+ Your Agentuity frontend is styled with Tailwind CSS.
+
+
+
+ );
+}
+```
+
+## Step 5: Verify
+
+Start the dev server and check that styles are applied:
+
+```bash
+bun run dev
+```
+
+Open `http://localhost:3500` in your browser. You should see your styled component.
+
+## Key Points
+
+- Tailwind applies to frontend builds only (via Vite)
+- The plugin scans your components and generates only the CSS you use
+- No `tailwind.config.ts` needed for basic usage (Tailwind v4 works out of the box)
+- Style changes reflect immediately in dev mode via Vite HMR
+
+## Next Steps
+
+- [Build Configuration](/Reference/CLI/build-configuration): Explore all config options including plugins and define constants
+- [Frontend Development](/Build/Frontend/react-hooks): Connect your styled frontend to agents using React hooks
diff --git a/content/Learn/Cookbook/Patterns/webhook-handler.mdx b/content/Learn/Cookbook/Patterns/webhook-handler.mdx
new file mode 100644
index 00000000..5118c9ea
--- /dev/null
+++ b/content/Learn/Cookbook/Patterns/webhook-handler.mdx
@@ -0,0 +1,151 @@
+---
+title: Webhook Handler
+description: Handle incoming webhooks with signature verification and background processing
+---
+
+Process webhooks from external services (Stripe, GitHub, Slack) with proper signature verification and fast response times.
+
+## The Pattern
+
+Webhooks require quick responses (usually under 3 seconds). Use `waitUntil` to acknowledge immediately and process in the background.
+
+```typescript title="src/api/webhooks/route.ts"
+import { createRouter } from '@agentuity/runtime';
+import crypto from 'crypto';
+import paymentProcessor from '@agent/payment-processor';
+import subscriptionHandler from '@agent/subscription-handler';
+
+const router = createRouter();
+
+router.post('/stripe', async (c) => {
+ // Get raw body for signature verification
+ const rawBody = await c.req.text();
+ const signature = c.req.header('stripe-signature');
+
+ // Verify signature
+ const secret = process.env.STRIPE_WEBHOOK_SECRET;
+ if (!secret || !verifyStripeSignature(rawBody, signature, secret)) { // [!code highlight]
+ c.var.logger.warn('Invalid webhook signature');
+ return c.text('Invalid signature', 401);
+ }
+
+ const event = JSON.parse(rawBody);
+ c.var.logger.info('Webhook received', { type: event.type });
+
+ // Process in background, respond immediately
+ c.waitUntil(async () => { // [!code highlight]
+ try {
+ switch (event.type) {
+ case 'payment_intent.succeeded':
+ await paymentProcessor.run({
+ paymentId: event.data.object.id,
+ amount: event.data.object.amount,
+ customerId: event.data.object.customer,
+ });
+ break;
+
+ case 'customer.subscription.updated':
+ await subscriptionHandler.run({
+ subscriptionId: event.data.object.id,
+ status: event.data.object.status,
+ });
+ break;
+
+ default:
+ c.var.logger.debug('Unhandled event type', { type: event.type });
+ }
+ } catch (error) {
+ c.var.logger.error('Webhook processing failed', { error, eventType: event.type });
+ // Store for retry
+ await c.var.kv.set('failed-webhooks', event.id, {
+ event,
+ error: String(error),
+ timestamp: Date.now(),
+ }, { ttl: 86400 }); // 24 hours
+ }
+ });
+
+ // Return 200 immediately
+ return c.json({ received: true }); // [!code highlight]
+});
+
+function verifyStripeSignature(
+ payload: string,
+ signature: string | undefined,
+ secret: string
+): boolean {
+ if (!signature) return false;
+
+ const parts = signature.split(',').reduce((acc, part) => {
+ const [key, value] = part.split('=');
+ acc[key] = value;
+ return acc;
+ }, {} as Record);
+
+ const timestamp = parts['t'];
+ const expectedSig = parts['v1'];
+
+ const signedPayload = `${timestamp}.${payload}`;
+ const computedSig = crypto
+ .createHmac('sha256', secret)
+ .update(signedPayload)
+ .digest('hex');
+
+ return crypto.timingSafeEqual(
+ Buffer.from(expectedSig),
+ Buffer.from(computedSig)
+ );
+}
+
+export default router;
+```
+
+## Slack Webhook Example
+
+```typescript title="src/api/webhooks/route.ts"
+import slackHandler from '@agent/slack-handler';
+
+router.post('/slack', async (c) => {
+ // Slack retries on failure - skip duplicates
+ if (c.req.header('x-slack-retry-num')) {
+ return c.text('OK');
+ }
+
+ const rawBody = await c.req.text();
+
+ // Verify Slack signature
+ const timestamp = c.req.header('x-slack-request-timestamp');
+ const signature = c.req.header('x-slack-signature');
+ const secret = process.env.SLACK_SIGNING_SECRET;
+
+ if (!verifySlackSignature(rawBody, timestamp, signature, secret)) {
+ return c.text('Invalid signature', 401);
+ }
+
+ const payload = JSON.parse(rawBody);
+
+ // Handle URL verification challenge
+ if (payload.type === 'url_verification') {
+ return c.text(payload.challenge);
+ }
+
+ // Process event in background
+ c.waitUntil(async () => { // [!code highlight]
+ await slackHandler.run(payload);
+ });
+
+ return c.text('OK');
+});
+```
+
+## Key Points
+
+- **Raw body first**: Read body as text before parsing for signature verification
+- **Fast response**: Return 200 immediately, process with `waitUntil`
+- **Error handling**: Store failed webhooks for retry/debugging
+- **Signature verification**: Always verify webhooks from external services
+
+## See Also
+
+- [HTTP Routes](/Build/Routes/http) for route patterns
+- [Background Tasks](/Build/Agents/calling-other-agents#background-execution) for `waitUntil`
diff --git a/content/Learn/Cookbook/Tutorials/meta.json b/content/Learn/Cookbook/Tutorials/meta.json
new file mode 100644
index 00000000..2b52607c
--- /dev/null
+++ b/content/Learn/Cookbook/Tutorials/meta.json
@@ -0,0 +1,7 @@
+{
+ "title": "Tutorials",
+ "pages": [
+ "understanding-agents",
+ "rag-agent"
+ ]
+}
diff --git a/content/Learn/Cookbook/Tutorials/rag-agent.mdx b/content/Learn/Cookbook/Tutorials/rag-agent.mdx
new file mode 100644
index 00000000..b3467ccb
--- /dev/null
+++ b/content/Learn/Cookbook/Tutorials/rag-agent.mdx
@@ -0,0 +1,383 @@
+---
+title: Build a RAG Agent
+description: Create a retrieval-augmented generation agent with vector search and citations
+---
+
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+
+This tutorial walks through building a RAG (Retrieval-Augmented Generation) agent that answers questions using your own knowledge base.
+
+## What You'll Build
+
+A question-answering agent that:
+- Searches a vector database for relevant content
+- Uses retrieved documents as context for the LLM
+- Returns answers with source citations
+- Handles cases where no relevant information is found
+
+## Prerequisites
+
+- An Agentuity project ([Quickstart](/Get-Started/quickstart) if you need one)
+- Basic familiarity with [Vector Storage](/Build/Storage/vector)
+
+## Project Structure
+
+```
+src/agent/knowledge/
+└── agent.ts # RAG agent logic
+src/api/
+└── index.ts # HTTP endpoint
+```
+
+
+
+
+## Create the Agent
+
+When a user asks a question, the agent needs to:
+
+1. Search the vector database for relevant documents
+2. Build context from the search results
+3. Generate an answer using the LLM with that context
+4. Return the answer with source citations
+
+```typescript title="src/agent/knowledge/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+const agent = createAgent('Knowledge Agent', {
+ description: 'Answers questions using a knowledge base',
+ schema: {
+ input: z.object({
+ question: z.string().describe('The question to answer'),
+ }),
+ output: z.object({
+ answer: z.string(),
+ sources: z.array(z.object({
+ id: z.string(),
+ title: z.string(),
+ relevance: z.number(),
+ })),
+ confidence: z.number().min(0).max(1),
+ }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Searching knowledge base', { question: input.question });
+
+ // Search for relevant documents
+ const results = await ctx.vector.search('knowledge-base', { // [!code highlight]
+ query: input.question, // [!code highlight]
+ limit: 5,
+ similarity: 0.7, // [!code highlight]
+ });
+
+ // Handle no results
+ if (results.length === 0) {
+ ctx.logger.info('No relevant documents found');
+ return {
+ answer: "I couldn't find relevant information to answer your question.",
+ sources: [],
+ confidence: 0,
+ };
+ }
+
+ // Build context from search results
+ const context = results // [!code highlight]
+ .map((r, i) => `[${i + 1}] ${r.document}`) // [!code highlight]
+ .join('\n\n');
+
+ ctx.logger.debug('Built context from documents', {
+ documentCount: results.length
+ });
+
+ // Generate answer with LLM
+ const { text } = await generateText({
+ model: openai('gpt-5-mini'),
+ system: `You are a helpful assistant that answers questions based on provided context.
+Only use information from the context. If the context doesn't contain the answer, say so.
+Cite sources using [1], [2], etc. when referencing specific information.`,
+ prompt: `Context:
+${context}
+
+Question: ${input.question}
+
+Answer the question using only the provided context. Cite your sources.`,
+ });
+
+ // Calculate confidence from average similarity
+ const avgSimilarity = results.reduce((sum, r) => sum + r.similarity, 0) / results.length;
+
+ return {
+ answer: text,
+ sources: results.map((r, i) => ({
+ id: r.key,
+ title: (r.metadata?.title as string) || `Document ${i + 1}`,
+ relevance: r.similarity,
+ })),
+ confidence: avgSimilarity,
+ };
+ },
+});
+
+export default agent;
+```
+
+
+
+## Create the Route
+
+The route exposes your agent over HTTP. Use `agent.validator()` for type-safe validation using the agent's schema.
+
+```typescript title="src/api/index.ts"
+import { createRouter } from '@agentuity/runtime';
+import knowledgeAgent from '@agent/knowledge';
+
+const router = createRouter();
+
+// Query endpoint - validates using agent's input schema
+router.post('/knowledge', knowledgeAgent.validator(), async (c) => { // [!code highlight]
+ const { question } = c.req.valid('json'); // [!code highlight]
+ const result = await knowledgeAgent.run({ question }); // [!code highlight]
+ return c.json(result);
+});
+
+// Health check
+router.get('/health', (c) => c.text('OK'));
+
+export default router;
+```
+
+
+
+## Add an Indexing Agent
+
+Before you can query your knowledge base, you need to populate it. A separate indexing agent handles this by:
+
+1. Accepting an array of documents
+2. Storing each document in the vector database with metadata
+3. Returning the count and IDs of indexed documents
+
+```typescript title="src/agent/indexer/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const DocumentSchema = z.object({
+ id: z.string(),
+ title: z.string(),
+ content: z.string(),
+ category: z.string().optional(),
+});
+
+const agent = createAgent('Document Indexer', {
+ description: 'Indexes documents into the knowledge base',
+ schema: {
+ input: z.object({
+ documents: z.array(DocumentSchema),
+ }),
+ output: z.object({
+ indexed: z.number(),
+ ids: z.array(z.string()),
+ }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Indexing documents', { count: input.documents.length });
+
+ const ids: string[] = [];
+
+ for (const doc of input.documents) {
+ await ctx.vector.upsert('knowledge-base', { // [!code highlight]
+ key: doc.id, // [!code highlight]
+ document: doc.content, // [!code highlight]
+ metadata: {
+ title: doc.title,
+ category: doc.category,
+ indexedAt: new Date().toISOString(),
+ },
+ });
+ ids.push(doc.id);
+ }
+
+ ctx.logger.info('Indexing complete', { indexed: ids.length });
+
+ return {
+ indexed: ids.length,
+ ids,
+ };
+ },
+});
+
+export default agent;
+```
+
+
+
+## Test Your Agent
+
+With both agents created, you can test the full flow: index some documents, then query them.
+
+Start the dev server:
+
+```bash
+agentuity dev
+```
+
+Index some test documents:
+
+```bash
+curl -X POST http://localhost:3500/indexer \
+ -H "Content-Type: application/json" \
+ -d '{
+ "documents": [
+ {
+ "id": "doc-1",
+ "title": "Getting Started",
+ "content": "Agentuity is a full-stack platform for building AI agents. You can create agents using TypeScript and deploy them with a single command."
+ },
+ {
+ "id": "doc-2",
+ "title": "Storage Options",
+ "content": "Agentuity provides three storage options: key-value for simple data, vector for semantic search, and object storage for files."
+ }
+ ]
+ }'
+```
+
+Query the knowledge base:
+
+```bash
+curl -X POST http://localhost:3500/knowledge \
+ -H "Content-Type: application/json" \
+ -d '{"question": "What storage options does Agentuity provide?"}'
+```
+
+Expected response:
+
+```json
+{
+ "answer": "Agentuity provides three storage options [2]: key-value storage for simple data, vector storage for semantic search, and object storage for files.",
+ "sources": [
+ { "id": "doc-2", "title": "Storage Options", "relevance": 0.89 }
+ ],
+ "confidence": 0.89
+}
+```
+
+### Frontend
+
+Build a search interface for your knowledge base:
+
+```tsx title="src/web/App.tsx"
+import { useAPI } from '@agentuity/react';
+import { useState } from 'react';
+
+interface Source {
+ id: string;
+ title: string;
+ relevance: number;
+}
+
+interface KnowledgeResult {
+ answer: string;
+ sources: Source[];
+ confidence: number;
+}
+
+export function App() {
+ const [question, setQuestion] = useState('');
+ const { data, invoke, isLoading } = useAPI('POST /knowledge'); // [!code highlight]
+
+ return (
+
+
Knowledge Search
+
+
+ setQuestion(e.target.value)}
+ onKeyDown={(e) => e.key === 'Enter' && invoke({ question })}
+ placeholder="Ask a question..."
+ disabled={isLoading}
+ style={{ flex: 1, padding: '0.75rem' }}
+ />
+ invoke({ question })}
+ disabled={isLoading || !question.trim()}
+ >
+ {isLoading ? 'Searching...' : 'Search'}
+
+
+
+ {data && (
+
+ {/* Answer */}
+
+
+ {/* Confidence */}
+
+ Confidence: {Math.round(data.confidence * 100)}%
+
+
+ {/* Sources */}
+ {data.sources.length > 0 && (
+
+
Sources
+
+ {data.sources.map((source) => (
+
+ {source.title}
+
+ ({Math.round(source.relevance * 100)}% relevant)
+
+
+ ))}
+
+
+ )}
+
+ )}
+
+ );
+}
+```
+
+Wrap your app with `AgentuityProvider`:
+
+```tsx title="src/web/frontend.tsx"
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import { AgentuityProvider } from '@agentuity/react';
+import { App } from './App';
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+);
+```
+
+
+
+
+## Summary
+
+| Concept | Description |
+|---------|-------------|
+| **Vector Search** | Find semantically similar documents using `ctx.vector.search()` |
+| **Context Building** | Format search results into LLM-readable context with citations |
+| **Similarity Threshold** | Filter results by minimum similarity score (e.g., 0.7) |
+| **Confidence Score** | Calculate from average similarity of retrieved documents |
+| **Indexing Agent** | Separate agent to populate the vector database with documents |
+
+## Next Steps
+
+- Add an [evaluation](/Build/Agents/evaluations) to check answer quality
+- Implement [streaming](/Build/Agents/streaming-responses) for longer responses
+- Add metadata filtering to search specific categories
+- See the [Vector Storage](/Build/Storage/vector) guide for advanced search options
diff --git a/content/Learn/Cookbook/Tutorials/understanding-agents.mdx b/content/Learn/Cookbook/Tutorials/understanding-agents.mdx
new file mode 100644
index 00000000..e862a785
--- /dev/null
+++ b/content/Learn/Cookbook/Tutorials/understanding-agents.mdx
@@ -0,0 +1,303 @@
+---
+title: Understanding How Agents Work
+description: Learn how AI agents use tools, run in loops with stopping conditions, and leverage LLMs to complete tasks autonomously
+---
+
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+
+This tutorial explains the core concepts that make AI agents "agentic": the ability to use tools, reason about results, and loop until a task is complete.
+
+## What Makes an Agent "Agentic"?
+
+A simple LLM call takes input and returns output. An **agent** goes further: it can decide to take actions, observe results, and continue working until the task is done.
+
+The agent loop follows this pattern:
+
+1. **Plan**: The LLM receives a prompt and decides what to do
+2. **Act**: If the LLM needs data, it requests a tool call
+3. **Observe**: The tool executes and returns results
+4. **Repeat**: The LLM sees the results and decides: respond to the user, or call another tool?
+
+This loop continues until the LLM has enough information to answer, or a stopping condition is reached.
+
+## What You'll Build
+
+A research agent that:
+- Accepts a topic from the user
+- Searches Wikipedia for relevant information
+- Summarizes findings and returns a response
+- Demonstrates the agent loop in action
+
+## Prerequisites
+
+- An Agentuity project ([Quickstart](/Get-Started/quickstart) if you need one)
+- Basic familiarity with [AI SDK Integration](/Build/Agents/ai-sdk-integration)
+
+## Project Structure
+
+```
+src/agent/researcher/
+└── agent.ts # Research agent with tools
+src/api/
+└── index.ts # HTTP endpoint
+```
+
+
+
+
+## Define a Tool
+
+Tools are functions the LLM can call. Each tool has three parts:
+
+1. **Description**: Tells the LLM when to use this tool
+2. **Input Schema**: Defines what parameters the tool accepts
+3. **Execute Function**: The actual code that runs
+
+```typescript
+import { tool } from 'ai';
+import { z } from 'zod';
+
+const searchWikipedia = tool({
+ description: 'Search Wikipedia for information on a topic', // [!code highlight]
+ inputSchema: z.object({ // [!code highlight]
+ query: z.string().describe('The search query'), // [!code highlight]
+ }), // [!code highlight]
+ execute: async ({ query }) => { // [!code highlight]
+ const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&format=json&origin=*&srlimit=3`;
+ const response = await fetch(url);
+ const data = await response.json();
+
+ return data.query.search.map((result: any) => ({
+ title: result.title,
+ snippet: result.snippet.replace(/<[^>]*>/g, ''), // Strip HTML tags
+ pageId: result.pageid,
+ }));
+ },
+});
+```
+
+The schema is converted to JSON and sent to the LLM, which uses the description and parameter definitions to understand when and how to call the tool.
+
+
+
+## Create the Agent with Tools
+
+The AI SDK's `generateText` function orchestrates the agent loop automatically. When you provide tools, it handles the back-and-forth between the LLM and tool execution.
+
+```typescript title="src/agent/researcher/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { generateText, tool, stepCountIs } from 'ai';
+import { openai } from '@ai-sdk/openai';
+import { z } from 'zod';
+
+// Define the search tool
+const searchWikipedia = tool({
+ description: 'Search Wikipedia for information on a topic',
+ inputSchema: z.object({
+ query: z.string().describe('The search query'),
+ }),
+ execute: async ({ query }) => {
+ const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&format=json&origin=*&srlimit=3`;
+ const response = await fetch(url);
+ const data = await response.json();
+
+ return data.query.search.map((result: any) => ({
+ title: result.title,
+ snippet: result.snippet.replace(/<[^>]*>/g, ''), // Strip HTML tags
+ pageId: result.pageid,
+ }));
+ },
+});
+
+const agent = createAgent('Research Agent', {
+ description: 'Researches topics using Wikipedia',
+ schema: {
+ input: z.object({ topic: z.string() }),
+ output: z.object({ summary: z.string(), sourcesUsed: z.number() }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info('Starting research', { topic: input.topic });
+
+ const result = await generateText({
+ model: openai('gpt-5-mini'),
+ system: `You are a research assistant. Use the search tool to find information,
+then synthesize what you learn into a helpful summary. Always search before answering.`,
+ prompt: `Research this topic and provide a summary: ${input.topic}`,
+ tools: { searchWikipedia }, // [!code highlight]
+ stopWhen: stepCountIs(5), // [!code highlight]
+ });
+
+ ctx.logger.info('Research complete', {
+ steps: result.steps.length,
+ toolCalls: result.toolCalls.length,
+ });
+
+ return {
+ summary: result.text,
+ sourcesUsed: result.toolCalls.length,
+ };
+ },
+});
+
+export default agent;
+```
+
+
+
+## Understanding the Loop
+
+When you call `generateText` with tools, here's what happens:
+
+1. **Initial Request**: The LLM receives the prompt, system message, and tool definitions
+2. **Decision**: The LLM analyzes the request and decides to call `searchWikipedia`
+3. **Tool Execution**: The AI SDK validates parameters and runs the `execute` function
+4. **Result Injection**: Tool results are added to the conversation
+5. **Continue or Finish**: The LLM sees results and either calls another tool or returns a final response
+
+The `stopWhen` option controls when the loop ends. Use `stepCountIs(n)` to limit iterations and prevent runaway agents:
+
+```typescript
+import { generateText, stepCountIs } from 'ai';
+
+const result = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: 'Research quantum computing',
+ tools: { searchWikipedia },
+ stopWhen: stepCountIs(5), // [!code highlight]
+});
+
+// Inspect what happened
+ctx.logger.info(`Completed in ${result.steps.length} steps`);
+ctx.logger.info(`Made ${result.toolCalls.length} tool calls`);
+```
+
+You can combine multiple stopping conditions. The loop stops when any condition is met:
+
+```typescript
+import { generateText, stepCountIs, hasToolCall } from 'ai';
+
+const result = await generateText({
+ model: openai('gpt-5-mini'),
+ prompt: 'Research quantum computing',
+ tools: { searchWikipedia },
+ stopWhen: [stepCountIs(10), hasToolCall('searchWikipedia')], // [!code highlight]
+});
+```
+
+
+
+## Add the Route
+
+Create an HTTP endpoint to call your agent:
+
+```typescript title="src/api/index.ts"
+import { createRouter } from '@agentuity/runtime';
+import researchAgent from '@agent/researcher';
+
+const router = createRouter();
+
+router.post('/research', researchAgent.validator(), async (c) => { // [!code highlight]
+ const { topic } = c.req.valid('json'); // [!code highlight]
+ const result = await researchAgent.run({ topic }); // [!code highlight]
+ return c.json(result);
+});
+
+export default router;
+```
+
+
+
+## Test It
+
+Start the dev server:
+
+```bash
+agentuity dev
+```
+
+### Using curl
+
+```bash
+curl -X POST http://localhost:3500/research \
+ -H "Content-Type: application/json" \
+ -d '{"topic": "how do AI agents work"}'
+```
+
+### Frontend
+
+Create a simple frontend to interact with your agent:
+
+```tsx title="src/web/App.tsx"
+import { useAPI } from '@agentuity/react';
+import { useState } from 'react';
+
+export function App() {
+ const [topic, setTopic] = useState('');
+ const { data, invoke, isLoading } = useAPI('POST /research'); // [!code highlight]
+
+ return (
+
+
Research Agent
+
+
+ setTopic(e.target.value)}
+ placeholder="Enter a topic to research"
+ disabled={isLoading}
+ style={{ flex: 1, padding: '0.5rem' }}
+ />
+ invoke({ topic })} disabled={isLoading || !topic}>
+ {isLoading ? 'Researching...' : 'Research'}
+
+
+
+ {data && (
+
+
{data.summary}
+
Sources used: {data.sourcesUsed}
+
+ )}
+
+ );
+}
+```
+
+Wrap your app with `AgentuityProvider` in the entry point:
+
+```tsx title="src/web/frontend.tsx"
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import { AgentuityProvider } from '@agentuity/react';
+import { App } from './App';
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+);
+```
+
+Check the logs to see the agent loop in action: the search tool being called, results being processed, and the final summary being generated.
+
+
+
+
+## Summary
+
+| Concept | Description |
+|---------|-------------|
+| **Tool** | A function the LLM can call, defined with `inputSchema` and `execute` |
+| **Agent Loop** | Plan → Act → Observe → Repeat until done |
+| **stopWhen** | Controls when the loop ends (e.g., `stepCountIs(5)`) |
+| **stepCountIs** | Built-in condition to limit loop iterations |
+| **generateText** | AI SDK function that orchestrates the loop automatically |
+
+## Next Steps
+
+- [AI SDK Integration](/Build/Agents/ai-sdk-integration): More patterns for tool use and streaming
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Build multi-agent systems
+- [Evaluations](/Build/Agents/evaluations): Test agent output quality
diff --git a/content/Learn/Cookbook/meta.json b/content/Learn/Cookbook/meta.json
new file mode 100644
index 00000000..ed9e09f5
--- /dev/null
+++ b/content/Learn/Cookbook/meta.json
@@ -0,0 +1,8 @@
+{
+ "title": "Cookbook",
+ "pages": [
+ "overview",
+ "Tutorials",
+ "Patterns"
+ ]
+}
diff --git a/content/Learn/Cookbook/overview.mdx b/content/Learn/Cookbook/overview.mdx
new file mode 100644
index 00000000..5e0c68f3
--- /dev/null
+++ b/content/Learn/Cookbook/overview.mdx
@@ -0,0 +1,41 @@
+---
+title: Overview
+description: Tutorials and patterns for building with Agentuity
+---
+
+import { Card, Cards } from 'fumadocs-ui/components/card';
+import { Bot, Database, KeyRound } from 'lucide-react';
+
+## Tutorials
+
+Step-by-step guides that build complete features from scratch.
+
+
+ }
+ >
+ Learn how agents use tools and run in loops to complete tasks
+
+ }
+ >
+ Retrieval-augmented generation with vector search and citations
+
+
+
+## Patterns
+
+Copy-paste solutions for common tasks.
+
+- [Background Tasks](/Learn/Cookbook/Patterns/background-tasks) — Use `waitUntil` for fire-and-forget work
+- [Chat with Conversation History](/Learn/Cookbook/Patterns/chat-with-history) — Maintain conversation context using thread state
+- [Cron with Storage](/Learn/Cookbook/Patterns/cron-with-storage) — Cache scheduled task results in KV for later retrieval
+- [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities) — Use storage, logging, and error handling from Next.js or external backends
+- [Product Search with Vector](/Learn/Cookbook/Patterns/product-search) — Semantic search with metadata filtering
+- [Tailwind CSS Setup](/Learn/Cookbook/Patterns/tailwind-setup) — Add Tailwind styling to your frontend
+- [Webhook Handler](/Learn/Cookbook/Patterns/webhook-handler) — Process external webhooks with signature verification
+
diff --git a/content/Learn/meta.json b/content/Learn/meta.json
new file mode 100644
index 00000000..51632bc1
--- /dev/null
+++ b/content/Learn/meta.json
@@ -0,0 +1,6 @@
+{
+ "title": "Learn",
+ "pages": [
+ "Cookbook"
+ ]
+}
diff --git a/content/Reference/CLI/ai-commands.mdx b/content/Reference/CLI/ai-commands.mdx
new file mode 100644
index 00000000..b5930eb5
--- /dev/null
+++ b/content/Reference/CLI/ai-commands.mdx
@@ -0,0 +1,147 @@
+---
+title: AI Commands
+description: CLI commands for AI agents, IDE integration, and schema inspection.
+---
+
+AI coding agents and IDE extensions work best when they understand your tools programmatically. These commands expose the CLI's structure, capabilities, and project context in machine-readable formats.
+
+## CLI Capabilities
+
+Show the CLI's capabilities in a structured format for AI consumption:
+
+```bash
+agentuity ai capabilities show
+```
+
+This outputs a machine-readable description of what the CLI can do, useful for:
+- AI coding agents that need to understand available commands
+- IDE extensions building Agentuity integrations
+- Documentation generators
+
+## Schema Inspection
+
+Output the CLI's command schema for programmatic consumption:
+
+```bash
+# Show the full CLI schema
+agentuity ai schema show
+
+# Generate schema in a specific format
+agentuity ai schema generate
+```
+
+The schema includes:
+- All available commands and subcommands
+- Required and optional parameters
+- Parameter types and validation rules
+- Command descriptions and examples
+
+## Agent Skills Generation
+
+Generate [Agent Skills](https://agentskills.io) documentation from the CLI schema:
+
+```bash
+# Generate SKILL.md files
+agentuity ai skills generate
+
+# Output to custom directory
+agentuity ai skills generate --output ./skills
+```
+
+This creates machine-readable skill definitions that enable coding agents (e.g., Claude Code, Cursor, Codex) to discover and use Agentuity CLI capabilities.
+
+**Generated files:**
+- `SKILL.md` files with YAML frontmatter for each command
+- `README.md` with a skill index
+
+
+In dev mode (`agentuity dev`), skills are automatically regenerated when the CLI version changes.
+
+
+## Project Context Files
+
+During development (`agentuity dev` or `bun run dev`), the CLI generates AGENTS.md files to help AI coding assistants (e.g., Claude Code, Codex, Cursor) understand Agentuity patterns:
+
+```
+.agents/
+└── agentuity/
+ └── sdk/
+ ├── agent/AGENTS.md # Agent creation patterns
+ ├── api/AGENTS.md # Route creation patterns
+ └── web/AGENTS.md # Frontend patterns
+```
+
+These files are auto-updated when the CLI version changes and should be added to `.gitignore`.
+
+## Prompt Generation
+
+Generate context-aware prompts for LLMs working with Agentuity projects:
+
+```bash
+# Generate prompt for building agents
+agentuity ai prompt agent
+
+# Generate prompt for building APIs
+agentuity ai prompt api
+
+# Generate general LLM prompt
+agentuity ai prompt llm
+
+# Generate prompt for web/frontend development
+agentuity ai prompt web
+```
+
+Each prompt type includes:
+- Relevant SDK patterns and best practices
+- Code examples for the target domain
+- Common pitfalls to avoid
+- Links to documentation
+
+
+These prompts are useful for:
+- Bootstrapping AI coding sessions with Agentuity context
+- Training custom AI assistants on Agentuity patterns
+- Generating project-specific documentation
+
+
+## Integration Examples
+
+### IDE Extension
+
+Use the CLI to provide autocomplete, validation, and project configuration help:
+
+```typescript
+// Get CLI capabilities for IDE integration
+const { execSync } = require('child_process');
+
+const capabilities = JSON.parse(
+ execSync('agentuity --json ai capabilities show').toString()
+);
+
+// Use capabilities to build autocomplete, validation, etc.
+```
+
+```typescript
+// Get agentuity.json schema for configuration validation
+const schema = JSON.parse(
+ execSync('agentuity --json ai schema generate').toString()
+);
+
+// Use schema to validate project configuration files
+```
+
+### AI Coding Agent
+
+```bash
+# Generate context for an AI agent working on your project
+agentuity ai prompt agent > /tmp/agentuity-context.md
+
+# Include in your AI agent's system prompt
+cat /tmp/agentuity-context.md
+```
+
+## Next Steps
+
+- [Getting Started with the CLI](/Reference/CLI/getting-started): Install and authenticate
+- [Local Development](/Reference/CLI/development): Run agents locally
+- [Creating Agents](/Build/Agents/creating-agents): Build your first agent
diff --git a/content/Reference/CLI/build-configuration.mdx b/content/Reference/CLI/build-configuration.mdx
new file mode 100644
index 00000000..7aecae4f
--- /dev/null
+++ b/content/Reference/CLI/build-configuration.mdx
@@ -0,0 +1,140 @@
+---
+title: Build Configuration
+description: Customize the build process with Vite plugins and build-time constants
+---
+
+Customize how your project is built by creating an `agentuity.config.ts` file in your project root. Add Vite plugins for frontend builds or define build-time constants.
+
+## Basic Configuration
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ // Configuration options here
+} satisfies AgentuityConfig;
+```
+
+## Configuration Options
+
+### plugins
+
+Add Vite plugins for frontend builds (`src/web/`). Plugins run after built-in plugins (React, environment variables).
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+import tailwindcss from '@tailwindcss/vite';
+
+export default {
+ plugins: [tailwindcss()],
+} satisfies AgentuityConfig;
+```
+
+See the [Vite plugin documentation](https://vitejs.dev/plugins/) for available plugins.
+
+
+Vite plugins apply to frontend builds only. Server code is bundled separately with Bun.
+
+
+### define
+
+Replace identifiers with constant values at build time. Values must be JSON-stringified.
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ define: {
+ 'API_VERSION': JSON.stringify('v2'),
+ '__DEV__': JSON.stringify(false),
+ },
+} satisfies AgentuityConfig;
+```
+
+
+These keys are set by the build system and will override any user-defined values:
+- `import.meta.env.AGENTUITY_PUBLIC_*` (Agentuity internal variables)
+- `process.env.NODE_ENV`
+
+
+### workbench
+
+Configure the development Workbench UI. See [Testing with Workbench](/Build/Agents/workbench) for usage.
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+
+export default {
+ workbench: {
+ route: '/workbench', // Access at http://localhost:3500/workbench
+ headers: {}, // Custom headers for requests
+ },
+} satisfies AgentuityConfig;
+```
+
+Omit the `workbench` section to disable Workbench.
+
+## Environment Variables
+
+Environment variables with these prefixes are available in frontend code:
+
+| Prefix | Description |
+|--------|-------------|
+| `VITE_*` | Standard Vite convention |
+| `AGENTUITY_PUBLIC_*` | Agentuity convention |
+| `PUBLIC_*` | Short form |
+
+```typescript
+// .env.local
+AGENTUITY_PUBLIC_API_URL=https://api.example.com
+
+// src/web/App.tsx
+const apiUrl = import.meta.env.AGENTUITY_PUBLIC_API_URL;
+```
+
+
+Public environment variables are bundled into frontend code and visible in the browser. Never put secrets or API keys in public variables.
+
+
+## Build Architecture
+
+Agentuity uses a hybrid build system:
+
+| Component | Tool | Output |
+|-----------|------|--------|
+| Frontend (`src/web/`) | Vite | `.agentuity/client/` |
+| Workbench | Vite | `.agentuity/workbench/` |
+| Server (agents, routes) | Bun | `.agentuity/app.js` |
+
+This separation allows Vite's optimizations for frontend (HMR, tree-shaking, CSS processing) while using Bun's fast bundling for server code.
+
+For details on how these components interact during development, see [Dev Server Architecture](/Reference/CLI/development#dev-server-architecture).
+
+## Full Example
+
+```typescript
+import type { AgentuityConfig } from '@agentuity/cli';
+import tailwindcss from '@tailwindcss/vite';
+
+export default {
+ // Vite plugins for frontend
+ plugins: [tailwindcss()],
+
+ // Build-time constants
+ define: {
+ 'APP_VERSION': JSON.stringify('1.0.0'),
+ },
+
+ // Development workbench
+ workbench: {
+ route: '/workbench',
+ headers: {},
+ },
+} satisfies AgentuityConfig;
+```
+
+## Next Steps
+
+- [Tailwind CSS Setup](/Learn/Cookbook/Patterns/tailwind-setup): Add Tailwind styling to your frontend
+- [Development Server](/Reference/CLI/development): Run the dev server with your configuration
+- [Deployment](/Reference/CLI/deployment): Deploy with build configuration
diff --git a/content/Reference/CLI/configuration.mdx b/content/Reference/CLI/configuration.mdx
new file mode 100644
index 00000000..812c850b
--- /dev/null
+++ b/content/Reference/CLI/configuration.mdx
@@ -0,0 +1,177 @@
+---
+title: Configuration Commands
+description: Manage environment variables, secrets, and API keys from the CLI.
+---
+
+These CLI commands help you manage configuration values for your deployed agents.
+
+
+All configuration commands require the `cloud` prefix. For example: `agentuity cloud env list`
+
+
+## Environment Variables
+
+Manage non-sensitive configuration values.
+
+### List Variables
+
+```bash
+agentuity cloud env list
+```
+
+### Get a Variable
+
+```bash
+agentuity cloud env get NODE_ENV
+```
+
+### Set a Variable
+
+```bash
+agentuity cloud env set NODE_ENV production
+agentuity cloud env set API_URL https://api.example.com
+```
+
+### Delete a Variable
+
+```bash
+agentuity cloud env delete OLD_CONFIG
+```
+
+### Push from Local File
+
+Upload variables from `.env.production` (or `.env`) to cloud:
+
+```bash
+agentuity cloud env push
+```
+
+This filters out `AGENTUITY_` prefixed keys automatically.
+
+### Pull to Local File
+
+Download cloud variables to `.env.production`:
+
+```bash
+# Merge with local (local values take priority)
+agentuity cloud env pull
+
+# Overwrite local with cloud values
+agentuity cloud env pull --force
+```
+
+### Import from File
+
+```bash
+agentuity cloud env import .env.staging
+```
+
+
+Use `cloud secret` for sensitive values like API keys and database passwords. Use `cloud env` for non-sensitive configuration like feature flags and URLs.
+
+
+## Secrets
+
+Manage sensitive values like API keys and tokens. Commands mirror `cloud env`.
+
+### List Secrets
+
+```bash
+agentuity cloud secret list
+```
+
+### Get a Secret
+
+```bash
+agentuity cloud secret get API_KEY
+```
+
+### Set a Secret
+
+```bash
+agentuity cloud secret set API_KEY "sk_live_..."
+agentuity cloud secret set DATABASE_URL "postgresql://..."
+```
+
+### Delete a Secret
+
+```bash
+agentuity cloud secret delete OLD_TOKEN
+```
+
+### Push/Pull
+
+```bash
+# Push from local file
+agentuity cloud secret push
+
+# Pull to local file
+agentuity cloud secret pull
+agentuity cloud secret pull --force
+```
+
+### Import from File
+
+```bash
+agentuity cloud secret import .env.secrets
+```
+
+**In agents:** Access secrets via `process.env.API_KEY`. Secrets are injected at runtime and never logged.
+
+## API Keys
+
+Create and manage API keys for programmatic access to your project.
+
+### Create an API Key
+
+```bash
+# With 1 year expiration
+agentuity cloud apikey create --name "Production Key" --expires-at 1y
+
+# With 30 day expiration
+agentuity cloud apikey create --name "Short-lived Key" --expires-at 30d
+
+# With specific date
+agentuity cloud apikey create --name "Q1 Key" --expires-at 2026-03-31T23:59:59Z
+
+# Skip confirmation prompt
+agentuity cloud apikey create --name "CI/CD Key" --expires-at 90d --confirm
+```
+
+
+The API key value is shown only once during creation. Copy it immediately; you cannot retrieve it later.
+
+
+### List API Keys
+
+```bash
+agentuity cloud apikey list
+```
+
+### Get API Key Details
+
+```bash
+agentuity cloud apikey get
+```
+
+This shows metadata (name, expiration) but not the key value.
+
+### Delete an API Key
+
+```bash
+agentuity cloud apikey delete
+```
+
+
+API keys authenticate requests to Agentuity APIs. Store them in your `.env` as `AGENTUITY_SDK_KEY`:
+
+```bash
+AGENTUITY_SDK_KEY=agt_...
+```
+
+
+## Next Steps
+
+- [Storage Commands](/Reference/CLI/storage): Manage KV, S3, Vector, Database, and Streams
+- [Deployment Commands](/Reference/CLI/deployment): Deploy and manage your agents
+- [Development Commands](/Reference/CLI/development): Local development workflow
diff --git a/content/Reference/CLI/debugging.mdx b/content/Reference/CLI/debugging.mdx
new file mode 100644
index 00000000..98740fe1
--- /dev/null
+++ b/content/Reference/CLI/debugging.mdx
@@ -0,0 +1,290 @@
+---
+title: Debugging Deployments
+description: SSH into containers, inspect sessions, and troubleshoot issues in your deployed agents.
+---
+
+Debug live deployments by SSHing into containers, transferring files, inspecting sessions and threads, and viewing deployment logs.
+
+## SSH Access
+
+Connect to your deployed containers for debugging:
+
+```bash
+# SSH into current project
+agentuity cloud ssh
+
+# SSH into specific project
+agentuity cloud ssh proj_abc123xyz
+
+# SSH into specific deployment
+agentuity cloud ssh dep_abc123xyz
+
+# Run a command and exit
+agentuity cloud ssh 'ps aux'
+
+# Run command on specific project
+agentuity cloud ssh proj_abc123xyz 'tail -f /var/log/app.log'
+
+# Show SSH command without executing
+agentuity cloud ssh --show
+```
+
+
+Add your SSH public key before connecting:
+
+```bash
+agentuity auth ssh add ~/.ssh/id_rsa.pub
+```
+
+See [Getting Started](/Reference/CLI/getting-started) for authentication setup.
+
+
+**Interactive session:**
+```bash
+agentuity cloud ssh
+
+# Now you're in the container
+cd /app
+ls -la
+cat .env
+exit
+```
+
+## File Transfer
+
+Use SCP to upload and download files from deployments:
+
+```bash
+# Upload file to home directory
+agentuity cloud scp upload ./config.json
+
+# Upload to specific path
+agentuity cloud scp upload ./config.json /app/config.json
+
+# Upload to specific project
+agentuity cloud scp upload ./config.json --identifier=proj_abc123xyz
+
+# Upload multiple files
+agentuity cloud scp upload ./logs/*.log ~/logs/
+
+# Download file to current directory
+agentuity cloud scp download /var/log/app.log
+
+# Download to specific path
+agentuity cloud scp download /var/log/app.log ./logs/
+
+# Download from specific project
+agentuity cloud scp download /app/config.json --identifier=proj_abc123xyz
+
+# Download multiple files
+agentuity cloud scp download ~/logs/*.log ./logs/
+```
+
+**Common use cases:**
+- Upload configuration files for testing
+- Download logs for local analysis
+- Transfer debug scripts
+- Backup application state
+
+## Agent Inspection
+
+List and inspect agents deployed in your project:
+
+```bash
+# List all agents in the project
+agentuity cloud agent list
+
+# List agents for a specific project
+agentuity cloud agent list --project-id=proj_abc123xyz
+
+# Get details for a specific agent
+agentuity cloud agent get agent_abc123xyz
+
+# View agent input/output schema
+agentuity cloud agent schema agent_abc123xyz
+```
+
+**Agent details include:**
+- Agent ID and name
+- Description and metadata
+- Associated routes
+- Schema definitions (input/output types)
+
+Use agent inspection to:
+- Verify deployed agent configuration
+- Debug schema mismatches
+- Explore available agents in a project
+- Generate client code from schemas
+
+## Session Logs
+
+Inspect individual agent sessions, including request details, timeline, and logs:
+
+```bash
+# List recent sessions
+agentuity cloud session list
+
+# List 25 most recent sessions
+agentuity cloud session list --count=25
+
+# Filter by project
+agentuity cloud session list --project-id=proj_abc123xyz
+
+# Filter by deployment
+agentuity cloud session list --deployment-id=dep_abc123xyz
+
+# Only successful sessions
+agentuity cloud session list --success=true
+
+# Only failed sessions
+agentuity cloud session list --success=false
+
+# Filter by specific trigger type
+agentuity cloud session list --trigger=api
+
+# Filter by specific environment
+agentuity cloud session list --env=production
+```
+
+**Get session details:**
+```bash
+# Full session information with timeline
+agentuity cloud session get sess_abc123xyz
+```
+
+This shows:
+- Request method, URL, and headers
+- Success/failure status and error messages
+- Duration and timing information
+- Agent execution timeline
+- Eval runs (if configured)
+
+**View session logs:**
+```bash
+# View logs for specific session
+agentuity cloud session logs sess_abc123xyz
+
+# Hide timestamps
+agentuity cloud session logs sess_abc123xyz --no-timestamps
+```
+
+
+Session logs show output for a single request. Deployment logs show all output from a deployment, including startup, errors, and background tasks.
+
+
+## Thread Inspection
+
+List and manage conversation threads. For details on how threads work in agents, see [State Management](/Build/Agents/state-management).
+
+```bash
+# List recent threads
+agentuity cloud thread list
+
+# List 25 most recent threads
+agentuity cloud thread list --count=25
+
+# Filter by project
+agentuity cloud thread list --project-id=proj_abc123xyz
+
+# Get thread details
+agentuity cloud thread get thrd_abc123xyz
+
+# Delete a thread
+agentuity cloud thread delete thrd_abc123xyz
+```
+
+**Thread details include:**
+- Thread ID and timestamps
+- Associated project
+- User data (metadata)
+- Deletion status
+
+Use thread inspection to:
+- Debug conversation state issues
+- Clean up old threads
+- Verify thread metadata
+- Track thread lifecycle
+
+## Deployment Logs
+
+Stream logs from a specific deployment:
+
+```bash
+# View deployment logs
+agentuity cloud deployment logs dep_abc123xyz
+
+# Limit to 50 log entries
+agentuity cloud deployment logs dep_abc123xyz --limit=50
+
+# Hide timestamps
+agentuity cloud deployment logs dep_abc123xyz --no-timestamps
+
+# Specify project explicitly
+agentuity cloud deployment logs dep_abc123xyz --project-id=proj_abc123xyz
+```
+
+**Log output includes:**
+- Severity levels (INFO, WARN, ERROR)
+- Timestamps
+- Log messages
+- Stack traces for errors
+
+**Use deployment logs to:**
+- Monitor startup issues
+- Debug background tasks
+- Track errors across requests
+- Analyze performance issues
+
+## JSON Output for Scripting
+
+All commands support `--json` for machine-readable output. Combined with [jq](/Reference/CLI/getting-started#json-output), you can filter and transform results:
+
+```bash
+# Get session list as JSON
+agentuity --json cloud session list --count=100 > sessions.json
+
+# Get thread details as JSON
+agentuity --json cloud thread get thrd_abc123xyz
+
+# Process with jq
+agentuity --json cloud session list | jq '.[] | select(.success == false)'
+
+# Find failed sessions in last hour
+agentuity --json cloud session list --count=100 | \
+ jq '.[] | select(.success == false) | {id, url, error}'
+
+# Count sessions by trigger type
+agentuity --json cloud session list --count=100 | \
+ jq 'group_by(.trigger) | map({trigger: .[0].trigger, count: length})'
+```
+
+**Scripting examples:**
+
+Here are some practical scripts for monitoring and automation:
+
+```bash
+#!/bin/bash
+# Monitor for failures and send alerts
+
+FAILED=$(agentuity --json cloud session list --success=false --count=10)
+COUNT=$(echo "$FAILED" | jq 'length')
+
+if [ "$COUNT" -gt 5 ]; then
+ echo "Alert: $COUNT failed sessions detected"
+ echo "$FAILED" | jq '.[] | {id, url, error}'
+fi
+```
+
+```bash
+#!/bin/bash
+# Export thread user data
+
+agentuity --json cloud thread list --count=100 | \
+ jq -r '.[] | [.id, .user_data] | @csv' > threads.csv
+```
+
+## Next Steps
+
+- [Managing Cloud Data](/Reference/CLI/data-management): Inspect storage, env vars, and secrets
+- [Deploying to the Cloud](/Reference/CLI/deployment): Deploy and manage projects
+- [Logging](/Build/Observability/logging): Configure logging in your agents
diff --git a/content/Reference/CLI/deployment.mdx b/content/Reference/CLI/deployment.mdx
new file mode 100644
index 00000000..7cb11413
--- /dev/null
+++ b/content/Reference/CLI/deployment.mdx
@@ -0,0 +1,422 @@
+---
+title: Deploying to the Cloud
+description: Deploy your agents to Agentuity Cloud with automatic infrastructure provisioning.
+---
+
+Deploy your Agentuity project to the cloud with a single command. The platform handles infrastructure, scaling, and monitoring automatically.
+
+## Deploy Your Project
+
+```bash
+agentuity deploy
+# or
+bun run deploy
+```
+
+The deploy command:
+1. Syncs environment variables from `.env.production` (or `.env` as fallback)
+2. Builds and packages your project
+3. Encrypts and uploads the deployment bundle securely
+4. Provisions your deployment on Agentuity's infrastructure
+5. Activates your deployment
+
+After deployment, view your environment variables and secrets in the [Agentuity App](https://app-v1.agentuity.com) under **Project > Settings**.
+
+**Example output:**
+
+```
+✓ Sync Env & Secrets
+✓ Create Deployment
+✓ Build, Verify and Package
+✓ Encrypt and Upload Deployment
+✓ Provision Deployment
+
+Your project was deployed!
+
+→ Deployment ID: dep_abc123xyz
+→ Deployment URL: https://dep-abc123xyz.agentuity.cloud
+→ Project URL: https://proj-456def.agentuity.cloud
+→ Dashboard: https://app-v1.agentuity.com/deployments/dep_abc123xyz
+```
+
+The Dashboard URL links directly to the deployment details in the Agentuity App.
+
+## Deployment URLs
+
+Each deployment gets two URLs:
+
+**Deployment URL** (`dep_xxx.agentuity.cloud`):
+- Unique URL for this specific deployment
+- Persists even after new deployments
+- Use for testing a specific version
+
+**Project URL** (`proj_xxx.agentuity.cloud`):
+- Always points to the active deployment
+- Updates automatically when you deploy
+- Use for stable endpoints and webhooks
+
+```bash
+# Deploy creates both URLs
+agentuity deploy
+
+# Deployment URL: https://dep-abc123.agentuity.cloud
+# Project URL: https://proj-456def.agentuity.cloud
+```
+
+Both URLs are automatically provisioned with HTTPS. The project URL always routes to the active deployment.
+
+## Tagging Deployments
+
+Add tags to label deployments:
+
+```bash
+# Single tag
+agentuity deploy --tag staging
+
+# Multiple tags
+agentuity deploy --tag staging --tag hotfix-123
+```
+
+Tags appear in deployment lists and help organize versions:
+
+```bash
+agentuity cloud deployment list
+# Shows tags column for each deployment
+```
+
+## Viewing Deployments
+
+List recent deployments:
+
+```bash
+# Show 10 most recent
+agentuity cloud deployment list
+
+# Custom count
+agentuity cloud deployment list --count=25
+
+# For a specific project
+agentuity cloud deployment list --project-id=proj_abc123xyz
+```
+
+**Example output:**
+
+| ID | State | Active | Created | Message | Tags |
+|----|-------|--------|---------|---------|------|
+| dep_abc123 | completed | Yes | 12/1/25, 3:45 PM | | staging |
+| dep_def456 | completed | | 12/1/25, 2:30 PM | | v1.2.0 |
+| dep_ghi789 | completed | | 11/30/25, 5:00 PM | | |
+
+## Deployment Details
+
+View detailed information about a deployment:
+
+```bash
+# Show deployment details
+agentuity cloud deployment show dep_abc123xyz
+
+# For specific project
+agentuity cloud deployment show dep_abc123xyz --project-id=proj_abc123
+```
+
+**Output includes:**
+- Deployment ID, state, and creation time
+- Active status
+- Tags and custom domains
+- Cloud region
+- Git metadata (repo, commit, branch, PR)
+- Build information (SDK version, runtime, platform)
+
+```
+ID: dep_abc123xyz
+Project: proj_456def
+State: completed
+Active: Yes
+Created: 12/1/25, 3:45 PM
+Tags: staging, hotfix-123
+
+Git Information
+ Repo: myorg/myapp
+ Branch: main
+ Commit: a1b2c3d
+ Message: Fix authentication bug
+
+Build Information
+ Agentuity: 1.0.0
+ Bun: 1.1.40
+ Platform: linux
+ Arch: x64
+```
+
+## Viewing Logs
+
+Fetch logs for a deployment:
+
+```bash
+# View logs
+agentuity cloud deployment logs dep_abc123xyz
+
+# Limit log entries
+agentuity cloud deployment logs dep_abc123xyz --limit=50
+
+# Hide timestamps
+agentuity cloud deployment logs dep_abc123xyz --no-timestamps
+
+# For specific project
+agentuity cloud deployment logs dep_abc123xyz --project-id=proj_abc123
+```
+
+Logs show severity (INFO, WARN, ERROR) and message body with color-coded output.
+
+
+For live streaming logs, use SSH access. See [Debugging](/Reference/CLI/debugging) for SSH setup.
+
+
+## Rolling Back
+
+Revert to a previous deployment:
+
+```bash
+agentuity cloud deployment rollback
+```
+
+The command:
+1. Finds the previous completed deployment
+2. Prompts for confirmation
+3. Activates the previous deployment
+4. Updates the project URL
+
+```
+Rollback to deployment dep_def456? (y/N): y
+✓ Rolled back to deployment dep_def456
+```
+
+Use for specific projects:
+
+```bash
+agentuity cloud deployment rollback --project-id=proj_abc123xyz
+```
+
+
+Rollback activates the most recent completed deployment before the current one. The current deployment remains available at its deployment URL but is no longer active.
+
+
+## Undeploying
+
+Stop the active deployment:
+
+```bash
+# With confirmation prompt
+agentuity cloud deployment undeploy
+
+# Skip confirmation
+agentuity cloud deployment undeploy --force
+
+# For specific project
+agentuity cloud deployment undeploy --project-id=proj_abc123xyz
+```
+
+After undeploying:
+- The project URL becomes unavailable
+- All deployment-specific URLs remain accessible
+- Previous deployments are not deleted
+- You can redeploy or rollback at any time
+
+
+Undeploying stops the active deployment immediately. Your project URL will return 404 until you deploy or rollback.
+
+
+## Removing Deployments
+
+Permanently delete a deployment:
+
+```bash
+# Remove a specific deployment
+agentuity cloud deployment remove dep_abc123xyz
+
+# For specific project
+agentuity cloud deployment remove dep_abc123xyz --project-id=proj_abc123xyz
+```
+
+
+Removing a deployment permanently deletes it. You cannot rollback to a removed deployment.
+
+
+## Custom Domains
+
+You can configure custom domains using either the configuration file or CLI commands.
+
+### Option 1: Configuration File
+
+Configure custom domains in `agentuity.json`:
+
+```json
+{
+ "projectId": "proj_abc123xyz",
+ "orgId": "org_def456",
+ "region": "us-east-1",
+ "deployment": {
+ "domains": ["api.example.com", "app.example.com"]
+ }
+}
+```
+
+Available regions are fetched from the API at deployment time. If multiple regions are available, the CLI prompts you to select one.
+
+### DNS Configuration
+
+Add a CNAME record for each custom domain. A CNAME record tells DNS to resolve your domain to Agentuity's servers:
+
+```
+Type: CNAME
+Name: api.example.com
+Value: p.agentuity.cloud
+TTL: 600
+```
+
+The `p` value is your project's unique identifier, shown when you run `agentuity deploy` or in the App.
+
+The CLI validates DNS records during deployment:
+
+```bash
+agentuity deploy
+```
+
+```
+✓ Validate Custom Domains: api.example.com, app.example.com
+✓ Sync Env & Secrets
+...
+```
+
+
+Deployment fails if DNS records are missing or incorrect. The CLI shows the required CNAME value in the error message.
+
+
+### Multiple Domains
+
+Custom domains replace the default URLs:
+
+```json
+{
+ "deployment": {
+ "domains": ["api.example.com"]
+ }
+}
+```
+
+After deployment with custom domains, the CLI only shows custom URLs:
+
+```
+→ Deployment ID: dep_abc123xyz
+→ Deployment URL: https://api.example.com
+```
+
+The project URL and deployment-specific URLs still exist but custom domains take precedence in the output.
+
+### Option 2: CLI Commands
+
+Manage custom domains directly from the CLI:
+
+```bash
+# List configured domains
+agentuity cloud domain list
+
+# Add a domain
+agentuity cloud domain add api.example.com
+
+# Remove a domain
+agentuity cloud domain remove api.example.com
+
+# Verify DNS configuration
+agentuity cloud domain verify api.example.com
+```
+
+Use the configuration file for domains that should persist across deployments. Use CLI commands for quick testing or temporary domains.
+
+## Environment Variables
+
+The deploy command syncs variables from `.env.production` (or `.env` as fallback):
+
+```bash
+# .env.production
+DATABASE_URL=postgres://...
+WEBHOOK_SECRET=secret123
+MY_CUSTOM_API_KEY=xxx
+```
+
+
+If you're using the [AI Gateway](/Build/Agents/ai-gateway), you don't need to include provider API keys (like `OPENAI_API_KEY`). The gateway handles authentication automatically. Only include provider keys if you're bypassing the gateway.
+
+
+Variables are automatically:
+- Filtered (removes `AGENTUITY_` prefixed keys)
+- Categorized (regular env vs secrets based on naming)
+- Encrypted (secrets only)
+- Synced to cloud before the build step
+
+
+Variables with suffixes like `_SECRET`, `_KEY`, `_TOKEN`, `_PASSWORD`, or `_PRIVATE` are automatically encrypted as secrets. All other variables are stored as regular environment variables.
+
+
+## Deploy Options
+
+| Option | Description |
+|--------|-------------|
+| `--tag ` | Add deployment tag (repeatable) |
+| `-f, --force` | Force deployment without confirmation |
+| `--dry-run` | Simulate deployment without executing |
+| `--log-level debug` | Show verbose output |
+| `--project-id ` | Deploy specific project |
+
+```bash
+# Verbose deployment
+agentuity deploy --log-level=debug
+
+# Multiple tags
+agentuity deploy --tag staging --tag v1.2.0
+
+# Specific project
+agentuity deploy --project-id=proj_abc123xyz
+
+# Simulate deployment
+agentuity deploy --dry-run
+
+# Force deployment
+agentuity deploy --force
+```
+
+## CI/CD Pipelines
+
+For automated deployments in CI/CD systems (GitHub Actions, GitLab CI, etc.), you can use a pre-created deployment.
+
+### Using Pre-Created Deployments
+
+Set the `AGENTUITY_DEPLOYMENT` environment variable with deployment details:
+
+```bash
+export AGENTUITY_DEPLOYMENT='{"id":"dep_xxx","orgId":"org_xxx","publicKey":"..."}'
+agentuity deploy
+```
+
+The JSON object requires:
+
+| Field | Description |
+|-------|-------------|
+| `id` | The deployment ID |
+| `orgId` | Your organization ID |
+| `publicKey` | The deployment's public key |
+
+When this variable is set, the CLI:
+- Skips deployment creation and uses the existing deployment
+- Uses plain output mode (no TUI) for cleaner CI logs
+- Validates the JSON schema before proceeding
+
+
+Pre-created deployments are typically provisioned by external systems like GitHub Actions workflows or custom CI pipelines that integrate with the Agentuity API.
+
+
+## Next Steps
+
+- [Debugging Deployments](/Reference/CLI/debugging): SSH access and debugging tools
+- [Logging](/Build/Observability/logging): Configure logging in your agents
+- [Key-Value Storage](/Build/Storage/key-value): Store persistent data
diff --git a/content/Reference/CLI/development.mdx b/content/Reference/CLI/development.mdx
new file mode 100644
index 00000000..d7f5c450
--- /dev/null
+++ b/content/Reference/CLI/development.mdx
@@ -0,0 +1,252 @@
+---
+title: Local Development
+description: Run the development server with hot reload, local mode, and the interactive Workbench.
+---
+
+Run your Agentuity project locally with automatic hot reload, type checking, and the interactive Workbench UI.
+
+## Starting the Dev Server
+
+```bash
+agentuity dev
+# or
+bun run dev
+```
+
+The server starts on port 3500 by default with:
+- Hot reload on file changes
+- TypeScript type checking
+- Public URL tunneling (optional, for webhooks and sharing)
+- Interactive keyboard shortcuts
+
+## Dev Server Options
+
+| Option | Default | Description |
+|--------|---------|-------------|
+| `--port` | 3500 (or `PORT` env) | TCP port for the dev server |
+| `--local` | false | Use local services instead of cloud |
+| `--public` | true | Enable public URL tunneling |
+| `--no-public` | - | Disable public URL tunneling |
+| `--interactive` | true | Enable interactive keyboard shortcuts |
+| `--watch ` | - | Additional paths to watch for changes (repeatable) |
+| `--profile ` | - | Load `.env.` in addition to `.env` |
+
+
+The dev server respects the `PORT` environment variable. The `--port` flag takes precedence if both are set.
+
+
+```bash
+# Custom port
+agentuity dev --port 8080
+
+# Local mode (offline development)
+agentuity dev --local
+
+# Disable public URL
+agentuity dev --no-public
+
+# Non-interactive mode (useful for CI/CD)
+agentuity dev --no-interactive
+
+# Watch additional directories (e.g., local packages)
+agentuity dev --watch ../my-shared-lib/dist --watch ../other-package/src
+```
+
+
+Use `--watch` when developing with local packages outside your project. Changes in watched paths trigger rebuilds just like changes in your source directory.
+
+
+## Keyboard Shortcuts
+
+Press keys during development to control the server:
+
+| Key | Action |
+|-----|--------|
+| `h` | Show help |
+| `c` | Clear console |
+| `r` | Restart server |
+| `o` | Show routes |
+| `a` | Show agents |
+| `q` | Quit |
+
+## Local Mode
+
+Use `--local` to develop offline without cloud services:
+
+```bash
+agentuity dev --local
+```
+
+
+Local mode disables cloud services (KV, Vector, Object Storage). Use when developing without internet or testing with mock data.
+
+
+**What happens in local mode:**
+- No connection to Agentuity cloud
+- Storage APIs disabled unless you provide [custom implementations](/Build/Storage/custom)
+- Public URL tunneling disabled
+- Requires your own API keys for AI providers (in `.env`), since the [AI Gateway](/Build/Agents/ai-gateway) is not available
+
+**Bring Your Own Storage:**
+
+```typescript
+// app.ts
+import { createApp } from '@agentuity/runtime';
+import { MyCustomKV } from './storage';
+
+const app = createApp({
+ services: {
+ useLocal: true,
+ keyvalue: new MyCustomKV(), // Your implementation
+ },
+});
+```
+
+See [Custom Storage](/Build/Storage/custom) for implementation details.
+
+## Profile-Specific Environment Variables
+
+Load different environment variables based on a profile name:
+
+```bash
+# Load .env.staging
+agentuity dev --profile staging
+
+# Load .env.testing
+agentuity dev --profile testing
+```
+
+Profile-specific files are loaded in addition to the base `.env` file. Variables in the profile file override those in `.env`.
+
+**Example setup:**
+
+```bash
+# .env (base, always loaded)
+DATABASE_URL=postgres://localhost:5432/myapp
+LOG_LEVEL=info
+
+# .env.staging (loaded with --profile staging)
+DATABASE_URL=postgres://staging.example.com:5432/myapp
+API_BASE_URL=https://staging-api.example.com
+
+# .env.testing (loaded with --profile testing)
+DATABASE_URL=postgres://localhost:5432/myapp_test
+MOCK_EXTERNAL_APIS=true
+```
+
+
+Use profiles to switch between configurations without editing files. Common profiles: `staging`, `testing`, `local`, `demo`.
+
+
+## Public URLs
+
+Enable public URLs to share your local dev server or receive webhooks:
+
+```bash
+# Public URL enabled by default
+agentuity dev
+
+# Or explicitly
+agentuity dev --public
+```
+
+The `--public` flag creates a secure tunnel through Agentuity's edge network, giving your local server a public HTTPS URL for testing webhooks, sharing with teammates, or external integrations.
+
+**Example output:**
+```
+⨺ Agentuity DevMode
+ Local: http://127.0.0.1:3500
+ Public: https://abc123.devmode.agentuity.com
+
+ Press h for keyboard shortcuts
+```
+
+**Example use cases:**
+- Testing Slack, Discord, or Twilio webhooks
+- Sharing with team members
+- Testing from mobile devices
+- OAuth callback URLs
+
+## Workbench UI
+
+Access the interactive Workbench at `http://localhost:3500/workbench` to test agents visually. It displays agent schemas, handles input validation, and shows execution results with timing metrics.
+
+See [Testing with Workbench](/Build/Agents/workbench) for setup and configuration.
+
+## Building Your Project
+
+Bundle your project for deployment:
+
+```bash
+agentuity build
+```
+
+**What happens during build:**
+1. TypeScript compilation
+2. Bundle agents, routes, and frontend
+3. Generate registry and types
+4. Type check with `tsc`
+5. Create `.agentuity/` output directory
+
+### Build Options
+
+| Option | Default | Description |
+|--------|---------|-------------|
+| `--dev` | false | Enable development mode |
+| `--outdir` | `.agentuity` | Output directory |
+| `--skip-type-check` | false | Skip TypeScript type checking |
+
+```bash
+# Skip type checking (faster builds)
+agentuity build --skip-type-check
+
+# Custom output directory
+agentuity build --outdir ./dist
+```
+
+
+Build fails if TypeScript errors are detected. Fix type errors or use `--skip-type-check` to override (not recommended for deployments).
+
+
+## Hot Reload Behavior
+
+The dev server watches for file changes and automatically:
+- Rebuilds on source file changes (`.ts`, `.tsx`, `.js`, `.jsx`)
+- Runs TypeScript type checking
+- Restarts the server
+- Preserves background tasks
+
+**Ignored files:**
+- `node_modules/`
+- `.agentuity/` (build output)
+- Generated files (`*.generated.ts`)
+- Temporary files
+
+**Cooldown period:** 500ms after build completes to prevent restart loops.
+
+## Dev Server Architecture
+
+The dev server uses Vite for frontend hot module replacement (HMR) and Bun for server-side code. All requests go through a single port (3500), so you don't need to manage multiple servers or ports during development.
+
+- **Frontend changes** (React, CSS) reload instantly via Vite HMR
+- **Server changes** (agents, routes) trigger a fast Bun rebuild
+- **WebSocket connections** work seamlessly
+
+## Development vs Production
+
+Understanding the differences between local development and deployed production:
+
+| Aspect | Local (`agentuity dev`) | Production (`agentuity deploy`) |
+|--------|------------------------|--------------------------------|
+| **Storage** | Cloud services (or local with `--local`) | Cloud services always |
+| **AI Gateway** | Available (or BYO keys with `--local`) | Available always |
+| **URL** | `localhost:3500` + optional public tunnel | `*.agentuity.cloud` or custom domain |
+| **Hot Reload** | Yes | No (redeploy required) |
+| **Debugging** | Local logs, Workbench | SSH access, cloud logs |
+| **Environment** | `.env` | `.env.production` (synced to cloud) |
+
+## Next Steps
+
+- [Deploying to the Cloud](/Reference/CLI/deployment): Deploy to Agentuity Cloud
+- [Creating Agents](/Build/Agents/creating-agents): Create your first agent
+- [HTTP Routes](/Build/Routes/http): Add HTTP endpoints
diff --git a/content/Reference/CLI/getting-started.mdx b/content/Reference/CLI/getting-started.mdx
new file mode 100644
index 00000000..244b5234
--- /dev/null
+++ b/content/Reference/CLI/getting-started.mdx
@@ -0,0 +1,328 @@
+---
+title: Getting Started with the CLI
+description: Install the Agentuity CLI and authenticate to start building agents.
+---
+
+Everything you do with Agentuity goes through the CLI: creating projects, running locally, deploying to the cloud, and debugging live agents. The [App](https://app-v1.agentuity.com) stays synced when you need a visual interface.
+
+## Installation
+
+Install the CLI using the universal installer:
+
+```bash
+curl -sSL https://v1.agentuity.sh | sh
+```
+
+Alternatively, install via package manager: `bun add -g @agentuity/cli`
+
+Verify the installation:
+
+```bash
+agentuity --version
+```
+
+
+Bun 1.3.0 or higher is required to run the CLI.
+
+
+## Upgrading
+
+Upgrade the CLI to the latest version:
+
+```bash
+agentuity upgrade
+```
+
+Force upgrade even if already on the latest version:
+
+```bash
+agentuity upgrade --force
+```
+
+The CLI periodically checks for new versions and prompts you to upgrade when one is available.
+
+## Authentication
+
+### Login to Your Account
+
+Authenticate using a browser-based login flow:
+
+```bash
+agentuity auth login
+# or simply
+agentuity login
+```
+
+This command:
+1. Generates a one-time password and opens your browser
+2. Prompts you to authenticate in the web app
+3. Saves your API credentials locally
+
+Check your authentication status:
+
+```bash
+agentuity auth whoami
+```
+
+### Create a New Account
+
+Sign up for a new Agentuity account directly from the CLI:
+
+```bash
+agentuity auth signup
+```
+
+This opens your browser to complete account creation, then automatically saves your credentials locally.
+
+### Logout
+
+Clear your local credentials:
+
+```bash
+agentuity auth logout
+# or simply
+agentuity logout
+```
+
+## Creating Projects
+
+### Create a New Project
+
+The quickest way to get started is the interactive project creation:
+
+```bash
+agentuity project create
+# or simply
+agentuity create
+```
+
+Create a project with a specific name:
+
+```bash
+agentuity project create --name my-agent
+```
+
+Create a project in a specific directory:
+
+```bash
+agentuity project create --name my-agent --dir ~/projects/agents
+```
+
+### Available Templates
+
+| Template | Description |
+|----------|-------------|
+| `default` | React UI with example agents using `@agentuity/schema` (recommended for getting started) |
+| `tailwind` | React UI with Tailwind CSS pre-configured |
+| `openai` | Uses OpenAI SDK directly for chat completions |
+| `groq` | Uses Groq SDK for fast inference with open-source models |
+| `xai` | Uses AI SDK with xAI provider for Grok models |
+| `vercel-openai` | Uses AI SDK with OpenAI provider |
+
+Additional templates coming soon. Run `agentuity create` to see the current options.
+
+To use a specific template:
+
+```bash
+agentuity project create --template openai
+```
+
+### Project Creation Options
+
+- `--name `: Project name
+- `--dir `: Directory to create the project in
+- `--template `: Template to use (default: "default")
+- `--no-install`: Skip dependency installation
+- `--no-build`: Skip initial build
+- `--no-register`: Don't register the project with Agentuity Cloud
+
+Example:
+
+```bash
+agentuity project create \
+ --name customer-service-bot \
+ --dir ~/projects \
+ --no-build
+```
+
+## Managing Projects
+
+### List Projects
+
+View all registered projects:
+
+```bash
+agentuity project list
+```
+
+For machine-readable output (useful for scripts and AI coding agents):
+
+```bash
+agentuity --json project list
+```
+
+### Show Project Details
+
+View details for a specific project:
+
+```bash
+agentuity project show
+```
+
+### Delete a Project
+
+Delete projects interactively:
+
+```bash
+agentuity project delete
+```
+
+Delete a specific project:
+
+```bash
+agentuity project delete
+```
+
+Skip confirmation prompt:
+
+```bash
+agentuity project delete --confirm
+```
+
+
+Project deletion is permanent and cannot be undone. Deployed agents and associated resources will be removed.
+
+
+## Command Shortcuts
+
+Several common commands have shortcuts that let you skip the subcommand prefix:
+
+| Full Command | Shortcut | Also Works |
+|--------------|----------|------------|
+| `agentuity auth login` | `agentuity login` | |
+| `agentuity auth logout` | `agentuity logout` | |
+| `agentuity auth signup` | `agentuity signup` | |
+| `agentuity project create` | `agentuity create` | `new`, `init` |
+| `agentuity cloud deploy` | `agentuity deploy` | |
+| `agentuity cloud ssh` | `agentuity ssh` | |
+
+All other commands require their full prefix (e.g., `agentuity cloud session list`, `agentuity auth ssh add`).
+
+## Global Options
+
+The CLI supports several global flags that work with any command:
+
+| Flag | Description | Example |
+|------|-------------|---------|
+| `--json` | Output in JSON format | `agentuity --json project list` |
+| `--log-level ` | Set log verbosity (debug, trace, info, warn, error) | `agentuity --log-level=debug auth login` |
+| `--quiet` | Suppress non-essential output | `agentuity --quiet project create` |
+| `--no-progress` | Disable progress indicators | `agentuity --no-progress build` |
+| `--color ` | Control color output (auto, always, never) | `agentuity --color=never project list` |
+| `--explain` | Show what the command would do without executing | `agentuity --explain project delete my-proj` |
+| `--dry-run` | Simulate command execution | `agentuity --dry-run project delete my-proj` |
+| `--skip-version-check` | Disable automatic version checking | `agentuity --skip-version-check dev` |
+
+### JSON Output
+
+All commands support `--json` for machine-readable output, useful for shell scripts and AI coding agents:
+
+```bash
+# Get JSON output for scripting
+agentuity --json auth whoami
+
+# Parse with jq (a command-line JSON processor)
+agentuity --json project list | jq '.[].name'
+```
+
+[jq](https://jqlang.org/) is a lightweight command-line JSON processor. Install via `brew install jq` (macOS) or `apt install jq` (Linux).
+
+### Log Levels
+
+Control CLI verbosity:
+
+```bash
+# Detailed debugging output
+agentuity --log-level=debug project create
+
+# Only show errors
+agentuity --log-level=error build
+```
+
+## Configuration Profiles
+
+The CLI supports multiple configuration profiles for different environments (development, staging, production).
+
+### Switch Profiles
+
+Switch to a different profile:
+
+```bash
+agentuity profile use production
+```
+
+### List Profiles
+
+View available profiles:
+
+```bash
+agentuity profile list
+```
+
+Configuration is stored in `~/.config/agentuity/production.yaml` by default. Override with `--config=/path/to/config.yaml`.
+
+## SSH Key Management
+
+Add SSH keys to your account for secure container access during development and debugging.
+
+### List SSH Keys
+
+View all SSH keys on your account:
+
+```bash
+agentuity auth ssh list
+```
+
+### Add an SSH Key
+
+Add a new SSH key interactively (automatically discovers keys in `~/.ssh/`):
+
+```bash
+agentuity auth ssh add
+```
+
+Add a specific key file:
+
+```bash
+agentuity auth ssh add --file ~/.ssh/id_ed25519.pub
+```
+
+Pipe a key from stdin:
+
+```bash
+cat ~/.ssh/id_rsa.pub | agentuity auth ssh add
+```
+
+### Remove an SSH Key
+
+Remove keys interactively:
+
+```bash
+agentuity auth ssh delete
+```
+
+Remove a specific key by fingerprint:
+
+```bash
+agentuity auth ssh delete
+```
+
+SSH keys enable secure access to deployed agent containers for debugging and log inspection. See [Debugging Deployments](/Reference/CLI/debugging) for details.
+
+## Next Steps
+
+Now that you have the CLI installed and authenticated:
+
+- [Local Development](/Reference/CLI/development): Run agents locally with hot reload
+- [Deploying to the Cloud](/Reference/CLI/deployment): Deploy agents to Agentuity Cloud
+- [Managing Cloud Data](/Reference/CLI/data-management): Inspect storage, env vars, and secrets
diff --git a/content/Reference/CLI/index.mdx b/content/Reference/CLI/index.mdx
new file mode 100644
index 00000000..b75071fb
--- /dev/null
+++ b/content/Reference/CLI/index.mdx
@@ -0,0 +1,51 @@
+---
+title: CLI Reference
+description: Command-line tools for building, deploying, and managing agents
+---
+
+The Agentuity CLI is your primary interface for building and managing agents. Create projects, deploy to the cloud, inspect sessions, and manage storage from the terminal.
+
+## Installation
+
+```bash
+curl -sSL https://v1.agentuity.sh | sh
+```
+
+See [Getting Started](/Reference/CLI/getting-started) for installation options, authentication, and first steps.
+
+## Command Categories
+
+| Category | Commands | Use For |
+|----------|----------|---------|
+| [Getting Started](/Reference/CLI/getting-started) | `login`, `logout`, `new` | Install, authenticate, create projects |
+| [Development](/Reference/CLI/development) | `dev` | Local development server |
+| [Deployment](/Reference/CLI/deployment) | `deploy`, `cloud project` | Deploy and manage cloud projects |
+| [Storage](/Reference/CLI/storage) | `cloud kv`, `cloud vector`, `cloud object`, `cloud redis` | Manage KV, vector, object, and Redis storage |
+| [Configuration](/Reference/CLI/configuration) | `cloud env`, `cloud secret`, `cloud apikey` | Manage env vars, secrets, and API keys |
+| [Debugging](/Reference/CLI/debugging) | `cloud ssh`, `cloud session` | SSH access, session inspection |
+| [AI Commands](/Reference/CLI/ai-commands) | `ai` | AI coding agent utilities |
+
+## Quick Reference
+
+```bash
+# Development
+agentuity dev # Start dev server
+
+# Deployment
+agentuity deploy # Deploy to cloud
+
+# Sessions and Debugging
+agentuity cloud session list # List recent sessions
+agentuity cloud session logs # View session logs
+agentuity cloud ssh # SSH into deployment
+
+# Storage
+agentuity cloud kv list # List KV keys
+agentuity cloud vector list # List vector namespaces
+```
+
+## Next Steps
+
+- [Getting Started](/Reference/CLI/getting-started): Install and authenticate
+- [Development](/Reference/CLI/development): Run the local dev server
+- [Debugging](/Reference/CLI/debugging): SSH access and session inspection
diff --git a/content/Reference/CLI/meta.json b/content/Reference/CLI/meta.json
new file mode 100644
index 00000000..cdcea172
--- /dev/null
+++ b/content/Reference/CLI/meta.json
@@ -0,0 +1,14 @@
+{
+ "title": "CLI",
+ "pages": [
+ "getting-started",
+ "development",
+ "build-configuration",
+ "deployment",
+ "storage",
+ "sandbox",
+ "configuration",
+ "debugging",
+ "ai-commands"
+ ]
+}
diff --git a/content/Reference/CLI/sandbox.mdx b/content/Reference/CLI/sandbox.mdx
new file mode 100644
index 00000000..515be166
--- /dev/null
+++ b/content/Reference/CLI/sandbox.mdx
@@ -0,0 +1,324 @@
+---
+title: Sandbox Commands
+description: Create and manage isolated execution environments from the CLI
+---
+
+Use these commands to test code execution, debug running sandboxes, and create snapshots without writing application code.
+
+
+All sandbox commands require the `cloud` prefix. For example: `agentuity cloud sandbox run ...`
+
+
+## Quick Reference
+
+| Command | Description |
+|---------|-------------|
+| `sandbox run -- ` | One-shot execution |
+| `sandbox create` | Create interactive sandbox |
+| `sandbox list` | List sandboxes |
+| `sandbox get ` | Get sandbox details |
+| `sandbox delete ` | Destroy sandbox |
+| `sandbox exec -- ` | Execute in existing sandbox |
+| `sandbox cp` | Copy files to/from sandbox |
+| `sandbox snapshot` | Manage snapshots |
+| `sandbox execution` | View execution history |
+
+**Alias:** `sb` (e.g., `agentuity cloud sb list`)
+
+## One-shot Execution
+
+Run a single command in a new sandbox that's automatically destroyed afterward.
+
+```bash
+agentuity cloud sandbox run [options] --
+```
+
+### Options
+
+| Option | Description |
+|--------|-------------|
+| `--memory ` | Memory limit (e.g., `512Mi`, `1Gi`) |
+| `--cpu ` | CPU limit (e.g., `500m`, `1000m`) |
+| `--disk ` | Disk limit |
+| `--network` | Enable outbound network access |
+| `--timeout ` | Execution timeout (e.g., `30s`, `5m`) |
+| `--snapshot ` | Create from snapshot |
+| `--json` | JSON output |
+
+### Examples
+
+```bash
+# Simple command
+agentuity cloud sandbox run -- echo "Hello, World!"
+
+# Python with network access
+agentuity cloud sandbox run --network -- python3 -c "import urllib.request; print(urllib.request.urlopen('https://httpbin.org/ip').read())"
+
+# From a snapshot with resource limits
+agentuity cloud sandbox run --snapshot node-typescript --memory 1Gi -- npm run build
+
+# With timeout
+agentuity cloud sandbox run --timeout 10s -- sleep 5 && echo "Done"
+```
+
+## Interactive Sandbox
+
+Create a persistent sandbox for multiple commands.
+
+### Create
+
+```bash
+agentuity cloud sandbox create [options]
+```
+
+| Option | Description |
+|--------|-------------|
+| `--memory ` | Memory limit |
+| `--cpu ` | CPU limit |
+| `--disk ` | Disk limit |
+| `--network` | Enable outbound network |
+| `--snapshot ` | Create from snapshot |
+| `--idle-timeout ` | Auto-destroy after idle (e.g., `1h`) |
+
+```bash
+# Create with defaults
+agentuity cloud sandbox create
+
+# Create with resources and network
+agentuity cloud sandbox create --memory 1Gi --cpu 1000m --network
+
+# Create from snapshot
+agentuity cloud sandbox create --snapshot python-ml
+```
+
+### Execute Command
+
+```bash
+agentuity cloud sandbox exec [options] --
+```
+
+```bash
+# Run commands in sequence
+agentuity cloud sandbox exec sbx_abc123 -- npm init -y
+agentuity cloud sandbox exec sbx_abc123 -- npm install zod
+agentuity cloud sandbox exec sbx_abc123 -- npm run build
+```
+
+### List Sandboxes
+
+```bash
+agentuity cloud sandbox list [options]
+```
+
+| Option | Description |
+|--------|-------------|
+| `--status ` | Filter by status (`idle`, `running`, `creating`) |
+| `--limit ` | Max results |
+| `--json` | JSON output |
+
+```bash
+agentuity cloud sandbox list
+agentuity cloud sandbox list --status idle
+agentuity cloud sandbox list --json
+```
+
+### Get Sandbox Details
+
+```bash
+agentuity cloud sandbox get
+```
+
+Shows sandbox status, creation time, resource usage, and execution count.
+
+### Delete Sandbox
+
+```bash
+agentuity cloud sandbox delete [--confirm]
+```
+
+```bash
+agentuity cloud sandbox delete sbx_abc123
+agentuity cloud sandbox delete sbx_abc123 --confirm # Skip prompt
+```
+
+## File Operations
+
+Copy files to and from sandboxes.
+
+```bash
+agentuity cloud sandbox cp
+```
+
+```bash
+# Upload a file
+agentuity cloud sandbox cp ./local-file.txt sbx_abc123:/workspace/file.txt
+
+# Download a file
+agentuity cloud sandbox cp sbx_abc123:/workspace/output.json ./output.json
+
+# Upload a directory
+agentuity cloud sandbox cp ./src sbx_abc123:/workspace/src
+```
+
+## Snapshot Commands
+
+Manage sandbox snapshots for creating pre-configured environments.
+
+### Create Snapshot
+
+```bash
+agentuity cloud sandbox snapshot create [--tag ]
+```
+
+```bash
+# Create snapshot
+agentuity cloud sandbox snapshot create sbx_abc123
+
+# Create with tag
+agentuity cloud sandbox snapshot create sbx_abc123 --tag python-ml-v2
+```
+
+### List Snapshots
+
+```bash
+agentuity cloud sandbox snapshot list [options]
+```
+
+| Option | Description |
+|--------|-------------|
+| `--sandbox ` | Filter by source sandbox |
+| `--limit ` | Max results |
+| `--json` | JSON output |
+
+```bash
+agentuity cloud sandbox snapshot list
+agentuity cloud sandbox snapshot list --sandbox sbx_abc123
+```
+
+### Get Snapshot Details
+
+```bash
+agentuity cloud sandbox snapshot get
+```
+
+Shows snapshot size, file count, tag, and sandboxes created from it.
+
+### Tag Snapshot
+
+```bash
+agentuity cloud sandbox snapshot tag
+agentuity cloud sandbox snapshot tag --clear
+```
+
+```bash
+# Set tag
+agentuity cloud sandbox snapshot tag snp_xyz789 latest
+
+# Update tag
+agentuity cloud sandbox snapshot tag snp_xyz789 v2.0
+
+# Remove tag
+agentuity cloud sandbox snapshot tag snp_xyz789 --clear
+```
+
+### Delete Snapshot
+
+```bash
+agentuity cloud sandbox snapshot delete [--confirm]
+```
+
+```bash
+agentuity cloud sandbox snapshot delete snp_xyz789
+agentuity cloud sandbox snapshot delete snp_xyz789 --confirm
+```
+
+## Execution History
+
+View past command executions within a sandbox.
+
+### List Executions
+
+```bash
+agentuity cloud sandbox execution list [--limit ]
+```
+
+```bash
+agentuity cloud sandbox execution list sbx_abc123
+agentuity cloud sandbox execution list sbx_abc123 --limit 5
+```
+
+### Get Execution Details
+
+```bash
+agentuity cloud sandbox execution get
+```
+
+Shows command, exit code, duration, and stream URLs for stdout/stderr.
+
+## Common Workflows
+
+### Set Up a Development Environment
+
+```bash
+# Create sandbox with network access
+agentuity cloud sandbox create --memory 2Gi --network
+# sbx_abc123
+
+# Install dependencies
+agentuity cloud sandbox exec sbx_abc123 -- apt-get update
+agentuity cloud sandbox exec sbx_abc123 -- apt-get install -y python3 python3-pip
+agentuity cloud sandbox exec sbx_abc123 -- pip install numpy pandas scikit-learn
+
+# Create snapshot for reuse
+agentuity cloud sandbox snapshot create sbx_abc123 --tag python-ml
+
+# Clean up original sandbox
+agentuity cloud sandbox delete sbx_abc123
+```
+
+### Run Code from Snapshot
+
+```bash
+# Create sandbox from snapshot (fast - deps already installed)
+agentuity cloud sandbox create --snapshot python-ml
+# sbx_def456
+
+# Upload and run code
+agentuity cloud sandbox cp ./analysis.py sbx_def456:/workspace/
+agentuity cloud sandbox exec sbx_def456 -- python3 /workspace/analysis.py
+
+# Download results
+agentuity cloud sandbox cp sbx_def456:/workspace/output.csv ./results.csv
+
+# Clean up
+agentuity cloud sandbox delete sbx_def456
+```
+
+### Quick One-shot Testing
+
+```bash
+# Test Python code
+agentuity cloud sandbox run -- python3 -c "print(sum(range(100)))"
+
+# Test with dependencies from snapshot
+agentuity cloud sandbox run --snapshot python-ml -- python3 -c "import numpy; print(numpy.array([1,2,3]).mean())"
+
+# Test with network
+agentuity cloud sandbox run --network -- curl -s https://api.github.com/zen
+```
+
+## JSON Output
+
+All commands support `--json` for machine-readable output:
+
+```bash
+agentuity cloud sandbox list --json
+agentuity cloud sandbox get sbx_abc123 --json
+agentuity cloud sandbox snapshot list --json
+```
+
+## Next Steps
+
+- [Sandbox Overview](/Build/Sandbox): Understand sandbox concepts, security defaults, and when to use each execution mode
+- [SDK Usage](/Build/Sandbox/sdk-usage): Use sandboxes programmatically in agents and routes
+- [Snapshots](/Build/Sandbox/snapshots): Pre-configure environments for faster cold starts
diff --git a/content/Reference/CLI/storage.mdx b/content/Reference/CLI/storage.mdx
new file mode 100644
index 00000000..a7d3d7b2
--- /dev/null
+++ b/content/Reference/CLI/storage.mdx
@@ -0,0 +1,403 @@
+---
+title: Storage Commands
+description: Manage Key-Value, S3, Vector, Database, and Stream storage from the CLI.
+---
+
+These CLI commands help you inspect and manage cloud storage during development and debugging.
+
+
+All storage commands require the `cloud` prefix. For example: `agentuity cloud kv get ...`
+
+
+## Key-Value Storage
+
+Inspect and manage key-value data organized into namespaces.
+
+### Interactive REPL
+
+Start an interactive session for faster exploration:
+
+```bash
+agentuity cloud kv repl
+```
+
+In the REPL, use commands like `set`, `get`, `delete`, `keys`, and `stats`:
+
+```
+> set cache user:123 '{"name":"Alice"}'
+> get cache user:123
+> keys cache
+> stats
+```
+
+### Get a Value
+
+```bash
+agentuity cloud kv get production user:123
+agentuity cloud kv get cache session:abc
+```
+
+### Set a Value
+
+```bash
+# Store JSON data
+agentuity cloud kv set production user:123 '{"name":"Alice","email":"alice@example.com"}'
+
+# Set with TTL (expires after 1 hour)
+agentuity cloud kv set cache session:abc "session-data" --ttl 3600
+```
+
+### Delete a Key
+
+```bash
+agentuity cloud kv delete production user:123
+agentuity cloud kv rm cache session:abc # Using alias
+```
+
+### List Keys
+
+```bash
+agentuity cloud kv keys production
+agentuity cloud kv ls cache # Using alias
+```
+
+### Search Keys
+
+```bash
+agentuity cloud kv search production user
+agentuity cloud kv search cache session
+```
+
+### View Statistics
+
+```bash
+# Stats for all namespaces
+agentuity cloud kv stats
+
+# Stats for specific namespace
+agentuity cloud kv stats production
+```
+
+### Namespace Management
+
+A namespace is a logical container that groups related keys together. For example, you might use `cache` for temporary data, `users` for user profiles, and `sessions` for session state.
+
+```bash
+# List all namespaces
+agentuity cloud kv list-namespaces
+agentuity cloud kv ns # Using alias
+
+# Create a namespace
+agentuity cloud kv create-namespace staging
+
+# Delete a namespace and all its keys
+agentuity cloud kv delete-namespace old-cache
+```
+
+**In agents:** Use `ctx.kv` for programmatic access. See [Key-Value Storage](/Build/Storage/key-value).
+
+## S3 Storage
+
+Manage S3-compatible storage resources for file uploads and downloads.
+
+Both `cloud storage` and `cloud s3` work interchangeably. Examples below use `s3` for brevity.
+
+### Create Storage Resource
+
+```bash
+agentuity cloud storage create --name my-storage
+# or: agentuity cloud s3 create --name my-storage
+```
+
+This adds S3 credentials to your local `.env` file automatically.
+
+### List Storage Resources
+
+```bash
+agentuity cloud s3 list
+```
+
+### Upload a File
+
+```bash
+agentuity cloud s3 upload ./local-file.pdf
+```
+
+### Download a File
+
+```bash
+agentuity cloud s3 download --output ./downloaded-file.pdf
+```
+
+### Get Storage Details
+
+```bash
+agentuity cloud s3 get
+```
+
+### Delete Storage Resource
+
+```bash
+agentuity cloud s3 delete
+```
+
+**In agents:** Use Bun's `s3` API (`import { s3 } from "bun"`). See [Object Storage (S3)](/Build/Storage/object).
+
+## Object Storage (Legacy)
+
+The `cloud obj` commands provide bucket-based object management. For new projects, consider using `cloud s3` instead.
+
+### Interactive REPL
+
+```bash
+agentuity cloud obj repl
+```
+
+### Upload a File
+
+```bash
+# Upload from file path
+agentuity cloud obj put uploads images/logo.png @./logo.png
+
+# Store JSON directly
+agentuity cloud obj put assets config.json '{"api":"https://api.example.com"}'
+
+# With custom content type
+agentuity cloud obj put backups db.sql @~/backup.sql --content-type application/sql
+```
+
+### Download a File
+
+```bash
+agentuity cloud obj get uploads images/logo.png
+agentuity cloud obj get assets config.json
+```
+
+### Delete a File
+
+```bash
+agentuity cloud obj delete uploads old-image.png
+```
+
+### Generate Public URL
+
+```bash
+# Permanent URL
+agentuity cloud obj url uploads images/logo.png
+
+# Temporary URL (expires in 1 hour)
+agentuity cloud obj url uploads private-doc.pdf --expires 3600
+
+# 5-minute presigned URL
+agentuity cloud obj presigned backups db.sql --expires 300
+```
+
+### List Buckets and Files
+
+```bash
+agentuity cloud obj list-buckets
+agentuity cloud obj list-keys uploads
+agentuity cloud obj ls assets # Using alias
+```
+
+## Vector Storage
+
+Search and inspect vector embeddings.
+
+### Search by Similarity
+
+```bash
+# Basic search
+agentuity cloud vector search products "comfortable office chair"
+
+# Limit results
+agentuity cloud vector search docs "API documentation" --limit 5
+
+# Set minimum similarity threshold
+agentuity cloud vector search products "ergonomic" --similarity 0.8
+
+# Filter by metadata
+agentuity cloud vector search embeddings "neural networks" --metadata category=ai
+```
+
+### Get Vector by ID
+
+```bash
+agentuity cloud vec get
+```
+
+### Upsert Vectors
+
+Add or update vectors from a JSON file:
+
+```bash
+# Upsert from file
+agentuity cloud vector upsert products --file vectors.json
+
+# File format: array of { key, document?, embeddings?, metadata? }
+```
+
+Example `vectors.json`:
+
+```json
+[
+ {
+ "key": "product-123",
+ "document": "Ergonomic office chair with lumbar support",
+ "metadata": { "category": "furniture", "price": 299 }
+ },
+ {
+ "key": "product-456",
+ "document": "Standing desk with adjustable height",
+ "metadata": { "category": "furniture", "price": 599 }
+ }
+]
+```
+
+### Delete a Vector
+
+```bash
+agentuity cloud vec delete
+```
+
+### View Statistics
+
+```bash
+# Stats for all namespaces
+agentuity cloud vector stats
+
+# Stats for specific namespace
+agentuity cloud vector stats products
+```
+
+### List Namespaces
+
+```bash
+agentuity cloud vector namespaces
+```
+
+### Delete a Namespace
+
+Delete an entire namespace and all its vectors:
+
+```bash
+agentuity cloud vector delete-namespace old-products
+```
+
+
+Deleting a namespace removes all vectors within it. This cannot be undone.
+
+
+**In agents:** Use `ctx.vector` for programmatic access. See [Vector Storage](/Build/Storage/vector).
+
+## Database
+
+Manage database resources and run SQL queries.
+
+### List Databases
+
+```bash
+agentuity cloud db list
+```
+
+### Create a Database
+
+```bash
+agentuity cloud db create --name my-database
+```
+
+This adds `DATABASE_URL` to your local `.env` file automatically.
+
+### Get Database Details
+
+```bash
+agentuity cloud db get
+```
+
+### Run SQL Queries
+
+Execute SQL queries directly from the CLI:
+
+```bash
+# Simple query
+agentuity cloud db sql "SELECT * FROM users LIMIT 10"
+
+# Query with filtering
+agentuity cloud db sql "SELECT name, email FROM users WHERE active = true"
+
+# Insert data
+agentuity cloud db sql "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')"
+```
+
+### View Database Logs
+
+```bash
+agentuity cloud db logs
+```
+
+### Delete a Database
+
+```bash
+agentuity cloud db delete
+```
+
+**In agents:** Use Bun's `sql` API (`import { sql } from "bun"`). See [Database](/Build/Storage/database).
+
+## Streams
+
+List and manage durable event streams.
+
+### List Streams
+
+```bash
+agentuity cloud stream list
+```
+
+### Get Stream Details
+
+```bash
+agentuity cloud stream get
+```
+
+### Delete a Stream
+
+```bash
+agentuity cloud stream delete
+```
+
+**In agents:** Use `ctx.stream` for programmatic access. See [Durable Streams](/Build/Storage/durable-streams).
+
+## Redis
+
+View Redis connection details for your organization.
+
+### Show Connection URL
+
+```bash
+# Show Redis URL (credentials masked in terminal)
+agentuity cloud redis show
+
+# Show with credentials visible
+agentuity cloud redis show --show-credentials
+
+# JSON output (credentials always visible)
+agentuity --json cloud redis show
+```
+
+
+Redis is provisioned at the organization level. Contact support if you need Redis enabled for your organization.
+
+
+To use Redis locally, add the URL to your `.env`:
+
+```bash
+REDIS_URL=redis://...
+```
+
+## Next Steps
+
+- [Configuration Commands](/Reference/CLI/configuration): Manage environment variables, secrets, and API keys
+- [Key-Value Storage](/Build/Storage/key-value): Programmatic KV access in agents
+- [Object Storage (S3)](/Build/Storage/object): File storage with Bun S3
+- [Database](/Build/Storage/database): SQL queries with Bun SQL
+- [Vector Storage](/Build/Storage/vector): Semantic search in agents
diff --git a/content/Reference/meta.json b/content/Reference/meta.json
new file mode 100644
index 00000000..513312bf
--- /dev/null
+++ b/content/Reference/meta.json
@@ -0,0 +1,8 @@
+{
+ "title": "Reference",
+ "pages": [
+ "CLI",
+ "sdk-reference",
+ "migration-guide"
+ ]
+}
diff --git a/content/Reference/migration-guide.mdx b/content/Reference/migration-guide.mdx
new file mode 100644
index 00000000..35529009
--- /dev/null
+++ b/content/Reference/migration-guide.mdx
@@ -0,0 +1,639 @@
+---
+title: Migrating from v0 to v1
+description: Moving from v0? Here's everything you need to update.
+---
+
+v0 support is ending. We recommend migrating to v1 for new features and continued updates.
+
+This guide covers the breaking changes and how to update your agents.
+
+## What's New in v1?
+
+
+In v0, agents had to be created via the CLI (`agentuity agent create`) to register them with unique IDs in the cloud. In v1, just create a folder in `src/agent/` with `agent.ts` — agents are auto-discovered and registered on deploy. No CLI commands or manual registration required.
+
+
+Key improvements in v1:
+
+- **Auto-Discovery**: Create agents by adding folders, no CLI registration needed
+- **Type-Safe Schemas**: Built-in support for Zod, Valibot, ArkType, and StandardSchema libraries
+- **Advanced Routing**: WebSocket, SSE, streaming, and cron routes via middleware
+- **Bun Runtime**: Native S3 storage and SQL database support
+- **Evaluations & Events**: Test agent outputs and monitor lifecycle
+
+
+**Workbench:** v0's "DevMode" is being rebranded to "Workbench", to better support agent development both locally and in production. The v0 `welcome()` function pattern for suggested prompts has been removed as part of this redesign.
+
+
+---
+
+## Breaking Changes Overview
+
+### High Impact Changes
+
+These changes require code modifications in all agents:
+
+1. **Handler Pattern**: Default export functions replaced with `createAgent()`
+2. **Request/Response**: New pattern using direct parameters and return values
+3. **Context Properties**: `runId` renamed to `sessionId`, new properties added
+4. **Package Structure**: SDK split into multiple packages (`@agentuity/runtime`, `@agentuity/core`, etc.)
+5. **Language Support**: v1 is TypeScript-only, optimized for Bun runtime
+6. **Trigger Configuration**: Cron schedules are now configured in code using the `cron()` middleware rather than in the cloud console UI
+
+---
+
+## Step-by-Step Migration
+
+### Step 1: Create a Fresh v1 Project
+
+v1 has a different project structure, so we recommend creating a new project and migrating your agent code.
+
+Install the v1 CLI:
+
+```bash
+curl -sSL https://v1.agentuity.sh | sh
+```
+
+Create a new v1 project:
+
+```bash
+agentuity create
+```
+
+This sets up the correct project structure with all dependencies. You'll migrate your agent logic into this new project using the patterns in the following steps.
+
+---
+
+### Step 2: Update Agent Handler Pattern
+
+The most significant change is how agents are created and exported.
+
+#### Basic Agent Handler
+
+**v0:**
+```typescript
+import { AgentHandler } from '@agentuity/sdk';
+
+const handler: AgentHandler = async (request, response, context) => {
+ const data = await request.data.json();
+
+ context.logger.info('Processing request', data);
+
+ return response.json({
+ message: 'Hello from my agent!',
+ data: data
+ });
+};
+
+export default handler;
+```
+
+**v1:**
+```typescript
+// src/agent/my-agent/agent.ts
+import { createAgent } from '@agentuity/runtime';
+
+const agent = createAgent('My Agent', {
+ description: 'A simple agent',
+ handler: async (ctx, input) => {
+ ctx.logger.info('Processing request', input);
+
+ return {
+ message: 'Hello from my agent!',
+ data: input
+ };
+ }
+});
+
+export default agent;
+```
+
+**Key Changes:**
+1. Import from `@agentuity/runtime` instead of `@agentuity/sdk`
+2. Use `createAgent('Name', { ... })` with the name as the first argument
+3. Handler receives `(ctx, input)` instead of `(request, response, context)`
+4. Return values directly instead of using `response.json()`
+5. Export the agent (routes are defined separately in `src/api/`)
+
+**File Structure Change:**
+In v0, agents were typically single files. In v1, agents and routes are separated:
+- **`src/agent/my-agent/agent.ts`** - Contains the `createAgent()` call with your handler logic
+- **`src/api/index.ts`** - Contains all HTTP routes that import and call agents
+
+Routes import agents and call them via `agent.run(input)`. This separation keeps HTTP routing concerns separate from agent core logic, making agents reusable across different routes.
+
+---
+
+#### Agent with Schema Validation
+
+v1 introduces optional schema validation for type safety:
+
+```typescript
+// src/agent/typed-agent/agent.ts
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('Typed Agent', {
+ description: 'An agent with type-safe inputs and outputs',
+ schema: {
+ input: z.object({
+ message: z.string(),
+ count: z.number().optional()
+ }),
+ output: z.object({
+ response: z.string(),
+ timestamp: z.number()
+ })
+ },
+ handler: async (ctx, input) => {
+ // input is fully typed as { message: string, count?: number }
+
+ return {
+ response: `Received: ${input.message}`,
+ timestamp: Date.now()
+ };
+ // Return type is validated automatically
+ }
+});
+
+export default agent;
+```
+
+```typescript
+// src/api/index.ts - All routes are consolidated here
+import { createRouter } from '@agentuity/runtime';
+import typedAgent from '@agent/typed-agent';
+
+const router = createRouter();
+
+// Routes are mounted at /api/* automatically
+router.post('/typed-agent', typedAgent.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await typedAgent.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+**Benefits:**
+- Full TypeScript autocomplete
+- Runtime validation of inputs and outputs
+- Automatic error handling for invalid data
+- Self-documenting API contracts
+
+---
+
+### Step 3: Update Context Usage
+
+The context object has several changes and additions.
+
+#### Context Property Changes
+
+**v0:**
+```typescript
+const handler: AgentHandler = async (request, response, context) => {
+ // Access run ID
+ const id = context.runId;
+
+ // Access services
+ await context.kv.set('cache', 'key', data);
+
+ // Access logger
+ context.logger.info('Message');
+};
+```
+
+**v1:**
+```typescript
+const agent = createAgent('My Agent', {
+ handler: async (ctx, input) => {
+ // runId renamed to sessionId
+ const id = ctx.sessionId;
+
+ // Services work the same way
+ await ctx.kv.set('cache', 'key', data);
+
+ // Logger unchanged
+ ctx.logger.info('Message');
+
+ // NEW: State management
+ ctx.state.set('myKey', 'myValue');
+
+ // NEW: Session and thread objects
+ ctx.logger.info('Session:', ctx.session);
+ ctx.logger.info('Thread:', ctx.thread);
+
+ return { result: 'done' };
+ }
+});
+```
+
+**Key Changes:**
+- `context.runId` → `ctx.sessionId`
+- New `ctx.state` for temporary state storage
+- New `ctx.session` and `ctx.thread` for conversation management
+- Agent-to-agent communication uses imports (see Step 7)
+
+---
+
+### Step 4: Update Request Handling
+
+Request handling is simplified in v1.
+
+#### Accessing Request Data
+
+**v0:**
+```typescript
+const handler: AgentHandler = async (request, response, context) => {
+ // Get JSON data
+ const data = await request.data.json();
+
+ // Get text data
+ const text = await request.data.text();
+
+ // Get binary data
+ const binary = await request.data.binary();
+
+ // Get metadata
+ const userId = request.get('userId');
+ const trigger = request.trigger;
+};
+```
+
+**v1 (HTTP Routes):**
+```typescript
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.post('/my-agent', async (c) => {
+ // Get JSON body directly from Hono context
+ const data = await c.req.json();
+
+ // Get text body
+ const text = await c.req.text();
+
+ // Get headers
+ const userId = c.req.header('x-user-id');
+
+ // Get query params
+ const param = c.req.query('param');
+
+ return { processed: data };
+});
+
+export default router;
+```
+
+**v1 (Agent with Schema):**
+```typescript
+const agent = createAgent('My Agent', {
+ schema: {
+ input: z.object({ message: z.string() })
+ },
+ handler: async (ctx, input) => {
+ // Input is automatically parsed and validated
+ // No need to call request.data.json()
+ ctx.logger.info('Input message:', { message: input.message });
+
+ return { response: 'ok' };
+ }
+});
+```
+
+---
+
+### Step 5: Update Response Handling
+
+Responses are now returned directly instead of using a response builder.
+
+#### Basic Responses
+
+**v0:**
+```typescript
+const handler: AgentHandler = async (request, response, context) => {
+ // JSON response
+ return response.json({ message: 'Hello' });
+
+ // Text response
+ return response.text('Hello');
+
+ // Binary response
+ return response.binary(buffer);
+
+ // Empty response
+ return response.empty();
+};
+```
+
+**v1:**
+```typescript
+const agent = createAgent('My Agent', {
+ handler: async (ctx, input) => {
+ // JSON response - just return an object
+ return { message: 'Hello' };
+
+ // Text response - return a string
+ return 'Hello';
+ }
+});
+
+// For more control over responses, use routes in src/api/index.ts:
+router.get('/hello', async (c) => {
+ const result = await myAgent.run({ name: 'World' });
+ return c.json(result); // JSON response
+ return c.text('Hello'); // Text response
+ return c.body(buffer); // Binary response
+});
+```
+
+**Key Changes:**
+1. No `response` object - return values directly from agent handler
+2. Objects are automatically JSON-serialized
+3. Use Hono context methods in routes for advanced responses
+4. For typed responses, define output schema
+
+---
+
+### Step 6: Update Service Usage
+
+
+KV and Vector storage APIs are unchanged.
+
+
+#### Object Storage → Bun S3
+
+Object storage has been replaced with Bun's native S3 APIs for better performance and simpler code:
+
+**v0/Early v1:**
+```typescript
+// Store file
+await context.objectstore.put('uploads', 'hello.txt', data, {
+ contentType: 'text/plain',
+});
+
+// Get file
+const result = await context.objectstore.get('uploads', 'hello.txt');
+if (result.exists) {
+ const text = new TextDecoder().decode(result.data);
+}
+
+// Create public URL
+const url = await context.objectstore.createPublicURL('uploads', 'file.pdf', {
+ expiresDuration: 3600000,
+});
+
+// Delete file
+await context.objectstore.delete('uploads', 'hello.txt');
+```
+
+**v1 (Bun S3):**
+```typescript
+import { s3 } from "bun";
+
+// Store file
+const file = s3.file("uploads/hello.txt");
+await file.write("Hello, World!", { type: "text/plain" });
+
+// Get file
+if (await file.exists()) {
+ const text = await file.text();
+}
+
+// Presign URL (synchronous, no network request)
+const url = s3.presign("uploads/file.pdf", {
+ expiresIn: 3600, // seconds, not milliseconds
+});
+
+// Delete file
+await file.delete();
+```
+
+**Key Changes:**
+1. Import `s3` from `"bun"` instead of using `ctx.objectstore`
+2. Use `s3.file(path)` to create a lazy file reference
+3. `presign()` takes seconds, not milliseconds, and is synchronous
+4. File operations are methods on the file object: `file.write()`, `file.text()`, `file.delete()`
+5. Credentials are auto-injected via environment variables
+
+
+Agentuity automatically injects S3 credentials (`S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_BUCKET`, `S3_ENDPOINT`) during development and deployment.
+
+
+#### Database Support
+
+v1 adds SQL database support via Bun's native SQL APIs:
+
+```typescript
+import { sql } from "bun";
+
+// Query with automatic parameter escaping (prevents SQL injection)
+const users = await sql`SELECT * FROM users WHERE active = ${true}`;
+
+// Insert data
+await sql`INSERT INTO users (name, email) VALUES (${"Alice"}, ${"alice@example.com"})`;
+
+// Transactions
+await sql.begin(async (tx) => {
+ await tx`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`;
+ await tx`UPDATE accounts SET balance = balance + ${amount} WHERE id = ${toId}`;
+});
+```
+
+
+Agentuity automatically injects `DATABASE_URL` during development and deployment.
+
+
+---
+
+### Step 7: Update Agent-to-Agent Communication
+
+Agent-to-agent communication uses direct imports in v1.
+
+**v0:**
+```typescript
+const handler: AgentHandler = async (request, response, context) => {
+ // Get agent by ID
+ const agent = await context.getAgent({ id: 'agent_123' });
+
+ // Or by name
+ const agent = await context.getAgent({
+ name: 'other-agent',
+ projectId: 'proj_123'
+ });
+
+ // Run the agent
+ const result = await agent.run({
+ data: JSON.stringify({ message: 'Hello' }),
+ contentType: 'application/json'
+ });
+
+ const output = await result.data.json();
+};
+```
+
+**v1:**
+```typescript
+// src/agent/coordinator/agent.ts
+import { createAgent } from '@agentuity/runtime';
+import otherAgent from '@agent/other-agent';
+
+const agent = createAgent('Coordinator', {
+ handler: async (ctx, input) => {
+ // Import and call agents directly
+ const result = await otherAgent.run({
+ message: 'Hello'
+ });
+
+ // Result is automatically typed if the agent has a schema
+ ctx.logger.info('Agent response:', { response: result });
+
+ return result;
+ }
+});
+
+export default agent;
+```
+
+**Key Changes:**
+1. Import agents using `import agent from '@agent/agent-name'`
+2. Call directly with `agent.run(input)`
+3. No need to JSON-stringify data
+4. Type-safe when using schemas
+
+---
+
+## Other v1 Features
+
+These features are optional but can improve your agents.
+
+### Cron Routes
+
+v1 adds cron routes via middleware. See [Routes documentation](/Build/Routes) for WebSocket, SSE, and streaming.
+
+```typescript
+import { cron } from '@agentuity/runtime';
+
+router.post('/daily-job', cron('0 0 * * *', async (c) => {
+ c.var.logger.info('Daily job running');
+ return { status: 'completed' };
+}));
+```
+
+### Evaluations
+
+Test agent outputs automatically with `agent.createEval()`. See [Evaluations](/Build/Agents/evaluations).
+
+### Event Listeners
+
+Monitor agent lifecycle with `agent.addEventListener('started' | 'completed' | 'errored', ...)`. See [Events](/Build/Agents/events-lifecycle).
+
+### Sessions and Threads
+
+Manage conversational state with `ctx.session` and `ctx.thread`. See [State Management](/Build/Agents/state-management).
+
+---
+
+## Troubleshooting
+
+#### Issue 1: "Cannot find module '@agentuity/sdk'"
+
+**Cause**: You haven't updated your imports from v0 to v1.
+
+**Solution**: Change all imports from:
+```typescript
+import { ... } from '@agentuity/sdk';
+```
+
+To:
+```typescript
+import { ... } from '@agentuity/runtime';
+```
+
+---
+
+#### Issue 2: "Property 'runId' does not exist on type 'AgentContext'"
+
+**Cause**: `runId` was renamed to `sessionId` in v1.
+
+**Solution**: Replace all instances of `context.runId` with `ctx.sessionId`.
+
+---
+
+#### Issue 3: "Handler is not a function"
+
+**Cause**: You're not exporting the agent correctly.
+
+**Solution**: Export the agent from `agent.ts` and import it in your routes:
+```typescript
+// src/agent/my-agent/agent.ts
+const agent = createAgent('My Agent', { ... });
+export default agent;
+
+// src/api/index.ts
+import myAgent from '@agent/my-agent';
+router.post('/my-agent', async (c) => {
+ const result = await myAgent.run(await c.req.json());
+ return c.json(result);
+});
+```
+
+---
+
+#### Issue 4: "Input validation failed"
+
+**Cause**: You defined an input schema but the incoming data doesn't match it.
+
+**Solution**: Check your schema definition and ensure incoming data matches:
+```typescript
+const agent = createAgent('My Agent', {
+ schema: {
+ input: z.object({
+ message: z.string(),
+ // Make optional fields explicit
+ metadata: z.record(z.unknown()).optional()
+ })
+ },
+ handler: async (ctx, input) => {
+ // ...
+ }
+});
+```
+
+---
+
+#### Issue 5: "Cannot find agent" or import errors
+
+**Cause**: Agent import path is incorrect.
+
+**Solution**: Use the `@agent/` alias to import agents:
+```typescript
+// Correct - use @agent/ alias
+import myAgent from '@agent/my-agent';
+
+// The alias maps to src/agent/
+// So @agent/my-agent resolves to src/agent/my-agent/agent.ts
+```
+
+---
+
+### Getting Help
+
+If you encounter issues not covered in this guide:
+
+1. **Check the Documentation**: Visit the [SDK Reference](/Reference/sdk-reference) for detailed information
+2. **Review Examples**: Browse the [Cookbook](/Learn/Cookbook/overview) for working patterns
+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
+
+---
+
+## Next Steps
+
+After migrating your agents:
+
+1. **Add Schema Validation**: Improve type safety with [Schema Validation](/Build/Routes/http)
+2. **Implement Evaluations**: Ensure quality with [Evaluations](/Build/Agents/evaluations)
+3. **Use Advanced Routing**: Explore [WebSocket](/Build/Routes/websockets), [SSE](/Build/Routes/sse), and [other routes](/Build/Routes)
+4. **Add Event Listeners**: Monitor your agents with [Events & Lifecycle](/Build/Agents/events-lifecycle)
diff --git a/content/Reference/sdk-reference.mdx b/content/Reference/sdk-reference.mdx
new file mode 100644
index 00000000..94c5799f
--- /dev/null
+++ b/content/Reference/sdk-reference.mdx
@@ -0,0 +1,3310 @@
+---
+title: SDK Reference
+description: Comprehensive reference for the Agentuity TypeScript/JavaScript SDK
+---
+
+This section provides detailed documentation for the Agentuity TypeScript/JavaScript SDK, including method signatures, parameters, return values, and example usage.
+
+## Table of Contents
+
+- [Application Entry Point](#application-entry-point)
+- [Agent Creation](#agent-creation)
+- [Schema Validation](#schema-validation)
+- [Agent Handler](#agent-handler)
+- [Context API](#context-api)
+- [Router & Routes](#router--routes)
+- [Agent Communication](#agent-communication)
+- [Storage APIs](#storage-apis)
+- [Logging](#logging)
+- [Telemetry](#telemetry)
+- [Session & Thread Management](#session--thread-management)
+- [Evaluations](#evaluations)
+- [Event System](#event-system)
+- [Advanced Features](#advanced-features)
+
+---
+
+## Application Entry Point
+
+Every Agentuity v1 application starts with creating an application instance using the `createApp()` function. This function initializes your application with the necessary configuration, router, server, and event system.
+
+### createApp
+
+`createApp(config?: AppConfig): App`
+
+Creates and initializes an Agentuity application instance.
+
+**Parameters**
+
+- `config` (optional): Application configuration object
+ - `cors`: Override default CORS settings
+ - `services`: Override default services (KV, Vector, Stream)
+ - `useLocal`: Use local services for development (default: false)
+ - `keyvalue`: Custom KeyValueStorage implementation
+ - `vector`: Custom VectorStorage implementation
+ - `stream`: Custom StreamStorage implementation
+ - `setup`: Async function called before server starts, returns app state available via `ctx.app`
+ - `shutdown`: Async cleanup function called when server stops, receives app state
+
+**Return Value**
+
+Returns an `App` instance with the following properties:
+
+```typescript
+interface App {
+ router: Hono; // The main application router
+ server: Server; // Server instance with .url property
+ logger: Logger; // Application-level logger
+}
+```
+
+**Note:** The App instance also provides `addEventListener()` and `removeEventListener()` methods for lifecycle events. See the [Event System](#event-system) section for details.
+
+**Basic Example**
+
+```typescript
+// app.ts
+import { createApp } from '@agentuity/runtime';
+
+// Create the application instance (async)
+const { server, logger } = await createApp();
+
+// The application will automatically discover and mount agents
+// from the agents directory specified in your agentuity.json
+
+// Access application properties
+logger.info(`Server running at ${server.url}`);
+```
+
+**With Configuration**
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ // Custom CORS settings
+ cors: {
+ origin: ['https://example.com'],
+ credentials: true
+ },
+ // Use local services for development
+ services: {
+ useLocal: true
+ }
+});
+```
+
+**With Setup and Shutdown**
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { server, logger } = await createApp({
+ // Initialize shared resources
+ setup: async () => {
+ const db = await connectDatabase();
+ const redis = await connectRedis();
+ return { db, redis };
+ },
+ // Clean up on shutdown
+ shutdown: async (state) => {
+ await state.db.close();
+ await state.redis.quit();
+ },
+});
+
+// In agents, access via ctx.app:
+// ctx.app.db.query('SELECT * FROM users')
+```
+
+### Environment Variables
+
+Agentuity applications access configuration and secrets through standard Node.js environment variables (`process.env`).
+
+**Standard Environment Variables:**
+
+- `AGENTUITY_SDK_KEY` - SDK-level API key (used in development to access Agentuity Cloud)
+- `AGENTUITY_PROJECT_KEY` - Project-level API key (used when deployed)
+
+**Example**
+
+```typescript
+// app.ts
+import { createApp } from '@agentuity/runtime';
+
+if (!process.env.AGENTUITY_SDK_KEY) {
+ console.error('Missing AGENTUITY_SDK_KEY environment variable');
+ process.exit(1);
+}
+
+const { server, logger } = await createApp();
+
+// Access other environment variables
+const apiEndpoint = process.env.API_ENDPOINT || 'https://api.example.com';
+const openaiKey = process.env.OPENAI_API_KEY;
+// Optional: you can use the AI Gateway to access OpenAI, Anthropic, etc without needing to set various API keys.
+```
+
+**Note**: Environment variables are typically loaded from a `.env` file in development and configured in your deployment environment.
+
+---
+
+## Agent Creation
+
+Agents are created using the `createAgent()` function, which provides type-safe agent definitions with built-in schema validation.
+
+### createAgent
+
+`createAgent(name: string, config: AgentConfig): AgentRunner`
+
+Creates a new agent with schema validation and type inference.
+
+**Parameters**
+
+- `name`: Unique agent name (must be unique within the project)
+- `config`: Configuration object with the following properties:
+ - `description` (optional): Human-readable description of what the agent does
+ - `schema` (optional): Object containing input and output schemas
+ - `input`: Schema for validating incoming data (Zod, Valibot, ArkType, or any StandardSchemaV1)
+ - `output`: Schema for validating outgoing data
+ - `stream`: Enable streaming responses (boolean, defaults to false)
+ - `handler`: The agent function that processes inputs and returns outputs
+ - `setup` (optional): Async function called once on app startup, returns agent-specific config accessible via `ctx.config`
+ - `shutdown` (optional): Async cleanup function called on app shutdown
+
+**Return Value**
+
+Returns an `AgentRunner` object with the following properties:
+- `metadata`: Agent metadata (id, identifier, filename, version, name, description)
+- `run(input?)`: Execute the agent with optional input
+- `createEval(name, config)`: Create quality evaluations for this agent
+- `addEventListener(eventName, callback)`: Attach lifecycle event listeners
+- `removeEventListener(eventName, callback)`: Remove event listeners
+- `validator(options?)`: Route validation middleware (see below)
+- `inputSchema` (conditional): Present if input schema is defined
+- `outputSchema` (conditional): Present if output schema is defined
+- `stream` (conditional): Present if streaming is enabled
+
+**Note**: To call agents from other agents, import them directly: `import otherAgent from '@agent/other'; otherAgent.run(input)` (see [Agent Communication](#agent-communication)).
+
+### Agent Setup and Shutdown
+
+Agents can define `setup` and `shutdown` functions for initialization and cleanup:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('CachedProcessor', {
+ schema: {
+ input: z.object({ key: z.string() }),
+ output: z.object({ value: z.string() }),
+ },
+ // Called once when app starts - return value available via ctx.config
+ setup: async (app) => {
+ const cache = new Map();
+ const client = await initializeExternalService();
+ return { cache, client };
+ },
+ // Called when app shuts down
+ shutdown: async (app, config) => {
+ await config.client.disconnect();
+ config.cache.clear();
+ },
+ handler: async (ctx, input) => {
+ // ctx.config is fully typed from setup's return value
+ const cached = ctx.config.cache.get(input.key);
+ if (cached) {
+ return { value: cached };
+ }
+
+ const value = await ctx.config.client.fetch(input.key);
+ ctx.config.cache.set(input.key, value);
+ return { value };
+ },
+});
+
+export default agent;
+```
+
+The `setup` function receives the app state (from `createApp`'s setup) and returns agent-specific configuration. This is useful for:
+- Agent-specific caches or connection pools
+- Pre-computed data or models
+- External service clients
+
+### agent.validator()
+
+Creates Hono middleware for type-safe request validation using the agent's schema.
+
+**Signatures**
+
+```typescript
+agent.validator(): MiddlewareHandler
+agent.validator(options: { output: Schema }): MiddlewareHandler
+agent.validator(options: { input: Schema; output?: Schema }): MiddlewareHandler
+```
+
+**Options**
+- No options: Uses agent's input/output schemas
+- `{ output: Schema }`: Output-only validation (useful for GET routes)
+- `{ input: Schema, output?: Schema }`: Custom schema override
+
+**Example**
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import agent from './agent';
+
+const router = createRouter();
+
+// Use agent's schema
+router.post('/', agent.validator(), async (c) => {
+ const data = c.req.valid('json'); // Fully typed
+ return c.json(data);
+});
+
+// Custom schema override
+router.post('/custom',
+ agent.validator({ input: z.object({ custom: z.string() }) }),
+ async (c) => {
+ const data = c.req.valid('json');
+ return c.json(data);
+ }
+);
+```
+
+Returns 400 Bad Request with validation error details if input validation fails.
+
+**Example**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('GreetingAgent', {
+ description: 'A simple greeting agent that responds to user messages',
+ schema: {
+ input: z.object({
+ message: z.string().min(1),
+ userId: z.string().optional(),
+ }),
+ output: z.object({
+ response: z.string(),
+ timestamp: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Input is automatically validated and typed
+ ctx.logger.info(`Processing message from user: ${input.userId ?? 'anonymous'}`);
+
+ return {
+ response: `Hello! You said: ${input.message}`,
+ timestamp: Date.now(),
+ };
+ },
+});
+
+export default agent;
+```
+
+### Agent Configuration
+
+The agent configuration object defines the structure and behavior of your agent.
+
+**Schema Property**
+
+The `schema` property defines input and output validation using any library that implements StandardSchemaV1:
+
+```typescript
+// Using Zod
+import { z } from 'zod';
+
+const agent = createAgent('Greeter', {
+ schema: {
+ input: z.object({ name: z.string() }),
+ output: z.object({ greeting: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ return { greeting: `Hello, ${input.name}!` };
+ },
+});
+```
+
+```typescript
+// Using Valibot
+import * as v from 'valibot';
+
+const agent = createAgent('Greeter', {
+ schema: {
+ input: v.object({ name: v.string() }),
+ output: v.object({ greeting: v.string() }),
+ },
+ handler: async (ctx, input) => {
+ return { greeting: `Hello, ${input.name}!` };
+ },
+});
+```
+
+**Metadata Property**
+
+Agent metadata provides information about the agent for documentation and tooling:
+
+```typescript
+const agent = createAgent('DataProcessor', {
+ description: 'Processes and transforms user data',
+ schema: {
+ input: inputSchema,
+ output: outputSchema,
+ },
+ handler: async (ctx, input) => {
+ // Agent logic
+ },
+});
+```
+
+---
+
+## Schema Validation
+
+The SDK includes built-in schema validation using the StandardSchemaV1 interface, providing runtime type safety and automatic validation.
+
+### StandardSchema Support
+
+The SDK supports any validation library that implements the StandardSchemaV1 interface:
+
+**Supported Libraries:**
+- **Zod** - Most popular, recommended for new projects
+- **Valibot** - Lightweight alternative with similar API
+- **ArkType** - TypeScript-first validation
+- Any library implementing StandardSchemaV1
+
+**Why StandardSchema?**
+
+StandardSchemaV1 is a common interface that allows different validation libraries to work seamlessly with the SDK, so you're not locked into a single library and can choose the one that best fits your needs. For more details on schema validation patterns and best practices, see the [Schema Validation Guide](/Guides/schema-validation).
+
+**Example with Zod:**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('UserCreator', {
+ schema: {
+ input: z.object({
+ email: z.string().email(),
+ age: z.number().min(0).max(120),
+ preferences: z.object({
+ newsletter: z.boolean(),
+ notifications: z.boolean(),
+ }).optional(),
+ }),
+ output: z.object({
+ userId: z.string().uuid(),
+ created: z.date(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Input is validated before handler runs
+ // TypeScript knows exact shape of input
+
+ ctx.logger.info(`Creating user: ${input.email}`);
+
+ return {
+ userId: crypto.randomUUID(),
+ created: new Date(),
+ };
+ },
+});
+```
+
+**Validation Behavior:**
+
+- **Input validation**: Automatic before handler execution. If validation fails, an error is thrown and the handler is not called.
+- **Output validation**: Automatic after handler execution. If validation fails, an error is thrown before returning to the caller.
+- **Error messages**: Schema validation errors include detailed information about what failed and why.
+
+### Type Inference
+
+TypeScript automatically infers types from your schemas, providing full autocomplete and type checking:
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('SearchAgent', {
+ schema: {
+ input: z.object({
+ query: z.string(),
+ filters: z.object({
+ category: z.enum(['tech', 'business', 'sports']),
+ limit: z.number().default(10),
+ }),
+ }),
+ output: z.object({
+ results: z.array(z.object({
+ id: z.string(),
+ title: z.string(),
+ score: z.number(),
+ })),
+ total: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // TypeScript knows:
+ // - input.query is string
+ // - input.filters.category is 'tech' | 'business' | 'sports'
+ // - input.filters.limit is number
+
+ // Return type is also validated
+ return {
+ results: [
+ { id: '1', title: 'Example', score: 0.95 },
+ ],
+ total: 1,
+ };
+
+ // This would cause a TypeScript error:
+ // return { invalid: 'structure' };
+ },
+});
+
+// When calling the agent from another agent:
+import searchAgent from '@agent/search';
+
+const result = await searchAgent.run({
+ query: 'agentic AI',
+ filters: { category: 'tech', limit: 5 },
+});
+
+// TypeScript knows result has this shape:
+// {
+// results: Array<{ id: string; title: string; score: number }>;
+// total: number;
+// }
+```
+
+**Benefits of Type Inference:**
+- Full IDE autocomplete for input and output
+- Compile-time type checking catches errors before runtime
+- No need to manually define TypeScript interfaces
+- Refactoring is safer - changes to schemas update types automatically
+
+---
+
+## Agent Handler
+
+The agent handler is the core function that processes inputs and produces outputs.
+
+### Handler Signature
+
+The handler signature has changed significantly from v0:
+
+```typescript
+type AgentHandler = (
+ ctx: AgentContext,
+ input: TInput
+) => Promise | TOutput;
+```
+
+**Parameters**
+
+- `ctx`: The agent context providing access to services, logging, and agent capabilities
+- `input`: The validated input data (typed according to your input schema)
+
+**Return Value**
+
+The handler should return the output data (typed according to your output schema). The return can be:
+- A direct value: `return { result: 'value' }`
+- A Promise: `return Promise.resolve({ result: 'value' })`
+- An async function automatically returns a Promise
+
+**Key Differences from v0:**
+
+| Aspect | v0 | v1 |
+|--------|-----|-----|
+| **Parameters** | `(request, response, context)` | `(ctx, input)` |
+| **Input access** | `await request.data.json()` | Direct `input` parameter |
+| **Return pattern** | `return response.json(data)` | `return data` |
+| **Validation** | Manual | Automatic via schemas |
+| **Type safety** | Manual types | Auto-inferred from schemas |
+
+**Example Comparison:**
+
+```typescript
+// v0 pattern
+export default async (request, response, context) => {
+ const { name } = await request.data.json();
+ context.logger.info(`Hello ${name}`);
+ return response.json({ greeting: `Hello, ${name}!` });
+};
+```
+
+```typescript
+// v1 pattern
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+export default createAgent('Greeter', {
+ schema: {
+ input: z.object({ name: z.string() }),
+ output: z.object({ greeting: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ ctx.logger.info(`Hello ${input.name}`);
+ return { greeting: `Hello, ${input.name}!` };
+ },
+});
+```
+
+### Input Validation
+
+Input validation happens automatically before the handler executes:
+
+```typescript
+const agent = createAgent('UserValidator', {
+ schema: {
+ input: z.object({
+ email: z.string().email(),
+ age: z.number().min(18),
+ }),
+ output: z.object({
+ success: z.boolean(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // This code only runs if:
+ // - input.email is a valid email format
+ // - input.age is a number >= 18
+
+ ctx.logger.info(`Valid user: ${input.email}, age ${input.age}`);
+
+ return { success: true };
+ },
+});
+```
+
+**Validation Errors:**
+
+If validation fails, the handler is not called and an error response is returned:
+
+```typescript
+// Request with invalid input:
+// { email: "not-an-email", age: 15 }
+
+// Results in validation error thrown before handler:
+// Error: Validation failed
+// - email: Invalid email format
+// - age: Number must be greater than or equal to 18
+```
+
+### Return Values
+
+Handlers return data directly rather than using response builder methods:
+
+**Simple Returns:**
+
+```typescript
+const agent = createAgent('Adder', {
+ schema: {
+ input: z.object({ x: z.number(), y: z.number() }),
+ output: z.object({ sum: z.number() }),
+ },
+ handler: async (ctx, input) => {
+ return { sum: input.x + input.y };
+ },
+});
+```
+
+**Async Processing:**
+
+```typescript
+const agent = createAgent('UserFetcher', {
+ schema: {
+ input: z.object({ userId: z.string() }),
+ output: z.object({
+ user: z.object({
+ id: z.string(),
+ name: z.string(),
+ }),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Await async operations
+ const userData = await fetchUserFromDatabase(input.userId);
+
+ // Return the result
+ return {
+ user: {
+ id: userData.id,
+ name: userData.name,
+ },
+ };
+ },
+});
+```
+
+**Error Handling:**
+
+```typescript
+const agent = createAgent('RiskyOperator', {
+ schema: {
+ input: z.object({ id: z.string() }),
+ output: z.object({ data: z.any() }),
+ },
+ handler: async (ctx, input) => {
+ try {
+ const data = await riskyOperation(input.id);
+ return { data };
+ } catch (error) {
+ ctx.logger.error('Operation failed', { error });
+ throw new Error('Failed to process request');
+ }
+ },
+});
+```
+
+**Output Validation:**
+
+The return value is automatically validated against the output schema:
+
+```typescript
+const agent = createAgent('ValueChecker', {
+ schema: {
+ input: z.object({ value: z.number() }),
+ output: z.object({
+ result: z.number(),
+ isPositive: z.boolean(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // This would fail output validation:
+ // return { result: input.value };
+ // Error: Missing required field 'isPositive'
+
+ // This passes validation:
+ return {
+ result: input.value,
+ isPositive: input.value > 0,
+ };
+ },
+});
+```
+
+---
+
+## Context API
+
+The `AgentContext` provides access to various capabilities and services within your agent handler, including storage APIs, logging, tracing, agent communication, and state management.
+
+### Context Properties
+
+The context object passed to your agent handler contains the following properties:
+
+```typescript
+interface AgentContext {
+ // Identifiers
+ sessionId: string; // Unique ID for this agent execution
+ current: { // Current agent metadata
+ name: string; // Agent name from createAgent()
+ agentId: string; // Stable across deployments
+ id: string; // Changes each deployment
+ filename: string; // Path to agent file
+ version: string; // Changes when code changes
+ };
+
+ // Agent Calling (use imports instead)
+ // import otherAgent from '@agent/other-agent';
+ // await otherAgent.run(input);
+
+ // Configuration
+ config: TConfig; // Agent-specific config from setup()
+ app: TAppState; // App-wide state from createApp setup()
+
+ // State Management
+ session: Session; // Session object for cross-request state
+ thread: Thread; // Thread object for conversation state
+ state: Map; // Request-scoped state storage
+
+ // Storage Services
+ kv: KeyValueStorage; // Key-value storage
+ vector: VectorStorage; // Vector database for embeddings
+ stream: StreamStorage; // Stream storage
+
+ // Observability
+ logger: Logger; // Structured logging
+ tracer: Tracer; // OpenTelemetry tracing
+
+ // Lifecycle
+ waitUntil(promise: Promise | (() => void | Promise)): void;
+}
+```
+
+**Key Properties Explained:**
+
+**Identifiers:**
+- `sessionId`: Unique identifier for this agent execution. Use for tracking and correlating logs.
+- `current`: Metadata about the currently executing agent:
+ - `name`: The name passed to `createAgent()`.
+ - `agentId`: Stays the same across deployments. Use for state keys (e.g., `${ctx.current.agentId}_counter`).
+ - `id`: Changes with each deployment. Use when you need deployment-specific identifiers.
+ - `filename`: Relative path to the agent file.
+ - `version`: Changes when agent code changes. Use for cache keys or versioned storage.
+ - `description?`: Human-readable description from `createAgent()` config.
+ - `inputSchemaCode?`: Source code for the input schema (if defined).
+ - `outputSchemaCode?`: Source code for the output schema (if defined).
+
+**Configuration:**
+- `config`: Agent-specific configuration returned from the agent's `setup()` function. Fully typed based on what setup returns.
+- `app`: Application-wide state returned from `createApp()`'s `setup()` function. Shared across all agents.
+
+**Agent Calling:**
+- Import agents directly: `import otherAgent from '@agent/other-agent'`
+- Call with: `await otherAgent.run(input)`
+
+**State Management:**
+- `session`: Persistent session object that spans multiple agent calls.
+- `thread`: Thread object for managing conversation state.
+- `state`: Map for storing request-scoped data that persists throughout the handler execution.
+
+**Example Usage:**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('QueryProcessor', {
+ schema: {
+ input: z.object({ query: z.string() }),
+ output: z.object({ result: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Access session ID
+ ctx.logger.info(`Session ID: ${ctx.sessionId}`);
+
+ // Use storage services
+ await ctx.kv.set('cache', 'last-query', input.query);
+
+ // Store request-scoped data
+ ctx.state.set('startTime', Date.now());
+
+ // Call another agent (import at top of file)
+ // import enrichmentAgent from '@agent/enrichment';
+ const enrichedData = await enrichmentAgent.run({ text: input.query });
+
+ // Use session state
+ ctx.session.state.set('queryCount',
+ (ctx.session.state.get('queryCount') as number || 0) + 1
+ );
+
+ return { result: enrichedData.output };
+ },
+});
+```
+
+### Background Tasks (waitUntil)
+
+The `waitUntil` method allows you to execute background tasks that don't need to block the immediate response to the caller. These tasks will be completed after the main response is sent.
+
+#### waitUntil
+
+`waitUntil(callback: Promise | (() => void | Promise)): void`
+
+Defers the execution of a background task until after the main response has been sent.
+
+**Parameters**
+
+- `callback`: A Promise, or a function that returns either void (synchronous) or a Promise (asynchronous), to be executed in the background
+
+**Example**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('MessageReceiver', {
+ schema: {
+ input: z.object({ userId: z.string(), message: z.string() }),
+ output: z.object({ status: z.string(), timestamp: z.number() }),
+ },
+ handler: async (ctx, input) => {
+ const responseData = {
+ status: 'received',
+ timestamp: Date.now(),
+ };
+
+ // Schedule background tasks (async functions)
+ ctx.waitUntil(async () => {
+ // Log the message asynchronously
+ await logMessageToDatabase(input.userId, input.message);
+ });
+
+ ctx.waitUntil(async () => {
+ // Send push notification in the background
+ await sendPushNotification(input.userId, input.message);
+ });
+
+ // Can also use synchronous functions
+ ctx.waitUntil(() => {
+ // Update analytics synchronously
+ updateAnalyticsSync(input.userId, 'message_received');
+ });
+
+ // Return immediately without waiting for background tasks
+ return responseData;
+ },
+});
+```
+
+**Use Cases**
+
+- Logging and analytics that don't affect the user experience
+- Sending push notifications
+- Database cleanup or maintenance tasks
+- Third-party API calls that don't impact the response
+- Background data processing or enrichment
+
+---
+
+## Storage APIs
+
+The SDK provides five storage options: Key-Value, Vector, Database (SQL), Object (S3), and Stream. Built-in services (KV, Vector, Stream) are accessed through the agent context (`ctx.*`), while Database and Object storage use Bun's native APIs (`sql`, `s3`).
+
+### Key-Value Storage
+
+The Key-Value Storage API provides a simple way to store and retrieve data. It is accessed through the `ctx.kv` object.
+
+#### get
+
+`get(name: string, key: string): Promise`
+
+Retrieves a value from the key-value storage.
+
+**Parameters**
+
+- `name`: The name of the key-value storage
+- `key`: The key to retrieve the value for
+
+**Return Value**
+
+Returns a Promise that resolves to a `DataResult` object with:
+- `exists`: boolean indicating if the value was found
+- `data`: the actual value of type T (only present when exists is true)
+- `contentType`: the content type of the stored value
+
+**Example**
+
+```typescript
+// Retrieve a value from key-value storage
+const result = await ctx.kv.get<{ theme: string }>('user-preferences', 'user-123');
+if (result.exists) {
+ // data is only accessible when exists is true
+ ctx.logger.info('User preferences:', result.data);
+} else {
+ ctx.logger.info('User preferences not found');
+}
+```
+
+#### set
+
+`set(name: string, key: string, value: ArrayBuffer | string | Json, ttl?: number): Promise`
+
+Stores a value in the key-value storage.
+
+**Parameters**
+
+- `name`: The name of the key-value storage
+- `key`: The key to store the value under
+- `value`: The value to store (can be an ArrayBuffer, string, or JSON object)
+- `ttl` (optional): Time-to-live in seconds (minimum 60 seconds)
+
+**Return Value**
+
+Returns a Promise that resolves when the value has been stored.
+
+**Example**
+
+```typescript
+// Store a string value
+await ctx.kv.set('user-preferences', 'user-123', JSON.stringify({ theme: 'dark' }));
+
+// Store a JSON value
+await ctx.kv.set('user-preferences', 'user-123', { theme: 'dark' });
+
+// Store a binary value
+const binaryData = new Uint8Array([1, 2, 3, 4]).buffer;
+await ctx.kv.set('user-data', 'user-123', binaryData);
+
+// Store a value with TTL (expires after 1 hour)
+await ctx.kv.set('session', 'user-123', 'active', { ttl: 3600 });
+```
+
+#### delete
+
+`delete(name: string, key: string): Promise`
+
+Deletes a value from the key-value storage.
+
+**Parameters**
+
+- `name`: The name of the key-value storage
+- `key`: The key to delete
+
+**Return Value**
+
+Returns a Promise that resolves when the value has been deleted.
+
+**Example**
+
+```typescript
+// Delete a value
+await ctx.kv.delete('user-preferences', 'user-123');
+```
+
+#### search
+
+`search(name: string, keyword: string): Promise>>`
+
+Searches for keys matching a keyword pattern.
+
+**Parameters**
+
+- `name`: The name of the key-value storage
+- `keyword`: The keyword to search for in key names
+
+**Return Value**
+
+Returns a map of keys to items with metadata:
+
+```typescript
+interface KeyValueItemWithMetadata {
+ value: T; // The stored value
+ contentType: string; // MIME type of the value
+ size: number; // Size in bytes
+ created_at: string; // ISO timestamp
+ updated_at: string; // ISO timestamp
+}
+```
+
+**Example**
+
+```typescript
+// Search for all keys starting with 'user-'
+const matches = await ctx.kv.search<{ theme: string }>('preferences', 'user-');
+
+for (const [key, item] of Object.entries(matches)) {
+ ctx.logger.info('Found key', {
+ key,
+ value: item.value,
+ size: item.size,
+ updatedAt: item.updated_at,
+ });
+}
+```
+
+#### getKeys
+
+`getKeys(name: string): Promise`
+
+Returns all keys in a namespace.
+
+**Example**
+
+```typescript
+const keys = await ctx.kv.getKeys('cache');
+ctx.logger.info(`Found ${keys.length} keys in cache`);
+```
+
+#### getNamespaces
+
+`getNamespaces(): Promise`
+
+Returns all namespace names.
+
+**Example**
+
+```typescript
+const namespaces = await ctx.kv.getNamespaces();
+// ['cache', 'sessions', 'preferences']
+```
+
+#### getStats
+
+`getStats(name: string): Promise`
+
+Returns statistics for a namespace.
+
+```typescript
+interface KeyValueStats {
+ sum: number; // Total size in bytes
+ count: number; // Number of keys
+ createdAt?: number; // Unix timestamp
+ lastUsedAt?: number; // Unix timestamp
+}
+```
+
+**Example**
+
+```typescript
+const stats = await ctx.kv.getStats('cache');
+ctx.logger.info('Cache stats', { keys: stats.count, totalBytes: stats.sum });
+```
+
+#### getAllStats
+
+`getAllStats(): Promise>`
+
+Returns statistics for all namespaces.
+
+**Example**
+
+```typescript
+const allStats = await ctx.kv.getAllStats();
+for (const [namespace, stats] of Object.entries(allStats)) {
+ ctx.logger.info(`${namespace}: ${stats.count} keys, ${stats.sum} bytes`);
+}
+```
+
+#### createNamespace
+
+`createNamespace(name: string): Promise`
+
+Creates a new namespace.
+
+**Example**
+
+```typescript
+await ctx.kv.createNamespace('tenant-123');
+```
+
+#### deleteNamespace
+
+`deleteNamespace(name: string): Promise`
+
+Deletes a namespace and all its keys. **This operation cannot be undone.**
+
+**Example**
+
+```typescript
+await ctx.kv.deleteNamespace('old-cache');
+```
+
+### Vector Storage
+
+The Vector Storage API provides a way to store and search for data using vector embeddings. It is accessed through the `ctx.vector` object.
+
+#### upsert
+
+`upsert(name: string, ...documents: VectorUpsertParams[]): Promise`
+
+Inserts or updates vectors in the vector storage.
+
+**Parameters**
+
+- `name`: The name of the vector storage
+- `documents`: One or more documents to upsert. Each document must include a unique `key` and either embeddings or text
+
+**Return Value**
+
+Returns a Promise that resolves to an array of string IDs for the upserted vectors.
+
+**Example**
+
+```typescript
+// Upsert documents with text
+const ids = await ctx.vector.upsert(
+ 'product-descriptions',
+ { key: 'chair-001', document: 'Ergonomic office chair with lumbar support', metadata: { category: 'furniture' } },
+ { key: 'headphones-001', document: 'Wireless noise-cancelling headphones', metadata: { category: 'electronics' } }
+);
+
+// Upsert documents with embeddings
+const ids2 = await ctx.vector.upsert(
+ 'product-embeddings',
+ { key: 'embed-123', embeddings: [0.1, 0.2, 0.3, 0.4], metadata: { productId: '123' } },
+ { key: 'embed-456', embeddings: [0.5, 0.6, 0.7, 0.8], metadata: { productId: '456' } }
+);
+```
+
+#### search
+
+`search(name: string, params: VectorSearchParams): Promise`
+
+Searches for vectors in the vector storage.
+
+**Parameters**
+
+- `name`: The name of the vector storage
+- `params`: Search parameters object with the following properties:
+ - `query` (string, required): The text query to search for. This will be converted to embeddings and used to find semantically similar documents.
+ - `limit` (number, optional): Maximum number of search results to return. Must be a positive integer. If not specified, the server default will be used.
+ - `similarity` (number, optional): Minimum similarity threshold for results (0.0-1.0). Only vectors with similarity scores greater than or equal to this value will be returned. 1.0 means exact match, 0.0 means no similarity requirement.
+ - `metadata` (object, optional): Metadata filters to apply to the search. Only vectors whose metadata matches all specified key-value pairs will be included in results. Must be a valid JSON object.
+
+**Return Value**
+
+Returns a Promise that resolves to an array of search results, each containing an ID, key, metadata, and similarity score.
+
+**Examples**
+
+```typescript
+// Basic search with query only
+const results = await ctx.vector.search('product-descriptions', {
+ query: 'comfortable office chair'
+});
+
+// Search with limit and similarity threshold
+const results = await ctx.vector.search('product-descriptions', {
+ query: 'comfortable office chair',
+ limit: 5,
+ similarity: 0.7
+});
+
+// Search with metadata filtering
+const results = await ctx.vector.search('product-descriptions', {
+ query: 'comfortable office chair',
+ limit: 10,
+ similarity: 0.6,
+ metadata: { category: 'furniture', inStock: true }
+});
+
+// Process search results
+for (const result of results) {
+ ctx.logger.info(`Product ID: ${result.id}, Similarity: ${result.similarity}`);
+ ctx.logger.info(`Key: ${result.key}`);
+ ctx.logger.info('Metadata:', result.metadata);
+}
+```
+
+#### get
+
+`get(name: string, key: string): Promise`
+
+Retrieves a specific vector from the vector storage using its key.
+
+**Parameters**
+
+- `name`: The name of the vector storage
+- `key`: The unique key of the vector to retrieve
+
+**Return Value**
+
+Returns a Promise that resolves to a `VectorSearchResult` object if found, or `null` if the key doesn't exist.
+
+**Example**
+
+```typescript
+// Retrieve a specific vector by key
+const vector = await ctx.vector.get('product-descriptions', 'chair-001');
+
+if (vector) {
+ ctx.logger.info(`Found vector: ${vector.id}`);
+ ctx.logger.info(`Key: ${vector.key}`);
+ ctx.logger.info('Metadata:', vector.metadata);
+} else {
+ ctx.logger.info('Vector not found');
+}
+```
+
+#### delete
+
+`delete(name: string, ...keys: string[]): Promise`
+
+Deletes one or more vectors from the vector storage.
+
+**Parameters**
+
+- `name`: The name of the vector storage
+- `keys`: One or more keys of the vectors to delete
+
+**Return Value**
+
+Returns a Promise that resolves to the number of vectors that were deleted.
+
+**Examples**
+
+```typescript
+// Delete a single vector by key
+const deletedCount = await ctx.vector.delete('product-descriptions', 'chair-001');
+ctx.logger.info(`Deleted ${deletedCount} vector(s)`);
+
+// Delete multiple vectors in bulk
+const deletedCount2 = await ctx.vector.delete('product-descriptions', 'chair-001', 'headphones-001', 'desk-002');
+ctx.logger.info(`Deleted ${deletedCount2} vector(s)`);
+
+// Delete with array spread
+const keysToDelete = ['chair-001', 'headphones-001', 'desk-002'];
+const deletedCount3 = await ctx.vector.delete('product-descriptions', ...keysToDelete);
+
+// Handle cases where some vectors might not exist
+const deletedCount4 = await ctx.vector.delete('product-descriptions', 'existing-key', 'non-existent-key');
+ctx.logger.info(`Deleted ${deletedCount4} vector(s)`); // May be less than number of keys provided
+```
+
+### Database (Bun SQL)
+
+Database storage uses [Bun's native SQL APIs](https://bun.com/docs/runtime/sql). Agentuity auto-injects credentials (`DATABASE_URL`) for PostgreSQL.
+
+```typescript
+import { sql } from 'bun';
+```
+
+#### Basic Queries
+
+```typescript
+// Query with automatic parameter escaping
+const users = await sql`SELECT * FROM users WHERE active = ${true}`;
+
+// Insert data
+await sql`INSERT INTO users (name, email) VALUES (${"Alice"}, ${"alice@example.com"})`;
+
+// Update data
+await sql`UPDATE users SET active = ${false} WHERE id = ${userId}`;
+
+// Delete data
+await sql`DELETE FROM users WHERE id = ${userId}`;
+```
+
+#### Transactions
+
+```typescript
+await sql.begin(async (tx) => {
+ await tx`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`;
+ await tx`UPDATE accounts SET balance = balance + ${amount} WHERE id = ${toId}`;
+ await tx`INSERT INTO transfers (from_id, to_id, amount) VALUES (${fromId}, ${toId}, ${amount})`;
+});
+// Automatically rolls back on error
+```
+
+#### Dynamic Queries
+
+```typescript
+const users = await sql`
+ SELECT * FROM users
+ WHERE 1=1
+ ${minAge ? sql`AND age >= ${minAge}` : sql``}
+ ${active !== undefined ? sql`AND active = ${active}` : sql``}
+`;
+```
+
+#### Bulk Insert
+
+```typescript
+const newUsers = [
+ { name: "Alice", email: "alice@example.com" },
+ { name: "Bob", email: "bob@example.com" },
+];
+await sql`INSERT INTO users ${sql(newUsers)}`;
+```
+
+#### Custom Connections
+
+```typescript
+import { SQL } from "bun";
+
+// PostgreSQL
+const postgres = new SQL({
+ url: process.env.POSTGRES_URL,
+ max: 20,
+ idleTimeout: 30,
+});
+
+// MySQL
+const mysql = new SQL("mysql://user:pass@localhost:3306/mydb");
+
+// SQLite
+const sqlite = new SQL("sqlite://data/app.db");
+```
+
+For Agentuity-specific patterns, see [Database Storage](/Build/Storage/database). For the complete Bun SQL API, see [Bun SQL documentation](https://bun.com/docs/runtime/sql).
+
+### Object Storage (Bun S3)
+
+Object storage uses [Bun's native S3 APIs](https://bun.com/docs/runtime/s3). Agentuity auto-injects the required credentials (`S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_BUCKET`, `S3_ENDPOINT`).
+
+```typescript
+import { s3 } from 'bun';
+```
+
+#### Reading Files
+
+```typescript
+const file = s3.file('uploads/profile-123.jpg');
+
+if (await file.exists()) {
+ const text = await file.text(); // For text files
+ const json = await file.json(); // For JSON files
+ const bytes = await file.bytes(); // For binary data
+ const blob = await file.blob(); // As Blob
+}
+```
+
+#### Writing Files
+
+```typescript
+const file = s3.file('documents/readme.txt');
+
+// Write text
+await file.write('Hello, world!', { type: 'text/plain' });
+
+// Write JSON
+await file.write(JSON.stringify({ name: 'John' }), { type: 'application/json' });
+
+// Write binary data
+await file.write(pdfBuffer, { type: 'application/pdf' });
+```
+
+#### Deleting Files
+
+```typescript
+const file = s3.file('uploads/old-file.pdf');
+await file.delete();
+```
+
+#### Presigned URLs
+
+Generate time-limited URLs for file access (synchronous, no network required):
+
+```typescript
+// Download URL (1 hour)
+const downloadUrl = s3.presign('uploads/document.pdf', {
+ expiresIn: 3600,
+ method: 'GET',
+});
+
+// Upload URL
+const uploadUrl = s3.presign('uploads/new-file.pdf', {
+ expiresIn: 3600,
+ method: 'PUT',
+});
+```
+
+#### File Metadata
+
+```typescript
+const file = s3.file('uploads/document.pdf');
+const stat = await file.stat();
+// { etag, lastModified, size, type }
+```
+
+#### Listing Objects
+
+```typescript
+import { S3Client } from 'bun';
+
+const objects = await S3Client.list({
+ prefix: 'uploads/',
+ maxKeys: 100,
+});
+```
+
+#### Streaming Large Files
+
+```typescript
+const file = s3.file('large-file.zip');
+const writer = file.writer({ partSize: 5 * 1024 * 1024 }); // 5MB parts
+
+writer.write(chunk1);
+writer.write(chunk2);
+await writer.end();
+```
+
+For Agentuity-specific patterns, see [Object Storage](/Build/Storage/object). For the complete Bun S3 API, see [Bun S3 documentation](https://bun.com/docs/runtime/s3).
+
+### Stream Storage
+
+The Stream Storage API provides first-class support for creating and managing server-side streams. Streams are accessible via the `ctx.stream` object.
+
+#### create
+
+`create(name: string, props?: StreamCreateProps): Promise`
+
+Creates a new, named, writable stream.
+
+**Parameters**
+
+- `name`: A string identifier for the stream
+- `props` (optional): Configuration object
+ - `metadata`: Key-value pairs for identifying and searching streams
+ - `contentType`: Content type of the stream (defaults to `application/octet-stream`)
+ - `compress`: Enable automatic gzip compression (defaults to `false`)
+
+**Return Value**
+
+Returns a Promise that resolves to a `Stream` object:
+
+```typescript
+interface Stream {
+ id: string; // Unique stream identifier
+ url: string; // Public URL to access the stream
+ bytesWritten: number; // Total bytes written (readonly)
+ compressed: boolean; // Whether compression is enabled (readonly)
+
+ write(chunk: string | Uint8Array | ArrayBuffer | object): Promise;
+ close(): Promise;
+ getReader(): ReadableStream; // Get readable stream from URL
+}
+```
+
+**Stream Characteristics:**
+- **Read-Many**: Multiple consumers can read simultaneously
+- **Re-readable**: Can be read multiple times from the beginning
+- **Resumable**: Supports HTTP Range requests
+- **Persistent**: URLs remain accessible until expiration
+
+**Example**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('UserExporter', {
+ schema: {
+ input: z.object({ userId: z.string() }),
+ output: z.object({ streamId: z.string(), streamUrl: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Create a stream with metadata
+ const stream = await ctx.stream.create('user-export', {
+ contentType: 'text/csv',
+ metadata: {
+ userId: input.userId,
+ timestamp: Date.now(),
+ },
+ });
+
+ // Write data in the background
+ ctx.waitUntil(async () => {
+ try {
+ await stream.write('Name,Email\n');
+ await stream.write('John,john@example.com\n');
+ } finally {
+ await stream.close();
+ }
+ });
+
+ return {
+ streamId: stream.id,
+ streamUrl: stream.url,
+ };
+ },
+});
+```
+
+#### get
+
+`get(id: string): Promise`
+
+Retrieves metadata for a stream by ID.
+
+**Parameters**
+
+- `id`: The stream ID to retrieve
+
+**Return Value**
+
+Returns a `StreamInfo` object:
+
+```typescript
+interface StreamInfo {
+ id: string; // Unique stream identifier
+ name: string; // Stream name
+ metadata: Record; // User-defined metadata
+ url: string; // Public URL to access the stream
+ sizeBytes: number; // Size of stream content in bytes
+}
+```
+
+**Example**
+
+```typescript
+const info = await ctx.stream.get('stream_0199a52b06e3767dbe2f10afabb5e5e4');
+ctx.logger.info('Stream details', {
+ name: info.name,
+ sizeBytes: info.sizeBytes,
+ url: info.url,
+});
+```
+
+#### download
+
+`download(id: string): Promise>`
+
+Downloads stream content as a readable stream.
+
+**Parameters**
+
+- `id`: The stream ID to download
+
+**Return Value**
+
+Returns a `ReadableStream` of the stream content.
+
+**Example**
+
+```typescript
+const readable = await ctx.stream.download('stream_0199a52b06e3767dbe2f10afabb5e5e4');
+
+// Process the stream
+const reader = readable.getReader();
+const chunks: Uint8Array[] = [];
+
+while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ chunks.push(value);
+}
+
+const content = Buffer.concat(chunks).toString('utf-8');
+```
+
+#### list
+
+`list(params?: ListStreamsParams): Promise`
+
+Lists and searches streams with filtering and pagination.
+
+**Parameters**
+
+- `params` (optional):
+ - `name`: Filter by stream name
+ - `metadata`: Filter by metadata key-value pairs
+ - `limit`: Maximum streams to return (1-1000, default 100)
+ - `offset`: Number of streams to skip
+
+**Return Value**
+
+Returns a `ListStreamsResponse`:
+
+```typescript
+interface ListStreamsResponse {
+ success: boolean;
+ message?: string; // Error message if not successful
+ streams: StreamInfo[]; // Array of stream metadata
+ total: number; // Total count for pagination
+}
+```
+
+**Example**
+
+```typescript
+// List all streams
+const result = await ctx.stream.list();
+ctx.logger.info(`Found ${result.total} streams`);
+
+// Filter by metadata
+const userStreams = await ctx.stream.list({
+ metadata: { userId: 'user-123' }
+});
+```
+
+#### delete
+
+`delete(id: string): Promise`
+
+Deletes a stream by its ID.
+
+**Parameters**
+
+- `id`: The stream ID to delete
+
+**Example**
+
+```typescript
+await ctx.stream.delete(streamId);
+ctx.logger.info('Stream deleted successfully');
+```
+
+---
+
+## Logging
+
+The SDK provides logging functionality through the `ctx.logger` object.
+
+### Logger Interface
+
+The `Logger` interface defines the following methods:
+
+```typescript
+interface Logger {
+ trace(message: unknown, ...args: unknown[]): void;
+ debug(message: unknown, ...args: unknown[]): void;
+ info(message: unknown, ...args: unknown[]): void;
+ warn(message: unknown, ...args: unknown[]): void;
+ error(message: unknown, ...args: unknown[]): void;
+ fatal(message: unknown, ...args: unknown[]): never;
+ child(opts: Record): Logger;
+}
+```
+
+### Logging Methods
+
+#### trace
+
+`trace(message: unknown, ...args: unknown[]): void`
+
+Logs a trace message (most verbose logging level).
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Example**
+
+```typescript
+ctx.logger.trace('Detailed diagnostic info', { data: complexObject });
+```
+
+#### debug
+
+`debug(message: unknown, ...args: unknown[]): void`
+
+Logs a debug message.
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Example**
+
+```typescript
+ctx.logger.debug('Processing request', { requestId: '123' });
+```
+
+#### info
+
+`info(message: unknown, ...args: unknown[]): void`
+
+Logs an informational message.
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Example**
+
+```typescript
+ctx.logger.info('Request processed successfully', { requestId: '123' });
+```
+
+#### warn
+
+`warn(message: unknown, ...args: unknown[]): void`
+
+Logs a warning message.
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Example**
+
+```typescript
+ctx.logger.warn('Resource not found', { resourceId: '456' });
+```
+
+#### error
+
+`error(message: unknown, ...args: unknown[]): void`
+
+Logs an error message.
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Example**
+
+```typescript
+ctx.logger.error('Failed to process request', error);
+```
+
+#### fatal
+
+`fatal(message: unknown, ...args: unknown[]): never`
+
+Logs a fatal error message and exits the process.
+
+**Parameters**
+
+- `message`: The message to log (can be any type)
+- `args`: Additional arguments to include in the log
+
+**Return Value**
+
+This method never returns (type `never`) as it terminates the process.
+
+**Example**
+
+```typescript
+// Log fatal error and exit
+ctx.logger.fatal('Critical system failure', { error, context });
+// Code after this line will never execute
+```
+
+**Note**: Use `fatal()` only for unrecoverable errors that require process termination. For recoverable errors, use `error()` instead.
+
+### Creating Child Loggers
+
+#### child
+
+`child(opts: Record): Logger`
+
+Creates a child logger with additional context.
+
+**Parameters**
+
+- `opts`: Additional context to include in all logs from the child logger (key-value pairs of any type)
+
+**Return Value**
+
+Returns a new `Logger` instance with the additional context.
+
+**Example**
+
+```typescript
+const requestLogger = ctx.logger.child({ requestId: '123', userId: '456' });
+requestLogger.info('Processing request');
+```
+
+---
+
+## Telemetry
+
+The SDK integrates with OpenTelemetry for tracing and metrics.
+
+### Tracing
+
+The SDK provides access to OpenTelemetry tracing through the `ctx.tracer` object.
+
+**Example**
+
+```typescript
+// Create a span
+ctx.tracer.startActiveSpan('process-data', async (span) => {
+ try {
+ // Add attributes to the span
+ span.setAttribute('userId', '123');
+
+ // Perform some work
+ const result = await processData();
+
+ // Add events to the span
+ span.addEvent('data-processed', { itemCount: result.length });
+
+ return result;
+ } catch (error) {
+ // Record the error
+ span.recordException(error);
+ span.setStatus({ code: SpanStatusCode.ERROR });
+ throw error;
+ } finally {
+ span.end();
+ }
+});
+```
+
+---
+
+## Agent Communication
+
+Agents can communicate with each other through a type-safe registry pattern, enabling complex multi-agent workflows with full TypeScript support.
+
+### Agent Registry
+
+Import other agents directly and call them with full type safety.
+
+**Key Features:**
+- **Type-safe calls**: TypeScript infers input and output types from agent schemas
+- **Automatic validation**: Input and output are validated against schemas
+- **IDE autocomplete**: Full IntelliSense support for agent names and parameters
+- **Error handling**: Type-safe error responses
+
+**Basic Pattern:**
+
+```typescript
+import otherAgent from '@agent/other';
+
+// Call another agent
+const result = await otherAgent.run(input);
+```
+
+The `@agent/` path alias provides access to all agents in your project with compile-time type checking.
+
+### Calling Other Agents
+
+Import agents and call them directly.
+
+**Example: Simple Agent Call**
+
+```typescript
+// src/agent/processor/agent.ts
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+import enrichmentAgent from '@agent/enrichment';
+
+const processor = createAgent('Processor', {
+ schema: {
+ input: z.object({ userInput: z.string() }),
+ output: z.object({
+ processed: z.boolean(),
+ analysis: z.object({
+ sentiment: z.string(),
+ keywords: z.array(z.string()),
+ }),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Call the enrichment agent
+ const enriched = await enrichmentAgent.run({
+ text: input.userInput,
+ });
+
+ // TypeScript knows enriched has the shape from the agent's schema
+
+ return {
+ processed: true,
+ analysis: {
+ sentiment: enriched.sentiment,
+ keywords: enriched.keywords,
+ },
+ };
+ },
+});
+
+export default processor;
+```
+
+**Example: Calling Multiple Agents**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+import webSearchAgent from '@agent/web-search';
+import databaseAgent from '@agent/database';
+import cacheAgent from '@agent/cache';
+
+const coordinator = createAgent('Coordinator', {
+ schema: {
+ input: z.object({ query: z.string() }),
+ output: z.object({
+ results: z.array(z.any()),
+ metadata: z.object({
+ sources: z.number(),
+ processingTime: z.number(),
+ }),
+ }),
+ },
+ handler: async (ctx, input) => {
+ const startTime = Date.now();
+
+ // Call multiple agents in parallel
+ const [webResults, dbResults, cacheResults] = await Promise.all([
+ webSearchAgent.run({ query: input.query }),
+ databaseAgent.run({ query: input.query }),
+ cacheAgent.run({ key: input.query }),
+ ]);
+
+ // Combine results
+ const allResults = [
+ ...webResults.items,
+ ...dbResults.records,
+ ...(cacheResults.found ? [cacheResults.data] : []),
+ ];
+
+ return {
+ results: allResults,
+ metadata: {
+ sources: 3,
+ processingTime: Date.now() - startTime,
+ },
+ };
+ },
+});
+
+export default coordinator;
+```
+
+**Error Handling:**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+import externalService from '@agent/external-service';
+
+const robustAgent = createAgent('Robust', {
+ schema: {
+ input: z.object({ userId: z.string() }),
+ output: z.object({ success: z.boolean(), data: z.any() }),
+ },
+ handler: async (ctx, input) => {
+ try {
+ // Try calling external agent
+ const result = await externalService.run({
+ userId: input.userId,
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ ctx.logger.error('External service failed', { error });
+
+ // Fallback to cached data
+ const cached = await ctx.kv.get('user-cache', input.userId);
+
+ if (cached.exists) {
+ return { success: true, data: cached.data };
+ }
+
+ return { success: false, data: null };
+ }
+ },
+});
+
+export default robustAgent;
+```
+
+---
+
+## Router & Routes
+
+The SDK provides a Hono-based routing system for creating HTTP endpoints. Routes are defined in `src/api/index.ts` and provide full control over HTTP request handling.
+
+### Creating Routes
+
+Routes are created using the `createRouter()` function from `@agentuity/server`.
+
+**Basic Setup:**
+
+```typescript
+// src/api/index.ts
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+// Define routes
+router.get('/', (c) => {
+ return c.json({ message: 'Hello from route' });
+});
+
+export default router;
+```
+
+### Router Context
+
+Router handlers receive a context parameter (typically `c`) that provides access to the request, response helpers, and Agentuity services. This Hono Context is distinct from the `AgentContext` type used in agent handlers.
+
+#### Understanding Context Types
+
+Agentuity uses two distinct context types based on where you're writing code:
+
+- **AgentContext**: Used in `agent.ts` files for business logic (no HTTP access)
+- **Router Context (Hono)**: Used in `src/api/index.ts` for HTTP handling (has HTTP + agent services)
+
+Both commonly use `c` as the variable name in SDK examples. The distinction is **type-based**, not name-based.
+
+For a detailed explanation with examples, see the [Context Types Guide](/Guides/context-types).
+
+**Router Context Interface:**
+
+```typescript
+interface RouterContext {
+ // Request
+ req: Request; // Hono request object with .param(), .query(), .header(), .json()
+
+ // Agentuity Services (via c.var)
+ var: {
+ kv: KeyValueStorage; // Key-value storage
+ vector: VectorStorage; // Vector storage
+ stream: StreamStorage; // Stream storage
+ logger: Logger; // Structured logging
+ tracer: Tracer; // OpenTelemetry tracing
+ };
+
+ // Response Helpers
+ json(data: any, status?: number): Response;
+ text(text: string, status?: number): Response;
+ html(html: string, status?: number): Response;
+ redirect(url: string, status?: number): Response;
+ // ... other Hono response methods
+}
+```
+
+**Key Differences Between Context Types:**
+
+| Feature | Router Context (Hono) | Agent Context |
+|---------|----------------------|---------------|
+| **Type** | Hono Context | `AgentContext` |
+| **Used in** | `src/api/index.ts` | `agent.ts` files |
+| **Request access** | `c.req` (Hono Request) | Direct `input` parameter (validated) |
+| **Response** | Builder methods (`.json()`, `.text()`) | Direct returns |
+| **Services** | `c.var.kv`, `c.var.logger`, etc. | `ctx.kv`, `ctx.logger`, etc. |
+| **Agent calling** | Import and call: `agent.run()` | Import and call: `agent.run()` |
+| **State management** | Via Hono middleware | Built-in (`.state`, `.session`, `.thread`) |
+
+**Example Usage:**
+
+```typescript
+import processor from '@agent/processor';
+
+router.post('/process', processor.validator(), async (c) => {
+ // Access request
+ const body = c.req.valid('json');
+ const authHeader = c.req.header('Authorization');
+
+ // Use Agentuity services
+ c.var.logger.info('Processing request', { body });
+
+ // Call an agent
+ const result = await processor.run({ data: body.data });
+
+ // Store result
+ await c.var.kv.set('results', body.id, result);
+
+ // Return response
+ return c.json({ success: true, result });
+});
+```
+
+### Accessing Services
+
+Agentuity services (storage, logging, tracing) are available in multiple contexts. The API is identical; only the access pattern differs.
+
+#### Quick Reference
+
+| Service | In Agents | In Routes | In Standalone |
+|---------|-----------|-----------|---------------|
+| Key-Value | `ctx.kv` | `c.var.kv` | `ctx.kv` |
+| Vector | `ctx.vector` | `c.var.vector` | `ctx.vector` |
+| Streams | `ctx.stream` | `c.var.stream` | `ctx.stream` |
+| Logger | `ctx.logger` | `c.var.logger` | `ctx.logger` |
+| Tracer | `ctx.tracer` | `c.var.tracer` | `ctx.tracer` |
+| State | `ctx.state` | `c.var.state` | `ctx.state` |
+| Thread | `ctx.thread` | `c.var.thread` | `ctx.thread` |
+| Session | `ctx.session` | `c.var.session` | `ctx.session` |
+
+#### From Agents
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+
+export default createAgent('cache-manager', {
+ handler: async (ctx, input) => {
+ await ctx.kv.set('cache', 'key', { data: 'value' });
+ ctx.logger.info('Data cached');
+ return { success: true };
+ },
+});
+```
+
+#### From Routes
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.post('/cache', async (c) => {
+ await c.var.kv.set('cache', 'key', { data: 'value' });
+ c.var.logger.info('Data cached');
+ return c.json({ success: true });
+});
+
+export default router;
+```
+
+#### From Standalone Code
+
+For Discord bots, CLI tools, or queue workers running within the Agentuity runtime:
+
+```typescript
+import { createApp, createAgentContext } from '@agentuity/runtime';
+
+await createApp();
+
+const ctx = createAgentContext();
+await ctx.invoke(async () => {
+ await ctx.kv.set('cache', 'key', { data: 'value' });
+ ctx.logger.info('Data cached from standalone context');
+});
+```
+
+See [Running Agents Without HTTP](/Build/Agents/standalone-execution) for Discord bots, CLI tools, and queue worker patterns.
+
+#### From External Backends (Next.js, Express)
+
+External backends cannot access Agentuity services directly. Create authenticated routes that expose storage operations, then call them via HTTP:
+
+```typescript title="Agentuity route: src/api/sessions/route.ts"
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/:id', async (c) => {
+ const result = await c.var.kv.get('sessions', c.req.param('id'));
+ return result.exists ? c.json(result.data) : c.json({ error: 'Not found' }, 404);
+});
+
+export default router;
+```
+
+```typescript title="Next.js: lib/agentuity.ts"
+const AGENTUITY_URL = process.env.AGENTUITY_URL!;
+const API_KEY = process.env.STORAGE_API_KEY!;
+
+export async function getSession(id: string) {
+ const res = await fetch(`${AGENTUITY_URL}/api/sessions/${id}`, {
+ headers: { 'x-api-key': API_KEY },
+ });
+ if (!res.ok) return null;
+ return res.json();
+}
+```
+
+See [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities) for the complete pattern with authentication.
+
+#### From Frontend
+
+Frontend code accesses services through routes using `useAPI` or `fetch`:
+
+```tsx
+import { useAPI } from '@agentuity/react';
+
+function SessionView({ id }: { id: string }) {
+ const { data, isLoading } = useAPI(`GET /api/sessions/${id}`);
+
+ if (isLoading) return Loading...
;
+ return {data?.message}
;
+}
+```
+
+See [React Hooks](/Build/Frontend/react-hooks) for `useAPI`, `useWebsocket`, and `useEventStream`.
+
+### HTTP Methods
+
+The router supports all standard HTTP methods.
+
+**GET Requests:**
+
+```typescript
+router.get('/users', (c) => {
+ return c.json({ users: [] });
+});
+
+router.get('/users/:id', (c) => {
+ const id = c.req.param('id');
+ return c.json({ userId: id });
+});
+```
+
+**POST Requests:**
+
+```typescript
+router.post('/users', async (c) => {
+ const body = await c.req.json();
+ return c.json({ created: true, user: body });
+});
+```
+
+**PUT, PATCH, DELETE:**
+
+```typescript
+router.put('/users/:id', async (c) => {
+ const id = c.req.param('id');
+ const body = await c.req.json();
+ return c.json({ updated: true, id, data: body });
+});
+
+router.patch('/users/:id', async (c) => {
+ const id = c.req.param('id');
+ const updates = await c.req.json();
+ return c.json({ patched: true, id, updates });
+});
+
+router.delete('/users/:id', (c) => {
+ const id = c.req.param('id');
+ return c.json({ deleted: true, id });
+});
+```
+
+**Calling Agents from Routes:**
+
+Import agents and call them directly:
+
+```typescript
+import processorAgent from '@agent/processor';
+
+router.post('/process', processorAgent.validator(), async (c) => {
+ const input = c.req.valid('json');
+
+ // Call the agent
+ const result = await processorAgent.run({
+ data: input.data,
+ });
+
+ return c.json(result);
+});
+```
+
+### Specialized Routes
+
+The router provides specialized route handlers for non-HTTP triggers like WebSockets, scheduled jobs, and real-time communication.
+
+#### WebSocket Routes
+
+Create a WebSocket endpoint for real-time bidirectional communication using the `websocket` middleware.
+
+**Import:**
+
+```typescript
+import { websocket } from '@agentuity/runtime';
+```
+
+**Handler Signature:**
+
+```typescript
+type WebSocketHandler = (c: Context, ws: WebSocketConnection) => void | Promise;
+
+interface WebSocketConnection {
+ onOpen(handler: (event: any) => void | Promise): void;
+ onMessage(handler: (event: any) => void | Promise): void;
+ onClose(handler: (event: any) => void | Promise): void;
+ send(data: string | ArrayBuffer | Uint8Array): void;
+}
+```
+
+**Example:**
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.get('/chat', websocket((c, ws) => {
+ ws.onOpen((event) => {
+ c.var.logger.info('WebSocket connected');
+ ws.send(JSON.stringify({ type: 'connected' }));
+ });
+
+ ws.onMessage(async (event) => {
+ const message = JSON.parse(event.data);
+
+ // Process message with agent
+ const response = await chatAgent.run({
+ message: message.text,
+ });
+
+ ws.send(JSON.stringify({ type: 'response', data: response }));
+ });
+
+ ws.onClose((event) => {
+ c.var.logger.info('WebSocket disconnected');
+ });
+}));
+
+export default router;
+```
+
+#### Server-Sent Events (SSE)
+
+Create a Server-Sent Events endpoint for server-to-client streaming using the `sse` middleware.
+
+**Import:**
+
+```typescript
+import { sse } from '@agentuity/runtime';
+```
+
+**Handler Signature:**
+
+```typescript
+type SSEHandler = (c: Context, stream: SSEStream) => void | Promise;
+
+interface SSEStream {
+ write(data: string | number | boolean | object): Promise;
+ writeSSE(message: { data?: string; event?: string; id?: string }): Promise;
+ onAbort(handler: () => void): void;
+ close?(): void;
+}
+```
+
+**Example:**
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+import longRunningAgent from '@agent/long-running';
+
+const router = createRouter();
+
+router.get('/updates', sse(async (c, stream) => {
+ // Send initial connection message
+ await stream.write({ type: 'connected' });
+
+ // Stream agent progress updates
+ const updates = await longRunningAgent.run({ task: 'process' });
+
+ for (const update of updates) {
+ await stream.write({
+ type: 'progress',
+ data: update,
+ });
+ }
+
+ // Clean up on client disconnect
+ stream.onAbort(() => {
+ c.var.logger.info('Client disconnected');
+ });
+}));
+
+export default router;
+```
+
+#### Stream Routes
+
+Create an HTTP streaming endpoint for piping data streams using the `stream` middleware.
+
+**Import:**
+
+```typescript
+import { stream } from '@agentuity/runtime';
+```
+
+**Handler Signature:**
+
+```typescript
+type StreamHandler = (c: Context) => ReadableStream | Promise>;
+```
+
+**Example:**
+
+```typescript
+import { createRouter, stream } from '@agentuity/runtime';
+import dataGenerator from '@agent/data-generator';
+
+const router = createRouter();
+
+router.post('/data', stream(async (c) => {
+ // Create a readable stream
+ const readableStream = new ReadableStream({
+ async start(controller) {
+ // Stream data chunks
+ const data = await dataGenerator.run({ query: 'all' });
+
+ for (const chunk of data) {
+ controller.enqueue(new TextEncoder().encode(JSON.stringify(chunk) + '\n'));
+ }
+
+ controller.close();
+ },
+ });
+
+ return readableStream;
+}));
+
+export default router;
+```
+
+#### Cron Routes
+
+Schedule recurring jobs using cron syntax with the `cron` middleware.
+
+**Import:**
+
+```typescript
+import { cron } from '@agentuity/runtime';
+```
+
+**Handler Signature:**
+
+```typescript
+type CronHandler = (c: Context) => any | Promise;
+```
+
+**Cron Schedule Format:**
+
+```
+┌───────────── minute (0 - 59)
+│ ┌───────────── hour (0 - 23)
+│ │ ┌───────────── day of month (1 - 31)
+│ │ │ ┌───────────── month (1 - 12)
+│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday = 0)
+│ │ │ │ │
+* * * * *
+```
+
+**Example:**
+
+```typescript
+import { createRouter, cron } from '@agentuity/runtime';
+import reportGenerator from '@agent/report-generator';
+import healthCheck from '@agent/health-check';
+
+const router = createRouter();
+
+// Run daily at 9am
+router.post('/daily-report', cron('0 9 * * *', async (c) => {
+ c.var.logger.info('Running daily report');
+
+ const report = await reportGenerator.run({
+ type: 'daily',
+ date: new Date().toISOString(),
+ });
+
+ // Store report in KV
+ await c.var.kv.set('reports', `daily-${Date.now()}`, report);
+
+ return c.json({ success: true });
+}));
+
+// Run every 5 minutes
+router.post('/health-check', cron('*/5 * * * *', async (c) => {
+ await healthCheck.run({});
+ return c.json({ checked: true });
+}));
+
+export default router;
+```
+
+### Route Parameters
+
+Access route parameters and query strings through the request object.
+
+**Path Parameters:**
+
+```typescript
+router.get('/posts/:postId/comments/:commentId', (c) => {
+ const postId = c.req.param('postId');
+ const commentId = c.req.param('commentId');
+
+ return c.json({ postId, commentId });
+});
+```
+
+**Query Parameters:**
+
+```typescript
+router.get('/search', (c) => {
+ const query = c.req.query('q');
+ const limit = c.req.query('limit') || '10';
+ const page = c.req.query('page') || '1';
+
+ return c.json({
+ query,
+ limit: parseInt(limit),
+ page: parseInt(page)
+ });
+});
+```
+
+**Request Headers:**
+
+```typescript
+router.get('/protected', (c) => {
+ const authHeader = c.req.header('Authorization');
+
+ if (!authHeader) {
+ return c.json({ error: 'Unauthorized' }, 401);
+ }
+
+ return c.json({ authorized: true });
+});
+```
+
+---
+
+## Session & Thread Management
+
+The SDK provides session and thread management for stateful agent interactions.
+
+### Sessions
+
+Sessions represent a user's interaction with your agents, persisting across multiple requests.
+
+**Session Interface:**
+
+```typescript
+interface Session {
+ id: string; // Unique session identifier
+ thread: Thread; // Reference to the current thread
+ state: Map; // Session-scoped persistent state
+
+ // Event listeners for session lifecycle (optional)
+ addEventListener(
+ eventName: 'completed',
+ callback: (eventName: 'completed', session: Session) => Promise | void
+ ): void;
+ removeEventListener(
+ eventName: 'completed',
+ callback: (eventName: 'completed', session: Session) => Promise | void
+ ): void;
+}
+```
+
+**Using Session State:**
+
+```typescript
+const agent = createAgent('MessageTracker', {
+ schema: {
+ input: z.object({ message: z.string() }),
+ output: z.object({
+ response: z.string(),
+ messageCount: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Get current message count from session
+ const currentCount = (ctx.session.state.get('messageCount') as number) || 0;
+ const newCount = currentCount + 1;
+
+ // Update session state
+ ctx.session.state.set('messageCount', newCount);
+ ctx.session.state.set('lastMessage', input.message);
+ ctx.session.state.set('lastTimestamp', Date.now());
+
+ return {
+ response: `Message received`,
+ messageCount: newCount,
+ };
+ },
+});
+```
+
+### Threads
+
+Threads represent a specific conversation or workflow within a session.
+
+**Thread Interface:**
+
+```typescript
+interface Thread {
+ id: string; // Unique thread identifier
+ state: Map; // Thread-scoped state
+
+ // Event listeners for thread lifecycle (optional)
+ addEventListener(
+ eventName: 'destroyed',
+ callback: (eventName: 'destroyed', thread: Thread) => Promise | void
+ ): void;
+ removeEventListener(
+ eventName: 'destroyed',
+ callback: (eventName: 'destroyed', thread: Thread) => Promise | void
+ ): void;
+ destroy(): Promise; // Destroy the thread
+}
+```
+
+**Using Thread State:**
+
+```typescript
+const conversationAgent = createAgent('ConversationAgent', {
+ schema: {
+ input: z.object({
+ message: z.string(),
+ userId: z.string(),
+ }),
+ output: z.object({
+ reply: z.string(),
+ context: z.array(z.string()),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Get conversation history from thread (async)
+ const history = (await ctx.thread.state.get('history')) || [];
+
+ // Add current message to history
+ history.push(input.message);
+ await ctx.thread.state.set('history', history);
+
+ // Store user info
+ await ctx.thread.state.set('userId', input.userId);
+
+ return {
+ reply: `Processed message ${history.length}`,
+ context: history,
+ };
+ },
+});
+```
+
+### State Management
+
+The context provides three levels of state management:
+
+**1. Request State (`ctx.state`):**
+- Scoped to the current request only
+- Cleared after handler completes
+- Use for temporary data within a single execution
+
+```typescript
+handler: async (ctx, input) => {
+ ctx.state.set('startTime', Date.now());
+
+ // Do work...
+
+ const duration = Date.now() - (ctx.state.get('startTime') as number);
+ ctx.logger.info(`Request took ${duration}ms`);
+}
+```
+
+**2. Thread State (`ctx.thread.state`):**
+- Persists across requests within the same thread
+- Useful for conversation context and workflow state
+- Destroyed when thread is destroyed
+- **All methods are async** for lazy-loading performance
+
+```typescript
+handler: async (ctx, input) => {
+ const step = (await ctx.thread.state.get('currentStep')) || 1;
+ await ctx.thread.state.set('currentStep', step + 1);
+}
+```
+
+**3. Session State (`ctx.session.state`):**
+- Persists across all threads in a session
+- Useful for user preferences and long-term data
+- Survives thread destruction
+
+```typescript
+handler: async (ctx, input) => {
+ const totalRequests = (ctx.session.state.get('totalRequests') as number) || 0;
+ ctx.session.state.set('totalRequests', totalRequests + 1);
+}
+```
+
+**Complete Example:**
+
+```typescript
+const statefulAgent = createAgent('StatefulAgent', {
+ schema: {
+ input: z.object({ action: z.string(), data: z.any() }),
+ output: z.object({
+ success: z.boolean(),
+ stats: z.object({
+ requestDuration: z.number(),
+ threadStep: z.number(),
+ sessionTotal: z.number(),
+ }),
+ }),
+ },
+ handler: async (ctx, input) => {
+ // Request-scoped state (sync)
+ ctx.state.set('startTime', Date.now());
+
+ // Thread-scoped state (async, conversation flow)
+ const threadStep = (await ctx.thread.state.get('step')) || 0;
+ await ctx.thread.state.set('step', threadStep + 1);
+ await ctx.thread.state.set('lastAction', input.action);
+
+ // Session-scoped state (user-level)
+ const sessionTotal = (ctx.session.state.get('total') as number) || 0;
+ ctx.session.state.set('total', sessionTotal + 1);
+ ctx.session.state.set('lastSeen', Date.now());
+
+ // Process action
+ await processAction(input.action, input.data);
+
+ return {
+ success: true,
+ stats: {
+ requestDuration: Date.now() - (ctx.state.get('startTime') as number),
+ threadStep: threadStep + 1,
+ sessionTotal: sessionTotal + 1,
+ },
+ };
+ },
+});
+```
+
+---
+
+## Evaluations
+
+The SDK includes a built-in evaluation framework for assessing agent quality and performance. Evals run automatically after agent execution to validate outputs and measure quality metrics.
+
+### Creating Evals
+
+Evals are defined in an `eval.ts` file in the same folder as your agent and use named exports:
+
+```
+src/agent/my-agent/
+├── agent.ts # Agent definition
+└── eval.ts # Evals with named exports
+```
+
+**Eval Configuration:**
+
+```typescript
+agent.createEval('eval-name', {
+ description?: string; // What this eval checks
+ handler: EvalFunction; // Eval logic
+});
+```
+
+**Basic Example:**
+
+```typescript title="src/agent/qa-agent/agent.ts"
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('ConfidenceAgent', {
+ schema: {
+ input: z.object({ query: z.string() }),
+ output: z.object({
+ answer: z.string(),
+ confidence: z.number(),
+ }),
+ },
+ handler: async (ctx, input) => {
+ return {
+ answer: 'Response to ' + input.query,
+ confidence: 0.95,
+ };
+ },
+});
+
+export default agent;
+```
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+// Named export required (not export default)
+export const confidenceEval = agent.createEval('confidence-check', {
+ description: 'Ensures confidence is above minimum threshold',
+ handler: async (ctx, input, output) => {
+ const passed = output.confidence >= 0.8;
+
+ return {
+ passed,
+ reason: passed ? 'Confidence acceptable' : 'Confidence too low',
+ metadata: { confidence: output.confidence, threshold: 0.8 },
+ };
+ },
+});
+```
+
+The runtime auto-discovers `eval.ts` files next to your agents. No special imports needed in your routes.
+
+### Eval Results
+
+Evals can return different result types depending on the evaluation needs.
+
+**Result Types:**
+
+```typescript
+type EvalRunResult =
+ | { passed: boolean; reason?: string; score?: number; metadata?: object } // Success
+ | { success: false; passed: false; error: string; reason?: string; metadata?: object }; // Error
+```
+
+**Binary Pass/Fail Eval:**
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+export const lengthEval = agent.createEval('output-length-check', {
+ description: 'Ensures output meets minimum length',
+ handler: async (ctx, input, output) => {
+ const passed = output.answer.length >= 10;
+
+ return {
+ passed,
+ reason: passed ? 'Output meets minimum length' : 'Output too short',
+ metadata: { actualLength: output.answer.length, minimumLength: 10 },
+ };
+ },
+});
+```
+
+**Score-Based Eval:**
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+export const qualityEval = agent.createEval('quality-score', {
+ description: 'Calculates overall quality score',
+ handler: async (ctx, input, output) => {
+ let score = 0;
+ if (output.answer.length > 20) score += 0.3;
+ if (output.confidence > 0.8) score += 0.4;
+ if (output.answer.includes(input.query)) score += 0.3;
+
+ return {
+ passed: score >= 0.7,
+ score,
+ reason: score >= 0.7 ? 'High quality response' : 'Quality below threshold',
+ metadata: {
+ factors: {
+ length: output.answer.length,
+ confidence: output.confidence,
+ relevance: output.answer.includes(input.query),
+ },
+ },
+ };
+ },
+});
+```
+
+**Error Handling in Evals:**
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+export const externalEval = agent.createEval('external-validation', {
+ description: 'Validates output via external API',
+ handler: async (ctx, input, output) => {
+ try {
+ const isValid = await validateWithExternalService(output);
+
+ return {
+ passed: isValid,
+ reason: isValid ? 'Validation passed' : 'Validation failed',
+ };
+ } catch (error) {
+ return {
+ success: false,
+ passed: false,
+ error: `Validation service error: ${error.message}`,
+ };
+ }
+ },
+});
+```
+
+### Eval Execution
+
+Evals run automatically after agent execution completes, using the `waitUntil()` mechanism.
+
+**Execution Flow:**
+
+1. Agent handler executes and returns output
+2. Output is validated against schema
+3. Agent emits `completed` event
+4. All evals attached to the agent run via `waitUntil()`
+5. Eval results are sent to eval tracking service
+6. Response is returned to caller (without waiting for evals)
+
+**Multiple Evals Example:**
+
+```typescript title="src/agent/text-analyzer/eval.ts"
+import agent from './agent';
+
+// Eval 1: Check summary length
+export const summaryLengthEval = agent.createEval('summary-length', {
+ description: 'Validates summary length is within bounds',
+ handler: async (ctx, input, output) => {
+ const passed = output.summary.length >= 20 && output.summary.length <= 200;
+ return {
+ passed,
+ reason: passed ? 'Summary length acceptable' : 'Summary length out of bounds',
+ metadata: { length: output.summary.length },
+ };
+ },
+});
+
+// Eval 2: Check keywords count
+export const keywordsCountEval = agent.createEval('keywords-count', {
+ description: 'Validates keyword count is within bounds',
+ handler: async (ctx, input, output) => {
+ const passed = output.keywords.length >= 2 && output.keywords.length <= 10;
+ return {
+ passed,
+ reason: passed ? 'Keyword count acceptable' : 'Keyword count out of bounds',
+ metadata: { count: output.keywords.length },
+ };
+ },
+});
+
+// Eval 3: Overall quality score
+export const qualityScoreEval = agent.createEval('quality-score', {
+ description: 'Calculates overall quality score',
+ handler: async (ctx, input, output) => {
+ const summaryQuality = output.summary.length >= 50 ? 0.5 : 0.3;
+ const keywordQuality = output.keywords.length >= 3 ? 0.5 : 0.3;
+ const score = summaryQuality + keywordQuality;
+
+ return {
+ passed: score >= 0.7,
+ score,
+ reason: score >= 0.7 ? 'High quality' : 'Below quality threshold',
+ metadata: { summaryQuality, keywordQuality },
+ };
+ },
+});
+```
+
+**Accessing Context in Evals:**
+
+Evals receive the same context as the agent, enabling access to storage, logging, and other services:
+
+```typescript title="src/agent/qa-agent/eval.ts"
+import agent from './agent';
+
+export const loggedEval = agent.createEval('logged-eval', {
+ description: 'Logs eval execution and stores results',
+ handler: async (ctx, input, output) => {
+ // Log eval execution
+ ctx.logger.info('Running eval', {
+ sessionId: ctx.sessionId,
+ input,
+ output,
+ });
+
+ // Store eval results
+ await ctx.kv.set('eval-results', ctx.sessionId, {
+ timestamp: Date.now(),
+ passed: true,
+ });
+
+ return {
+ passed: true,
+ reason: 'Eval completed and logged',
+ };
+ },
+});
+```
+
+---
+
+## Event System
+
+The SDK provides a comprehensive event system for hooking into agent, session, and thread lifecycles.
+
+### Agent Events
+
+Agents emit events during their lifecycle that you can listen to.
+
+**Available Events:**
+
+```typescript
+agent.addEventListener('started', (eventName, agent, ctx) => {
+ // Agent execution has started
+});
+
+agent.addEventListener('completed', (eventName, agent, ctx) => {
+ // Agent execution completed successfully
+ // Evals run during this event
+});
+
+agent.addEventListener('errored', (eventName, agent, ctx, error) => {
+ // Agent execution failed
+});
+```
+
+**Example: Logging Agent Lifecycle:**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const agent = createAgent('TaskRunner', {
+ schema: {
+ input: z.object({ task: z.string() }),
+ output: z.object({ result: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ return { result: `Completed: ${input.task}` };
+ },
+});
+
+// Log when agent starts
+agent.addEventListener('started', (eventName, agent, ctx) => {
+ ctx.logger.info('Agent started', {
+ agentName: agent.metadata.name,
+ sessionId: ctx.sessionId,
+ });
+});
+
+// Log when agent completes
+agent.addEventListener('completed', (eventName, agent, ctx) => {
+ ctx.logger.info('Agent completed', {
+ agentName: agent.metadata.name,
+ sessionId: ctx.sessionId,
+ });
+});
+
+// Log when agent errors
+agent.addEventListener('errored', (eventName, agent, ctx, error) => {
+ ctx.logger.error('Agent errored', {
+ agentName: agent.metadata.name,
+ sessionId: ctx.sessionId,
+ error: error.message,
+ });
+});
+```
+
+### App Events
+
+The application instance emits events for agents, sessions, and threads.
+
+**Available App Events:**
+
+```typescript
+// Agent lifecycle events
+app.addEventListener('agent.started', (eventName, agent, ctx) => {});
+app.addEventListener('agent.completed', (eventName, agent, ctx) => {});
+app.addEventListener('agent.errored', (eventName, agent, ctx, error) => {});
+
+// Session lifecycle events
+app.addEventListener('session.started', (eventName, session) => {});
+app.addEventListener('session.completed', (eventName, session) => {});
+
+// Thread lifecycle events
+app.addEventListener('thread.created', (eventName, thread) => {});
+app.addEventListener('thread.destroyed', (eventName, thread) => {});
+```
+
+**Example: Application-Wide Analytics:**
+
+```typescript
+import { createApp } from '@agentuity/runtime';
+
+const { app, server, logger } = createApp();
+
+// Track agent executions
+let agentExecutions = 0;
+
+app.addEventListener('agent.started', (eventName, agent, ctx) => {
+ agentExecutions++;
+ logger.info(`Total agent executions: ${agentExecutions}`);
+});
+
+// Track errors for monitoring
+app.addEventListener('agent.errored', (eventName, agent, ctx, error) => {
+ logger.error('Agent error detected', {
+ agentName: agent.metadata.name,
+ error: error.message,
+ sessionId: ctx.sessionId
+ });
+
+ // Could send to error tracking service
+ // await sendToErrorTracker(error, agent, ctx);
+});
+
+// Session analytics
+app.addEventListener('session.completed', (eventName, session) => {
+ const messageCount = session.state.get('messageCount') || 0;
+ logger.info('Session completed', {
+ sessionId: session.id,
+ totalMessages: messageCount
+ });
+});
+
+// Thread cleanup
+app.addEventListener('thread.destroyed', (eventName, thread) => {
+ logger.info('Thread destroyed', {
+ threadId: thread.id
+ });
+});
+```
+
+### Event Handlers
+
+Event handlers can be added and removed dynamically.
+
+**Adding Event Listeners:**
+
+```typescript
+// Agent-level
+const handler = (eventName, agent, ctx) => {
+ ctx.logger.info('Agent started');
+};
+
+agent.addEventListener('started', handler);
+
+// App-level
+app.addEventListener('agent.completed', (eventName, agent, ctx) => {
+ ctx.logger.info(`${agent.metadata.name} completed`);
+});
+```
+
+**Removing Event Listeners:**
+
+```typescript
+// Remove specific handler
+agent.removeEventListener('started', handler);
+
+// Note: You must keep a reference to the handler function
+// to remove it later
+```
+
+**Complete Example with Cleanup:**
+
+```typescript
+const agent = createAgent('ActionHandler', {
+ schema: {
+ input: z.object({ action: z.string() }),
+ output: z.object({ success: z.boolean() }),
+ },
+ handler: async (ctx, input) => {
+ return { success: true };
+ },
+});
+
+// Create handlers with references for cleanup
+const startedHandler = (eventName, agent, ctx) => {
+ ctx.logger.info('Started processing');
+};
+
+const completedHandler = (eventName, agent, ctx) => {
+ ctx.logger.info('Completed processing');
+};
+
+const erroredHandler = (eventName, agent, ctx, error) => {
+ ctx.logger.error('Error occurred', { error });
+};
+
+// Add listeners
+agent.addEventListener('started', startedHandler);
+agent.addEventListener('completed', completedHandler);
+agent.addEventListener('errored', erroredHandler);
+
+// Later, if needed, remove listeners
+// agent.removeEventListener('started', startedHandler);
+// agent.removeEventListener('completed', completedHandler);
+// agent.removeEventListener('errored', erroredHandler);
+```
+
+---
+
+## Advanced Features
+
+### File Imports
+
+The Agentuity bundler supports importing various file types directly into your agent code. Files are processed at build time and embedded in your agent bundle, making them immediately available without disk I/O.
+
+**Supported File Types:**
+
+| File Extension | Data Type | Description |
+|----------------|-----------|-------------|
+| `.json` | `object` | Parsed JSON data |
+| `.yaml`, `.yml` | `object` | Parsed YAML data |
+| `.toml` | `object` | Parsed TOML data |
+| `.sql` | `string` | SQL query content |
+| `.txt` | `string` | Text content |
+| `.md` | `string` | Markdown content |
+| `.csv` | `string` | CSV data |
+| `.xml` | `string` | XML content |
+| `.html` | `string` | HTML content |
+| `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.webp` | `string` | Base64 data URL |
+
+**Usage Example:**
+
+```typescript
+import { createAgent } from '@agentuity/runtime';
+import { z } from 'zod';
+
+// Import various file types
+import config from './config.json'; // object
+import emailTemplate from './templates/welcome.txt'; // string
+import getUserQuery from './queries/getUser.sql'; // string
+import logo from './assets/logo.png'; // string (base64 data URL)
+
+const agent = createAgent('ReportGenerator', {
+ schema: {
+ input: z.object({ userId: z.string(), format: z.enum(['html', 'text']) }),
+ output: z.object({ sent: z.boolean(), report: z.string() }),
+ },
+ handler: async (ctx, input) => {
+ // Use JSON config
+ const apiUrl = config.api.baseUrl;
+
+ // Use text template
+ const message = emailTemplate
+ .replace('{{userId}}', input.userId)
+ .replace('{{appName}}', config.appName);
+
+ // Use SQL query
+ const user = await database.query(getUserQuery, [input.userId]);
+
+ // Use image in HTML report
+ let report = 'Text report';
+ if (input.format === 'html') {
+ report = `
+
+
+
+ User Report
+ User: ${user.name}
+
+
+ `;
+ }
+
+ await sendEmail(input.userId, message);
+
+ return { sent: true, report };
+ },
+});
+```
+
+**Key Features:**
+
+- **Build-time processing**: Files are embedded during build, not loaded at runtime
+- **No disk I/O**: Data is immediately available in memory
+- **Automatic parsing**: JSON and YAML files are automatically parsed into objects
+- **Type safety**: TypeScript infers types for imported data
+- **Relative paths**: Import from current directory, subdirectories, or parent directories
+
+**TypeScript Support:**
+
+For TypeScript projects, add type declarations:
+
+```typescript
+// src/types/assets.d.ts
+declare module '*.json' {
+ const value: any;
+ export default value;
+}
+
+declare module '*.sql' {
+ const value: string;
+ export default value;
+}
+
+declare module '*.png' {
+ const value: string; // Base64 data URL
+ export default value;
+}
+
+declare module '*.txt' {
+ const value: string;
+ export default value;
+}
+```
+
+**Best Practices:**
+
+- **Keep files small** - Imported files are bundled with your code, increasing bundle size and deployment time
+- **Use for static data** - Best for configuration, templates, and static assets that don't change frequently
+- **Consider external storage** - For large datasets or frequently changing data, use Object Storage or Vector Storage APIs instead
+- **Version control** - Commit imported files to your repository to keep them in sync with code
+
+**Notes:**
+
+- All imports are processed at build time, not runtime
+- Imported files become part of your agent bundle
+- File paths are relative to the importing file
+- The bundler automatically handles file types by extension
+
+---
+
+## Migrating from v0
+
+For users upgrading from v0, the key architectural changes include:
+
+- **Agent definition**: Function exports → `createAgent('Name', { ... })` API
+- **Handler signature**: `(request, response, context)` → `(ctx, input)`
+- **Returns**: Explicit `response.json()` → Direct returns with schema validation
+- **Agent communication**: `context.getAgent()` → `import agent from '@agent/name'; agent.run()`
+- **File structure**: Single agent file → `src/agent/` for agents, `src/api/` for routes
+- **Context properties**: `runId` → `sessionId`, added `session`, `thread`, `state`
+- **Package names**: `@agentuity/sdk` → `@agentuity/runtime` (or `@agentuity/server`)
+
+For complete migration instructions, see the [Migration Guide](/Reference/migration-guide).
+
+---
diff --git a/content/Routes/cron.mdx b/content/Routes/cron.mdx
new file mode 100644
index 00000000..a9c4c1a6
--- /dev/null
+++ b/content/Routes/cron.mdx
@@ -0,0 +1,148 @@
+---
+title: Scheduling Cron Jobs
+description: Run tasks on a schedule with the cron() middleware
+---
+
+Schedule recurring tasks using cron expressions. Schedules are defined in code, deployed with your agents, and automatically provisioned.
+
+
+All routes live in `src/api/`. Import agents you need and call them directly.
+
+
+## Basic Example
+
+Use the `cron()` middleware to wrap a POST route handler with a schedule:
+
+```typescript
+import { createRouter, cron } from '@agentuity/runtime';
+import reportGenerator from '@agent/report-generator';
+
+const router = createRouter();
+
+// Runs daily at 9am
+router.post('/daily-report', cron('0 9 * * *', async (c) => {
+ c.var.logger.info('Daily report starting');
+
+ const report = await reportGenerator.run({
+ type: 'daily',
+ date: new Date().toISOString(),
+ });
+
+ await c.var.kv.set('reports', `daily-${Date.now()}`, report);
+
+ return c.text('OK');
+}));
+
+export default router;
+```
+
+## Cron Syntax
+
+Standard five-field cron format:
+
+```
+┌───────────── minute (0-59)
+│ ┌───────────── hour (0-23)
+│ │ ┌───────────── day of month (1-31)
+│ │ │ ┌───────────── month (1-12)
+│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
+│ │ │ │ │
+* * * * *
+```
+
+## Common Schedules
+
+| Schedule | Expression | Useful for |
+|----------|------------|-------------|
+| Every 5 minutes | `*/5 * * * *` | Health checks, quick sync |
+| Hourly | `0 * * * *` | Aggregations, cleanup, etc. |
+| Daily at 9am | `0 9 * * *` | Reports, notifications, etc. |
+| Weekly (Sunday midnight) | `0 0 * * 0` | Weekly summaries, etc. |
+| Monthly (1st at midnight) | `0 0 1 * *` | Monthly reports, etc. |
+
+## Full Example
+
+A health check that monitors external services and stores results:
+
+```typescript
+import { createRouter, cron } from '@agentuity/runtime';
+import healthChecker from '@agent/health-checker';
+
+const router = createRouter();
+
+// Runs every 5 minutes
+router.post('/health-check', cron('*/5 * * * *', async (c) => {
+ const startTime = Date.now();
+ c.var.logger.info('Health check starting');
+
+ try {
+ const status = await healthChecker.run({
+ services: ['api', 'database', 'cache'],
+ });
+
+ await c.var.kv.set('monitoring', 'latest-health', {
+ ...status,
+ checkedAt: new Date().toISOString(),
+ durationMs: Date.now() - startTime,
+ });
+
+ c.var.logger.info('Health check completed', { status });
+ return c.text('OK');
+ } catch (error) {
+ c.var.logger.error('Health check failed', { error });
+ return c.text('ERROR', 500);
+ }
+}));
+
+export default router;
+```
+
+## Testing Locally
+
+Cron jobs only trigger in deployed environments. Since cron routes use `router.post()` with an explicit path, you can test them locally by sending a POST request to that path:
+
+```bash
+# Test your cron route locally
+curl -X POST http://localhost:3000/daily-report
+```
+
+The `cron()` middleware only affects scheduling in deployed environments. Locally, the route behaves like a standard POST endpoint.
+
+## Best Practices
+
+- **Log job start and completion** for debugging scheduled tasks
+- **Use `c.var.kv` or object storage** to persist results for later inspection
+- **Handle errors gracefully** so one failure doesn't break the schedule
+- **Keep jobs idempotent** when possible, in case of retries
+
+## Standalone Usage
+
+Cron jobs work without agents. This example clears expired cache entries hourly:
+
+```typescript
+import { createRouter, cron } from '@agentuity/runtime';
+
+const router = createRouter();
+
+// Runs every hour
+router.post('/cache-cleanup', cron('0 * * * *', async (c) => {
+ const allKeys = await c.var.kv.getKeys('cache');
+ const expiredKeys = allKeys.filter(key => key.startsWith('temp-'));
+
+ for (const key of expiredKeys) {
+ await c.var.kv.delete('cache', key);
+ }
+
+ c.var.logger.info('Cache cleanup completed', { deleted: expiredKeys.length });
+ return c.text('OK');
+}));
+
+export default router;
+```
+
+## Next Steps
+
+- [HTTP Routes](/Build/Routes/http): Standard request/response endpoints
+- [Middleware](/Build/Routes/middleware): Add authentication and validation to routes
+- [Key-Value Storage](/Build/Storage/key-value): Store job results
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Orchestrate multiple agents from cron jobs
diff --git a/content/Routes/http.mdx b/content/Routes/http.mdx
new file mode 100644
index 00000000..ca8c0eb5
--- /dev/null
+++ b/content/Routes/http.mdx
@@ -0,0 +1,577 @@
+---
+title: Creating HTTP Routes
+description: Define GET, POST, and other HTTP endpoints with createRouter()
+---
+
+Routes define how your application responds to HTTP requests. Built on [Hono](https://hono.dev), the router provides a familiar Express-like API with full TypeScript support.
+
+
+All routes live in `src/api/`. Import agents you need and call them directly.
+
+
+## Basic Routes
+
+Create routes using `createRouter()`:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/', async (c) => {
+ return c.json({ status: 'healthy' });
+});
+
+router.post('/process', async (c) => {
+ const body = await c.req.json();
+ return c.json({ received: body });
+});
+
+export default router;
+```
+
+
+Return values are automatically converted: `string` → text response, `object` → JSON, `ReadableStream` → streamed response. You can also use explicit methods (`c.json()`, `c.text()`) for more control.
+
+
+## HTTP Methods
+
+The router supports all standard HTTP methods:
+
+```typescript
+router.get('/items', handler); // Read
+router.post('/items', handler); // Create
+router.put('/items/:id', handler); // Replace
+router.patch('/items/:id', handler); // Update
+router.delete('/items/:id', handler); // Delete
+```
+
+## Route Parameters
+
+Capture URL segments with `:paramName`:
+
+```typescript
+router.get('/users/:id', async (c) => {
+ const userId = c.req.param('id');
+ return c.json({ userId });
+});
+
+router.get('/posts/:year/:month/:slug', async (c) => {
+ const { year, month, slug } = c.req.param();
+ return c.json({ year, month, slug });
+});
+```
+
+### Wildcard Parameters
+
+For paths with variable depth, use regex patterns:
+
+```typescript
+router.get('/files/:bucket/:key{.*}', async (c) => {
+ const bucket = c.req.param('bucket');
+ const key = c.req.param('key'); // Captures "path/to/file.txt"
+ return c.json({ bucket, key });
+});
+// GET /files/uploads/images/photo.jpg → { bucket: "uploads", key: "images/photo.jpg" }
+```
+
+## Query Parameters
+
+Access query strings with `c.req.query()`:
+
+```typescript
+router.get('/search', async (c) => {
+ const query = c.req.query('q');
+ const page = c.req.query('page') || '1';
+ const limit = c.req.query('limit') || '10';
+
+ return c.json({ query, page, limit });
+});
+// GET /search?q=hello&page=2 → { query: "hello", page: "2", limit: "10" }
+```
+
+## Calling Agents
+
+Import and call agents directly. To create agents, see [Creating Agents](/Build/Agents/creating-agents).
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import assistant from '@agent/assistant';
+
+const router = createRouter();
+
+router.post('/chat', async (c) => {
+ const { message } = await c.req.json();
+ const response = await assistant.run({ message });
+ return c.json(response);
+});
+
+export default router;
+```
+
+For background processing, use `c.waitUntil()`:
+
+```typescript
+import webhookProcessor from '@agent/webhook-processor';
+
+router.post('/webhook', async (c) => {
+ const payload = await c.req.json();
+
+ // Process in background, respond immediately
+ c.waitUntil(async () => {
+ await webhookProcessor.run(payload);
+ });
+
+ return c.json({ status: 'accepted' });
+});
+```
+
+## Request Validation
+
+Two validators are available depending on your use case:
+
+| Validator | Import | Use Case |
+|-----------|--------|----------|
+| `agent.validator()` | From agent instance | Routes that call an agent |
+| `validator()` | `@agentuity/runtime` | Standalone routes (no agent) |
+
+### With Agents
+
+Use `agent.validator()` when your route calls an agent:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import userCreator from '@agent/user-creator';
+
+const router = createRouter();
+
+// Validates using agent's input schema
+router.post('/users', userCreator.validator(), async (c) => {
+ const data = c.req.valid('json'); // Fully typed from agent schema
+ const user = await userCreator.run(data);
+ return c.json(user);
+});
+
+export default router;
+```
+
+For custom validation (different from the agent's schema), pass a schema override:
+
+```typescript
+import { type } from 'arktype';
+import userCreator from '@agent/user-creator';
+
+router.post('/custom',
+ userCreator.validator({ input: type({ email: 'string.email' }) }),
+ async (c) => {
+ const data = c.req.valid('json'); // Typed as { email: string }
+ return c.json(data);
+ }
+);
+```
+
+
+`agent.validator()` supports three signatures:
+- `agent.validator()` — Uses agent's input/output schemas
+- `agent.validator({ output: schema })` — Output-only validation (GET-compatible)
+- `agent.validator({ input: schema, output?: schema })` — Custom schemas
+
+
+### Standalone Validation
+
+For routes that don't use an agent, import `validator` directly from `@agentuity/runtime`:
+
+```typescript
+import { createRouter, validator } from '@agentuity/runtime';
+import { s } from '@agentuity/schema';
+
+const router = createRouter();
+
+const createUserSchema = s.object({
+ name: s.string(),
+ email: s.string(),
+ age: s.number(),
+});
+
+router.post('/',
+ validator({ input: createUserSchema }),
+ async (c) => {
+ const data = c.req.valid('json');
+ // data is fully typed: { name: string, email: string, age: number }
+ return c.json({ success: true, user: data });
+ }
+);
+
+export default router;
+```
+
+The standalone validator auto-detects the HTTP method:
+- **GET**: Validates query parameters via `c.req.valid('query')`
+- **POST/PUT/PATCH/DELETE**: Validates JSON body via `c.req.valid('json')`
+
+```typescript
+import { createRouter, validator } from '@agentuity/runtime';
+import * as v from 'valibot';
+
+const router = createRouter();
+
+// GET route: validates query parameters
+const searchSchema = v.object({
+ q: v.string(),
+ limit: v.optional(v.number()),
+});
+
+router.get('/search',
+ validator({ input: searchSchema }),
+ async (c) => {
+ const { q, limit } = c.req.valid('query'); // GET uses query params
+ return c.json({ results: [], query: q, limit });
+ }
+);
+
+export default router;
+```
+
+#### Output Validation
+
+Add output validation to ensure your responses match the expected schema:
+
+```typescript
+import { createRouter, validator } from '@agentuity/runtime';
+import { z } from 'zod';
+
+const router = createRouter();
+
+const userInputSchema = z.object({
+ name: z.string(),
+ email: z.string().email(),
+});
+
+const userOutputSchema = z.object({
+ id: z.string(),
+ name: z.string(),
+ email: z.string(),
+ createdAt: z.string(),
+});
+
+router.post('/users',
+ validator({ input: userInputSchema, output: userOutputSchema }),
+ async (c) => {
+ const data = c.req.valid('json');
+ const user = {
+ id: crypto.randomUUID(),
+ ...data,
+ createdAt: new Date().toISOString(),
+ };
+ return c.json(user); // Validated against output schema
+ }
+);
+
+export default router;
+```
+
+
+Both validators work with any [Standard Schema](https://standardschema.dev/) library: `@agentuity/schema`, Zod, Valibot, or ArkType. Choose based on your needs: `@agentuity/schema` for zero dependencies, Zod for `.describe()` support with AI SDK, Valibot for minimal bundle size.
+
+
+
+Import `validator` from `@agentuity/runtime`, not from `hono/validator`. If you use Hono's validator directly, TypeScript won't know your types and `c.req.valid('json')` will show as `never`.
+
+```typescript
+// Types work
+import { validator } from '@agentuity/runtime';
+
+// Types show as 'never'
+import { validator } from 'hono/validator';
+```
+
+
+## Request Context
+
+The context object (`c`) provides access to request data and Agentuity services:
+
+**Request data:**
+```typescript
+await c.req.json(); // Parse JSON body
+await c.req.text(); // Get raw text body
+c.req.param('id'); // Route parameter
+c.req.query('page'); // Query string
+c.req.header('Authorization'); // Request header
+```
+
+**Responses:**
+```typescript
+c.json({ data }); // JSON response
+c.text('OK'); // Plain text
+c.html('Hello '); // HTML response
+c.redirect('/other'); // Redirect
+```
+
+**Agentuity services:**
+```typescript
+// Import agents at the top of your file
+import myAgent from '@agent/my-agent';
+await myAgent.run(input); // Call an agent
+
+c.var.kv.get('bucket', 'key'); // Key-value storage
+c.var.vector.search('ns', opts); // Vector search
+c.var.stream.create('name', opts); // Durable streams
+c.var.logger.info('message'); // Logging
+c.var.sandbox.run({ ... }); // Code execution sandbox
+```
+
+**Thread and session (for stateful routes):**
+```typescript
+c.var.thread.id; // Thread ID (persists across requests)
+c.var.session.id; // Session ID (unique per request)
+await c.var.thread.state.get('key'); // Thread state
+c.var.session.state.get('key'); // Session state
+await c.var.thread.getMetadata(); // Thread metadata
+```
+
+
+Routes can serve as a bridge between external backends (Next.js, Express) and Agentuity storage services. Create authenticated routes that expose KV, Vector, or Stream operations. See [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities).
+
+
+## Best Practices
+
+### Validate input
+
+Always validate request bodies, especially for public endpoints:
+
+```typescript
+// With an agent
+router.post('/api', agent.validator(), async (c) => {
+ const data = c.req.valid('json');
+ // data is guaranteed valid and fully typed
+});
+
+// Without an agent
+router.post('/api', validator({ input: schema }), async (c) => {
+ const data = c.req.valid('json');
+ // data is guaranteed valid and fully typed
+});
+```
+
+### Use structured logging
+
+Use `c.var.logger` instead of `console.log` for searchable, traceable logs:
+
+```typescript
+c.var.logger.info('Request processed', { userId, duration: Date.now() - start });
+c.var.logger.error('Processing failed', { error: err.message });
+```
+
+### Order routes correctly
+
+Register specific routes before generic ones:
+
+```typescript
+// Correct: specific before generic
+router.get('/users/me', getCurrentUser);
+router.get('/users/:id', getUserById);
+
+// Wrong: :id matches "me" first
+router.get('/users/:id', getUserById);
+router.get('/users/me', getCurrentUser); // Never reached
+```
+
+### Use middleware for cross-cutting concerns
+
+Apply middleware to all routes with `router.use()`:
+
+```typescript
+router.use(loggingMiddleware);
+router.use(authMiddleware);
+
+router.get('/protected', handler); // Both middlewares apply
+```
+
+For authentication patterns, rate limiting, and more, see [Middleware](/Build/Routes/middleware).
+
+### Handle errors gracefully
+
+Return appropriate status codes when things go wrong:
+
+```typescript
+import processor from '@agent/processor';
+
+router.post('/process', async (c) => {
+ try {
+ const body = await c.req.json();
+ const result = await processor.run(body);
+ return c.json(result);
+ } catch (error) {
+ c.var.logger.error('Processing failed', { error });
+ return c.json({ error: 'Processing failed' }, 500);
+ }
+});
+```
+
+## Streaming Responses
+
+Use the `stream()` middleware to return a `ReadableStream` directly to the client without buffering:
+
+```typescript
+import { createRouter, stream } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.post('/chat', stream(async (c) => {
+ const body = await c.req.json();
+ return chatAgent.run(body); // Returns a ReadableStream
+}));
+
+export default router;
+```
+
+### Creating Custom Streams
+
+Return any `ReadableStream` for custom streaming:
+
+```typescript
+import { createRouter, stream } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/events', stream((c) => {
+ return new ReadableStream({
+ start(controller) {
+ controller.enqueue('data: event 1\n\n');
+ controller.enqueue('data: event 2\n\n');
+ controller.close();
+ }
+ });
+}));
+
+export default router;
+```
+
+### With Middleware
+
+Stream routes support middleware:
+
+```typescript
+import { createRouter, stream } from '@agentuity/runtime';
+import streamAgent from '@agent/stream';
+
+const router = createRouter();
+
+router.post('/protected', authMiddleware, stream(async (c) => {
+ return streamAgent.run({ userId: c.var.userId });
+}));
+
+export default router;
+```
+
+### Stream vs SSE vs WebSocket
+
+| Type | Direction | Format | Use Case |
+|------|-----------|--------|----------|
+| `stream()` | Server → Client | Raw bytes | LLM responses, file downloads |
+| `sse()` | Server → Client | SSE events | Progress updates, notifications |
+| `websocket()` | Bidirectional | Messages | Chat, collaboration |
+
+Use `stream()` middleware for raw streaming (like AI SDK `textStream`). Use `sse()` middleware when you need named events or auto-reconnection. See [Streaming Responses](/Build/Agents/streaming-responses) for the full guide on streaming agents.
+
+## Routes Without Agents
+
+Not every route needs an agent. Use routes directly for CRUD APIs, webhook handlers, health checks, and proxy endpoints.
+
+### KV-Backed API
+
+```typescript
+import { createRouter, validator } from '@agentuity/runtime';
+import * as v from 'valibot';
+
+const router = createRouter();
+
+const itemSchema = v.object({
+ name: v.string(),
+ value: v.number(),
+});
+
+router.get('/items/:key', async (c) => {
+ const key = c.req.param('key');
+ const result = await c.var.kv.get('items', key);
+
+ if (!result.exists) {
+ return c.json({ error: 'Not found' }, 404);
+ }
+
+ return c.json({ data: result.data });
+});
+
+router.post('/items/:key',
+ validator({ input: itemSchema }),
+ async (c) => {
+ const key = c.req.param('key');
+ const data = c.req.valid('json');
+
+ await c.var.kv.set('items', key, data);
+ c.var.logger.info('Item created', { key });
+
+ return c.json({ success: true, key }, 201);
+ }
+);
+
+router.delete('/items/:key', async (c) => {
+ const key = c.req.param('key');
+ await c.var.kv.delete('items', key);
+
+ return c.json({ success: true });
+});
+
+export default router;
+```
+
+### Webhook Handler
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.post('/webhooks/stripe', async (c) => {
+ const signature = c.req.header('stripe-signature');
+ const payload = await c.req.text();
+
+ // Verify webhook signature
+ if (!verifyStripeSignature(payload, signature)) {
+ c.var.logger.warn('Invalid webhook signature');
+ return c.json({ error: 'Invalid signature' }, 401);
+ }
+
+ const event = JSON.parse(payload);
+
+ // Store event for processing
+ await c.var.kv.set('webhooks', event.id, {
+ type: event.type,
+ data: event.data,
+ receivedAt: new Date().toISOString(),
+ });
+
+ c.var.logger.info('Webhook received', {
+ eventId: event.id,
+ type: event.type,
+ });
+
+ return c.json({ received: true });
+});
+
+export default router;
+```
+
+
+Use agents when you need LLM orchestration, complex schemas, streaming AI responses, or multi-step workflows. Use pure routes for simple CRUD, webhooks, or data proxying.
+
+
+## Next Steps
+
+- [Middleware](/Build/Routes/middleware): Authentication, rate limiting, logging
+- [Scheduled Jobs (Cron)](/Build/Routes/cron): Run tasks on a schedule
+- [WebSockets](/Build/Routes/websockets): Real-time bidirectional communication
+- [Server-Sent Events](/Build/Routes/sse): Stream updates to clients
+- [Creating Agents](/Build/Agents/creating-agents): Build agents to call from routes
+- [Calling Other Agents](/Build/Agents/calling-other-agents): Multi-agent orchestration patterns
diff --git a/content/Routes/index.mdx b/content/Routes/index.mdx
new file mode 100644
index 00000000..ec09854d
--- /dev/null
+++ b/content/Routes/index.mdx
@@ -0,0 +1,165 @@
+---
+title: Routing Overview
+description: Define how requests reach your code
+---
+
+Routes define how requests reach your application, whether HTTP calls, scheduled jobs, or real-time connections. Built on [Hono](https://hono.dev), the router provides a familiar API with full TypeScript support.
+
+
+Routes are defined in your codebase and automatically discovered. Changes are tracked in Git, reviewed in PRs, and deployed with your code. No UI configuration required.
+
+
+## Where Routes Live
+
+All routes live in `src/api/`. Agents and routes are separate concerns:
+
+| Directory | Purpose |
+|-----------|---------|
+| `src/agent/*/` | Agent logic (no routes here) |
+| `src/api/` | All routes: HTTP, cron, WebSocket, SSE, etc. |
+
+Routes import and call agents directly:
+
+```typescript
+// src/api/index.ts
+import { createRouter } from '@agentuity/runtime';
+import slackHandler from '@agent/slack-handler';
+
+const router = createRouter();
+
+router.post('/slack', async (c) => {
+ const payload = await c.req.json();
+ const result = await slackHandler.run(payload);
+ return c.json(result);
+});
+
+export default router;
+```
+
+Routes in `src/api/` are automatically mounted at `/api`. For the full project layout, see [Project Structure](/Get-Started/project-structure).
+
+## Route Types
+
+| Type | Method | Use case |
+|------|--------|----------|
+| [HTTP](/Build/Routes/http) | `router.get()`, `router.post()`, `stream()` middleware | REST APIs, webhooks, LLM streaming |
+| [Middleware](/Build/Routes/middleware) | Hono middleware | Auth, logging, validation |
+| [Cron](/Build/Routes/cron) | `cron()` middleware | Scheduled tasks |
+| [WebSocket](/Build/Routes/websockets) | `websocket()` middleware | Real-time bidirectional |
+| [SSE](/Build/Routes/sse) | `sse()` middleware | Server-sent events |
+
+## Quick Examples
+
+### HTTP
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import assistant from '@agent/assistant';
+
+const router = createRouter();
+
+router.get('/health', (c) => {
+ return c.json({ status: 'ok', timestamp: Date.now() });
+});
+
+router.post('/chat', assistant.validator(), async (c) => {
+ const data = c.req.valid('json');
+ const result = await assistant.run(data);
+ return c.json(result);
+});
+
+export default router;
+```
+
+### Cron
+
+```typescript
+import { cron } from '@agentuity/runtime';
+import reportGenerator from '@agent/report-generator';
+
+router.post('/daily-report', cron('0 9 * * *', async (c) => {
+ await reportGenerator.run({ type: 'daily' });
+ return c.text('OK');
+}));
+```
+
+### WebSocket
+
+```typescript
+import { websocket } from '@agentuity/runtime';
+import assistant from '@agent/assistant';
+
+router.get('/chat', websocket((c, ws) => {
+ ws.onMessage(async (event) => {
+ const response = await assistant.run(event.data);
+ ws.send(response);
+ });
+}));
+```
+
+### SSE
+
+```typescript
+import { sse } from '@agentuity/runtime';
+
+router.get('/stream', sse(async (c, stream) => {
+ for (let i = 0; i < 5; i++) {
+ await stream.writeSSE({ data: `Message ${i}` });
+ }
+ stream.close();
+}));
+```
+
+## Context Access
+
+
+In routes, use [Hono's context](https://hono.dev/docs/api/context): `c.var.logger` or `c.get('logger')`, `c.var.kv`, `c.var.thread`, etc.
+
+In agents, access services directly on `ctx`: `ctx.logger`, `ctx.kv`, `ctx.thread`.
+
+
+All route handlers have access to the same context:
+
+```typescript
+import myAgent from '@agent/my-agent';
+import analytics from '@agent/analytics';
+
+router.post('/', async (c) => {
+ // Request data
+ const body = await c.req.json();
+ const header = c.req.header('Authorization');
+
+ // Logging and session
+ c.var.logger.info('Processing request');
+ const sessionId = c.var.sessionId;
+
+ // Thread and session state
+ c.var.thread.state.set('topic', body.topic);
+ const userId = c.var.session.state.get('userId');
+
+ // Storage
+ await c.var.kv.set('cache', 'key', data);
+ const results = await c.var.vector.search('docs', { query: 'search term' });
+
+ // Durable streams
+ const stream = await c.var.stream.create('export', { contentType: 'text/csv' });
+
+ // Call agents (import them at the top of your file)
+ const result = await myAgent.run(body);
+
+ // Background tasks
+ c.waitUntil(async () => {
+ await analytics.run({ event: 'request' });
+ });
+
+ return c.json(result);
+});
+```
+
+Routes can also expose storage operations to external backends like Next.js or Express. Create authenticated routes that read/write to `c.var.kv`, `c.var.vector`, or `c.var.stream`, then call them via HTTP. See [SDK Utilities for External Apps](/Learn/Cookbook/Patterns/server-utilities) for the complete pattern.
+
+## Next Steps
+
+- [HTTP Routes](/Build/Routes/http) - REST endpoints, parameters, validation
+- [Middleware](/Build/Routes/middleware) - Authentication, logging, CORS
+- [When to Use APIs](/Build/APIs/when-to-use) - Choosing between agents and lightweight routes
diff --git a/content/Routes/meta.json b/content/Routes/meta.json
new file mode 100644
index 00000000..6b695686
--- /dev/null
+++ b/content/Routes/meta.json
@@ -0,0 +1,11 @@
+{
+ "title": "Routes",
+ "pages": [
+ "index",
+ "http",
+ "middleware",
+ "cron",
+ "websockets",
+ "sse"
+ ]
+}
diff --git a/content/Routes/middleware.mdx b/content/Routes/middleware.mdx
new file mode 100644
index 00000000..68553916
--- /dev/null
+++ b/content/Routes/middleware.mdx
@@ -0,0 +1,390 @@
+---
+title: Middleware & Authentication
+description: Add authentication, validation, and request processing to your routes
+---
+
+Agentuity routes are built on [Hono](https://hono.dev), giving you access to Hono's middleware system. Use middleware to add authentication, logging, CORS, rate limiting, and other shared request processing.
+
+
+Middleware works on HTTP, WebSocket, SSE, Cron, and Stream routes.
+
+
+## Basic Middleware
+
+Create middleware with `createMiddleware` from Hono:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+
+const router = createRouter();
+
+// Middleware that logs all requests
+const loggerMiddleware = createMiddleware(async (c, next) => {
+ const start = Date.now();
+ await next();
+ const duration = Date.now() - start;
+ c.var.logger.info('Request completed', {
+ method: c.req.method,
+ path: c.req.path,
+ duration,
+ });
+});
+
+// Apply to specific route
+router.get('/data', loggerMiddleware, (c) => {
+ return c.json({ data: 'value' });
+});
+
+export default router;
+```
+
+## Authentication Patterns
+
+### API Key Authentication
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+
+const router = createRouter();
+
+const apiKeyAuth = createMiddleware(async (c, next) => {
+ const apiKey = c.req.header('X-API-Key');
+
+ if (!apiKey) {
+ return c.json({ error: 'API key required' }, 401);
+ }
+
+ // Validate against stored keys
+ const keyData = await c.var.kv.get('api-keys', apiKey);
+ if (!keyData.exists) {
+ return c.json({ error: 'Invalid API key' }, 401);
+ }
+
+ // Add user info to context for downstream handlers
+ c.set('apiKeyOwner', keyData.data.ownerId);
+ await next();
+});
+
+router.get('/protected', apiKeyAuth, (c) => {
+ const ownerId = c.var.apiKeyOwner;
+ return c.json({ message: 'Access granted', ownerId });
+});
+
+export default router;
+```
+
+### Bearer Token (JWT)
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+import { verify } from 'hono/jwt';
+
+const router = createRouter();
+
+const jwtAuth = createMiddleware(async (c, next) => {
+ const authHeader = c.req.header('Authorization');
+
+ if (!authHeader?.startsWith('Bearer ')) {
+ return c.json({ error: 'Bearer token required' }, 401);
+ }
+
+ const token = authHeader.slice(7);
+
+ try {
+ const payload = await verify(token, process.env.JWT_SECRET!);
+ c.set('user', payload);
+ await next();
+ } catch {
+ return c.json({ error: 'Invalid token' }, 401);
+ }
+});
+
+router.get('/me', jwtAuth, (c) => {
+ const user = c.var.user;
+ return c.json({ userId: user.sub, email: user.email });
+});
+
+export default router;
+```
+
+### Authentication Middleware
+
+The `@agentuity/auth` package provides authentication middleware:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createSessionMiddleware } from '@agentuity/auth';
+import { auth } from '../auth';
+
+const router = createRouter();
+
+router.get('/public', (c) => {
+ return c.json({ message: 'Public endpoint' });
+});
+
+// Protected route requiring authentication
+router.get('/protected', createSessionMiddleware(auth), async (c) => {
+ const user = await c.var.auth.getUser();
+ return c.json({
+ userId: user.id,
+ email: user.email,
+ name: user.name,
+ });
+});
+
+export default router;
+```
+
+The `@agentuity/auth` package automatically integrates with `useAPI` and `useWebsocket` hooks, injecting auth tokens into requests.
+
+
+For complete setup including client-side configuration, see [Adding Authentication](/Build/Frontend/authentication).
+
+
+## Request Validation
+
+Use `agent.validator()` for type-safe request validation:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import agent from './agent';
+
+const router = createRouter();
+
+// Validates using agent's input schema
+router.post('/items', agent.validator(), async (c) => {
+ const data = c.req.valid('json'); // Fully typed from schema
+ await c.var.kv.set('items', crypto.randomUUID(), data);
+ return c.json({ created: true, item: data });
+});
+
+export default router;
+```
+
+### Custom Schema Override
+
+Pass a schema to override the agent's default:
+
+```typescript
+import { z } from 'zod';
+
+const customSchema = z.object({
+ name: z.string().min(1).max(100),
+ price: z.number().positive(),
+ category: z.enum(['electronics', 'clothing', 'food']),
+});
+
+router.post('/custom',
+ agent.validator({ input: customSchema }),
+ async (c) => {
+ const data = c.req.valid('json');
+ return c.json(data);
+ }
+);
+```
+
+### With Valibot
+
+The validator works with any [StandardSchema](https://github.com/standard-schema/standard-schema)-compatible library:
+
+```typescript
+import * as v from 'valibot';
+
+const itemSchema = v.object({
+ name: v.pipe(v.string(), v.minLength(1), v.maxLength(100)),
+ price: v.pipe(v.number(), v.minValue(0)),
+ category: v.picklist(['electronics', 'clothing', 'food']),
+});
+
+router.post('/items',
+ agent.validator({ input: itemSchema }),
+ async (c) => {
+ const data = c.req.valid('json');
+ return c.json(data);
+ }
+);
+```
+
+See [Schema Libraries](/Build/Agents/schema-libraries) for more on Valibot and ArkType.
+
+## Route-Level Middleware
+
+Apply middleware to all routes in a router with `router.use()`:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+
+const router = createRouter();
+
+// Apply to all routes in this file
+router.use('/*', createMiddleware(async (c, next) => {
+ c.var.logger.info('API request', { path: c.req.path });
+ await next();
+}));
+
+// Apply to specific path prefix
+router.use('/admin/*', adminAuthMiddleware);
+
+router.get('/public', (c) => c.text('Anyone can access'));
+router.get('/admin/users', (c) => c.json({ users: [] })); // Requires admin auth
+
+export default router;
+```
+
+## Combining Middleware
+
+Chain multiple middleware for complex requirements:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+import agent from './agent';
+
+const router = createRouter();
+
+const rateLimiter = createMiddleware(async (c, next) => {
+ const ip = c.req.header('x-forwarded-for') || 'unknown';
+ const key = `ratelimit:${ip}`;
+
+ const result = await c.var.kv.get('ratelimit', key);
+ const count = result.exists ? result.data : 0;
+
+ if (count >= 100) {
+ return c.json({ error: 'Rate limit exceeded' }, 429);
+ }
+
+ await c.var.kv.set('ratelimit', key, count + 1, { ttl: 60 });
+ await next();
+});
+
+const authMiddleware = createMiddleware(async (c, next) => {
+ const token = c.req.header('Authorization')?.slice(7);
+ if (!token) {
+ return c.json({ error: 'Unauthorized' }, 401);
+ }
+ c.set('userId', await validateToken(token));
+ await next();
+});
+
+// Chain: rate limit → auth → validation → handler
+router.post('/message',
+ rateLimiter,
+ authMiddleware,
+ agent.validator(),
+ async (c) => {
+ const userId = c.var.userId;
+ const { message } = c.req.valid('json');
+
+ return c.json({ received: true, userId, message });
+ }
+);
+
+export default router;
+```
+
+## Error Handling
+
+Handle errors gracefully in middleware:
+
+```typescript
+import { createRouter } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+
+const router = createRouter();
+
+const errorHandler = createMiddleware(async (c, next) => {
+ try {
+ await next();
+ } catch (error) {
+ c.var.logger.error('Unhandled error', {
+ error: error instanceof Error ? error.message : String(error),
+ path: c.req.path,
+ });
+
+ return c.json(
+ { error: 'Internal server error' },
+ 500
+ );
+ }
+});
+
+router.use('/*', errorHandler);
+
+router.get('/risky', (c) => {
+ // If this throws, errorHandler catches it
+ throw new Error('Something went wrong');
+});
+
+export default router;
+```
+
+## Built-in Middleware
+
+Agentuity provides middleware for common needs, exported from `@agentuity/runtime`.
+
+### CORS
+
+Apply CORS headers to routes:
+
+```typescript
+import { createRouter, createCorsMiddleware } from '@agentuity/runtime';
+
+const router = createRouter();
+
+// Apply CORS to all API routes
+router.use('/api/*', createCorsMiddleware());
+
+// Or with custom options
+router.use('/api/*', createCorsMiddleware({
+ origin: ['https://myapp.com', 'https://admin.myapp.com'],
+ credentials: true,
+ maxAge: 3600,
+}));
+
+export default router;
+```
+
+CORS can also be configured globally via `createApp()`. See [App Configuration](/Get-Started/app-configuration).
+
+### Compression
+
+Compress responses with gzip/deflate based on the `Accept-Encoding` header:
+
+```typescript
+import { createRouter, createCompressionMiddleware } from '@agentuity/runtime';
+
+const router = createRouter();
+
+// Apply compression to all routes
+router.use('/*', createCompressionMiddleware());
+
+// Or with custom threshold (only compress responses > 2KB)
+router.use('/*', createCompressionMiddleware({
+ threshold: 2048,
+}));
+
+export default router;
+```
+
+Compression automatically bypasses:
+- WebSocket upgrade requests
+- Requests without `Accept-Encoding` headers
+- SSE and binary streams
+
+Compression can also be configured globally via `createApp({ compression: { ... } })`. See [App Configuration](/Get-Started/app-configuration).
+
+## Best Practices
+
+- **Order matters**: Middleware runs in registration order. Put error handling first, then auth, then validation.
+- **Early returns**: Return immediately on failure (don't call `next()`).
+- **Share data via context**: Use `c.set('key', value)` to pass data to downstream handlers, access with `c.var.key`.
+- **Keep middleware focused**: Each middleware should do one thing.
+
+## Next Steps
+
+- [HTTP Routes](/Build/Routes/http): Complete routing reference
+- [Calling Agents from APIs](/Build/APIs/calling-agents): Invoke agents from API routes
diff --git a/content/Routes/sse.mdx b/content/Routes/sse.mdx
new file mode 100644
index 00000000..a3cb0d8b
--- /dev/null
+++ b/content/Routes/sse.mdx
@@ -0,0 +1,274 @@
+---
+title: Streaming with SSE
+description: Stream updates from server to client using SSE middleware
+---
+
+Server-Sent Events (SSE) provide efficient one-way streaming from server to client over HTTP. Use them for progress indicators, live feeds, notifications, and LLM response streaming.
+
+
+All routes live in `src/api/`. Import agents you need and call them directly.
+
+
+## Basic Example
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/updates', sse(async (c, stream) => {
+ await stream.write('Connected!');
+
+ // Stream data to client
+ for (let i = 0; i < 5; i++) {
+ await stream.write(`Update ${i + 1}`);
+ await new Promise((r) => setTimeout(r, 1000));
+ }
+
+ stream.close();
+}));
+
+export default router;
+```
+
+## Handler Structure
+
+The `sse()` middleware wraps your handler and provides the stream object:
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+
+router.get('/path', sse(async (c, stream) => {
+ // c - Route context (logger, agents, storage)
+ // stream - SSE stream object
+
+ await stream.write('data');
+ await stream.writeSSE({ event, data, id });
+ stream.onAbort(() => { /* cleanup */ });
+ stream.close(); // Optional: stream closes automatically when handler returns
+}));
+```
+
+## With Middleware
+
+Apply authentication or logging before streaming:
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+
+const router = createRouter();
+
+const authMiddleware = createMiddleware(async (c, next) => {
+ const apiKey = c.req.header('X-API-Key');
+ if (!apiKey) {
+ return c.json({ error: 'API key required' }, 401);
+ }
+ await next();
+});
+
+router.get('/events', authMiddleware, sse(async (c, stream) => {
+ await stream.writeSSE({ event: 'connected', data: 'Authenticated!' });
+
+ // Stream events...
+ stream.close();
+}));
+
+export default router;
+```
+
+## Two Write APIs
+
+### Simple Write
+
+```typescript
+await stream.write('Hello');
+await stream.write(JSON.stringify({ status: 'ok' }));
+```
+
+Automatically formats data as SSE.
+
+### Full SSE Format
+
+```typescript
+await stream.writeSSE({
+ event: 'status', // Event type for client filtering
+ data: 'Processing...', // The payload
+ id: '1', // Optional event ID
+});
+```
+
+Use this for named events that clients can filter.
+
+## Named Events
+
+Clients can listen for specific event types:
+
+**Server:**
+```typescript
+await stream.writeSSE({ event: 'progress', data: '50%' });
+await stream.writeSSE({ event: 'complete', data: JSON.stringify({ success: true }) });
+```
+
+**Client:**
+```javascript
+const source = new EventSource('/agent-name');
+
+source.addEventListener('progress', (e) => {
+ console.log('Progress:', e.data);
+});
+
+source.addEventListener('complete', (e) => {
+ console.log('Done:', JSON.parse(e.data));
+ source.close();
+});
+```
+
+## Full Example
+
+A job progress tracker that streams status updates:
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/', sse(async (c, stream) => {
+ c.var.logger.info('Client connected');
+
+ const steps = [
+ 'Loading resources...',
+ 'Processing data...',
+ 'Generating report...',
+ 'Finalizing...',
+ ];
+
+ let stepIndex = 0;
+
+ const interval = setInterval(async () => {
+ try {
+ if (stepIndex < steps.length) {
+ const progress = ((stepIndex + 1) / steps.length * 100).toFixed(0);
+
+ await stream.writeSSE({
+ event: 'status',
+ data: `[${progress}%] ${steps[stepIndex]}`,
+ id: String(stepIndex),
+ });
+
+ stepIndex++;
+ } else {
+ await stream.write(JSON.stringify({ success: true }));
+ clearInterval(interval);
+ stream.close();
+ }
+ } catch (error) {
+ c.var.logger.error('Stream error', { error });
+ clearInterval(interval);
+ }
+ }, 1000);
+
+ stream.onAbort(() => {
+ c.var.logger.info('Client disconnected');
+ clearInterval(interval);
+ });
+
+ // Keep connection open
+ await new Promise(() => {});
+}));
+
+export default router;
+```
+
+## Client Disconnection
+
+Handle early client disconnection with `onAbort`:
+
+```typescript
+stream.onAbort(() => {
+ clearInterval(interval);
+ // Cancel any pending work
+});
+```
+
+Always clean up resources to prevent memory leaks.
+
+## Keeping the Connection Open
+
+SSE connections stay open until closed. Use a pending promise to keep the handler alive:
+
+```typescript
+router.get('/stream', sse(async (c, stream) => {
+ // Set up intervals, subscriptions, etc.
+
+ // Keep connection open until client disconnects or stream.close()
+ await new Promise(() => {});
+}));
+```
+
+## Client Connection
+
+Connect from JavaScript using the EventSource API:
+
+```javascript
+const source = new EventSource('https://your-project.agentuity.cloud/agent-name');
+
+source.onmessage = (event) => {
+ console.log('Received:', event.data);
+};
+
+source.onerror = () => {
+ console.log('Connection error or closed');
+ source.close();
+};
+```
+
+Or with cURL:
+
+```bash
+curl -N https://your-project.agentuity.cloud/agent-name
+```
+
+## SSE vs WebSocket
+
+| Aspect | SSE | WebSocket |
+|--------|-----|-----------|
+| Direction | Server → Client only | Bidirectional |
+| Protocol | HTTP | WebSocket |
+| Reconnection | Built-in auto-reconnect | Manual |
+| Browser support | Native EventSource | Native WebSocket |
+| Best for | Progress, feeds, LLM streaming | Chat, collaboration |
+
+Use SSE when you only need to push data **from server to client**. Use [WebSockets](/Build/Routes/websockets) when you need **bidirectional** communication.
+
+## Standalone Usage
+
+SSE handlers work without agents. This example streams build logs from storage:
+
+```typescript
+import { createRouter, sse } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/builds/:id/logs', sse(async (c, stream) => {
+ const buildId = c.req.param('id');
+ const logs = await c.var.kv.get('builds', `${buildId}:logs`);
+
+ if (logs.exists) {
+ for (const line of logs.data) {
+ await stream.writeSSE({ event: 'log', data: line });
+ }
+ }
+
+ await stream.writeSSE({ event: 'complete', data: 'Build finished' });
+ stream.close();
+}));
+
+export default router;
+```
+
+## Next Steps
+
+- [WebSockets](/Build/Routes/websockets): Bidirectional real-time communication
+- [HTTP Routes](/Build/Routes/http): Standard request/response endpoints
+- [React Hooks](/Build/Frontend/react-hooks): Connect from React with `useEventStream`
diff --git a/content/Routes/websockets.mdx b/content/Routes/websockets.mdx
new file mode 100644
index 00000000..f0ccd9f0
--- /dev/null
+++ b/content/Routes/websockets.mdx
@@ -0,0 +1,248 @@
+---
+title: Using WebSockets
+description: Real-time bidirectional communication with the websocket middleware
+---
+
+WebSockets enable persistent, bidirectional connections between client and server. Use them for chat interfaces, live dashboards, collaborative tools, and any scenario requiring real-time two-way communication.
+
+
+All routes live in `src/api/`. Import agents you need and call them directly.
+
+
+## Basic Example
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+import chatAgent from '@agent/chat';
+
+const router = createRouter();
+
+router.get('/chat', websocket((c, ws) => {
+ ws.onOpen(() => {
+ c.var.logger.info('Client connected');
+ ws.send('Connected!');
+ });
+
+ ws.onMessage(async (event) => {
+ const message = event.data as string;
+ const response = await chatAgent.run({ message });
+ ws.send(response);
+ });
+
+ ws.onClose(() => {
+ c.var.logger.info('Client disconnected');
+ });
+}));
+
+export default router;
+```
+
+## Handler Structure
+
+The `websocket()` middleware wraps your handler and upgrades the connection:
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+
+router.get('/path', websocket((c, ws) => {
+ // c - Hono context
+ // ws - WebSocket connection object
+
+ ws.onOpen(() => { /* connection opened */ });
+ ws.onMessage(async (event) => { /* message received */ });
+ ws.onClose(() => { /* connection closed */ });
+}));
+```
+
+## WebSocket Events
+
+| Event | Trigger | Example Use Case |
+|-------|---------|------------------|
+| `onOpen` | Connection established | Send welcome message, initialize state |
+| `onMessage` | Client sends data | Process messages, call agents |
+| `onClose` | Connection ends | Clean up resources |
+
+## With Middleware
+
+Apply authentication or logging before the WebSocket upgrade:
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+import { createMiddleware } from 'hono/factory';
+import chat from '@agent/chat';
+
+const router = createRouter();
+
+const authMiddleware = createMiddleware(async (c, next) => {
+ const token = c.req.query('token');
+ if (!token) {
+ return c.text('Unauthorized', 401);
+ }
+ c.set('userId', await validateToken(token));
+ await next();
+});
+
+router.get('/chat', authMiddleware, websocket((c, ws) => {
+ const userId = c.var.userId;
+
+ ws.onOpen(() => {
+ ws.send(`Welcome, user ${userId}!`);
+ });
+
+ ws.onMessage(async (event) => {
+ const response = await chat.run({
+ userId,
+ message: event.data as string,
+ });
+ ws.send(response);
+ });
+}));
+
+export default router;
+```
+
+## Server Push
+
+Send data to the client without waiting for a request:
+
+```typescript
+router.get('/notifications', websocket((c, ws) => {
+ let heartbeat: Timer;
+
+ ws.onOpen(() => {
+ ws.send(JSON.stringify({ type: 'connected' }));
+
+ // Push updates every 5 seconds
+ heartbeat = setInterval(() => {
+ ws.send(JSON.stringify({
+ type: 'heartbeat',
+ time: new Date().toISOString(),
+ }));
+ }, 5000);
+ });
+
+ ws.onClose(() => {
+ clearInterval(heartbeat); // Clean up!
+ });
+}));
+```
+
+## Full Example
+
+A real-time echo server with heartbeat:
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+import echoAgent from '@agent/echo';
+
+const router = createRouter();
+
+router.get('/', websocket((c, ws) => {
+ let heartbeat: Timer;
+
+ ws.onOpen(() => {
+ c.var.logger.info('WebSocket connected');
+ ws.send('Connected! Send a message to echo it back.');
+
+ heartbeat = setInterval(() => {
+ ws.send(`Ping: ${new Date().toLocaleTimeString()}`);
+ }, 5000);
+ });
+
+ ws.onMessage(async (event) => {
+ try {
+ const message = event.data as string;
+ c.var.logger.info('Message received', { message });
+
+ const response = await echoAgent.run(message);
+ ws.send(response);
+ } catch (error) {
+ c.var.logger.error('Message processing failed', { error });
+ ws.send(JSON.stringify({ error: 'Processing failed' }));
+ }
+ });
+
+ ws.onClose(() => {
+ c.var.logger.info('WebSocket disconnected');
+ clearInterval(heartbeat);
+ });
+}));
+
+export default router;
+```
+
+## Resource Cleanup
+
+Always clean up intervals, subscriptions, or other resources in `onClose`:
+
+```typescript
+ws.onClose(() => {
+ clearInterval(heartbeat); // Prevent memory leaks
+ subscription.unsubscribe();
+});
+```
+
+Failing to clean up can cause memory leaks and unexpected behavior.
+
+## Client Connection
+
+Connect from a browser or any WebSocket client:
+
+```javascript
+const ws = new WebSocket('wss://your-project.agentuity.cloud/agent-name');
+
+ws.onopen = () => {
+ console.log('Connected');
+ ws.send('Hello!');
+};
+
+ws.onmessage = (event) => {
+ console.log('Received:', event.data);
+};
+
+ws.onclose = () => {
+ console.log('Disconnected');
+};
+```
+
+## When to Use WebSockets
+
+| Use Case | WebSocket | SSE | HTTP |
+|----------|-----------|-----|------|
+| Chat / messaging | ✓ | | |
+| Live collaboration | ✓ | | |
+| Real-time dashboards | ✓ | ✓ | |
+| Progress updates | | ✓ | |
+| Request/response API | | | ✓ |
+
+Use WebSockets when you need **bidirectional** communication. For **server-to-client only** streaming, consider [Server-Sent Events](/Build/Routes/sse).
+
+## Standalone Usage
+
+WebSocket handlers work without agents. This example broadcasts system metrics to connected clients:
+
+```typescript
+import { createRouter, websocket } from '@agentuity/runtime';
+
+const router = createRouter();
+
+router.get('/metrics', websocket((c, ws) => {
+ const interval = setInterval(() => {
+ ws.send(JSON.stringify({
+ cpu: Math.random() * 100,
+ memory: Math.random() * 100,
+ timestamp: Date.now(),
+ }));
+ }, 5000);
+
+ ws.onClose(() => clearInterval(interval));
+}));
+
+export default router;
+```
+
+## Next Steps
+
+- [Server-Sent Events](/Build/Routes/sse): One-way streaming from server to client
+- [HTTP Routes](/Build/Routes/http): Standard request/response endpoints
+- [React Hooks](/Build/Frontend/react-hooks): Connect from React with `useWebsocket`
diff --git a/content/SDKs/index.mdx b/content/SDKs/index.mdx
deleted file mode 100644
index 3749fba1..00000000
--- a/content/SDKs/index.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: SDKs
-description: Agentuity SDKs
----
-
-
-
- Python SDK
- Build AI Agents with our Python SDK
-
-
-
- JavaScript SDK
- Build AI Agents using our JavaScript/TypeScript SDK
-
-
diff --git a/content/SDKs/javascript/api-reference.mdx b/content/SDKs/javascript/api-reference.mdx
deleted file mode 100644
index 64c90b8e..00000000
--- a/content/SDKs/javascript/api-reference.mdx
+++ /dev/null
@@ -1,2305 +0,0 @@
----
-title: API Reference
-description: Comprehensive reference for the Agentuity JavaScript SDK API
----
-
-This section provides detailed documentation for the Agentuity JavaScript SDK API, including method signatures, parameters, return values, and example usage.
-
-## Table of Contents
-
-- [File Imports](#file-imports)
-- [Agent Lifecycle](#agent-lifecycle)
-- [Context API](#context-api)
- - [Background Tasks (waitUntil)](#background-tasks-waituntil)
-- [Storage APIs](#storage-apis)
- - [Key-Value Storage](#key-value-storage)
- - [Vector Storage](#vector-storage)
- - [Object Storage](#object-storage)
- - [Stream Storage](#stream-storage)
-- [Agent Communication](#agent-communication)
-- [Response Types](#response-types)
- - [Stream Method](#stream-method)
-- [Request Handling](#request-handling)
-- [Logging](#logging)
-- [Telemetry](#telemetry)
-
-## File Imports
-
-The Agentuity JavaScript SDK supports automatic importing of various file types directly into your agent code. Files are processed at build time and their contents are embedded in your agent bundle, making the data immediately available without disk I/O.
-
-### Supported File Types
-
-| File Extension | Data Type | Description |
-|----------------|-----------|-------------|
-| `.json` | `object` | Parsed JSON data as a JavaScript object |
-| `.yaml`, `.yml` | `object` | Parsed YAML data as a JavaScript object |
-| `.txt` | `string` | Text content as a string |
-| `.md` | `string` | Markdown content as a string |
-| `.csv` | `string` | CSV data as a string |
-| `.xml` | `string` | XML content as a string |
-| `.sql` | `string` | SQL query content as a string |
-| `.png` | `Uint8Array` | Binary image data |
-| `.jpg`, `.jpeg` | `Uint8Array` | Binary image data |
-| `.gif` | `Uint8Array` | Binary image data |
-| `.svg` | `Uint8Array` | Binary SVG data |
-| `.webp` | `Uint8Array` | Binary image data |
-| `.pdf` | `Uint8Array` | Binary PDF data |
-
-### Usage Examples
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-
-// Import various file types
-import config from './config.yaml'; // object
-import userData from './users.json'; // object
-import readme from './README.md'; // string
-import csvData from './data.csv'; // string
-import sqlQuery from './queries/users.sql'; // string
-import xmlConfig from './config.xml'; // string
-import logo from './assets/logo.png'; // Uint8Array
-import iconSvg from './assets/icon.svg'; // Uint8Array
-
-const handler: AgentHandler = async (request, response, context) => {
- // Use YAML/JSON data directly as objects
- const apiUrl = config.api.baseUrl;
- const userCount = userData.users.length;
-
- // Use text data as strings
- const instructions = readme;
- const query = sqlQuery.replace('{{limit}}', '10');
-
- // Use binary data (e.g., for object storage)
- await context.objectstore.put('assets', 'logo.png', logo, {
- contentType: 'image/png'
- });
-
- await context.objectstore.put('assets', 'icon.svg', iconSvg, {
- contentType: 'image/svg+xml'
- });
-
- // Process CSV data
- const csvLines = csvData.split('\n');
- const headers = csvLines[0].split(',');
-
- return response.json({
- config: apiUrl,
- userCount,
- logoSize: logo.length,
- svgSize: iconSvg.length,
- csvHeaders: headers,
- sqlQuery: query
- });
-};
-
-export default handler;
-```
-
-### Key Features
-
-- **Build-time Processing**: Files are processed and embedded during the build process
-- **No Disk I/O**: Data is immediately available in memory, no file system access required
-- **Automatic Parsing**: JSON and YAML files are automatically parsed into JavaScript objects
-- **Type Safety**: TypeScript users get proper type inference for imported data
-- **Relative Paths**: Support for relative imports from your agent directory and parent directories
-
-### File Import Paths
-
-```typescript
-// Import from same directory
-import localData from './data.json';
-
-// Import from subdirectory
-import assetData from './assets/config.yaml';
-
-// Import from parent directories
-import sharedConfig from '../shared/config.json';
-import rootData from '../../../files/data.csv';
-```
-
-## Agent Lifecycle
-
-The Agentuity SDK provides a structured way to define and handle agents. An agent consists of a handler function, with its configuration managed by the Agentuity CLI.
-
-### Agent Configuration
-
-Agent configuration is managed by the Agentuity CLI and stored in the project configuration file. The `AgentConfig` interface is used internally by the CLI and SDK:
-
-```typescript
-interface AgentConfig {
- /**
- * the name of the agent
- */
- name: string;
- /**
- * the description of the agent
- */
- description?: string;
-}
-```
-
-### Agent Handler
-
-The `AgentHandler` type defines the handler function for an agent:
-
-```typescript
-type AgentHandler = (
- request: AgentRequest,
- response: AgentResponse,
- context: AgentContext
-) => Promise;
-```
-
-**Parameters**
-
-- `request`: An `AgentRequest` object containing the request data
-- `response`: An `AgentResponse` object for creating responses
-- `context`: An `AgentContext` object providing access to various capabilities
-
-**Return Value**
-
-The handler function should return a Promise that resolves to an `AgentResponseType` object.
-
-**Example**
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-
-// Agent handler function
-const handler: AgentHandler = async (request, response, context) => {
- try {
- // Get the request data
- const { name } = await request.data.json();
-
- // Log the request
- context.logger.info(`Received greeting request for ${name}`);
-
- // Return a personalized greeting
- return response.json({
- message: `Hello, ${name}! Welcome to Agentuity.`
- });
- } catch (error) {
- // Handle errors
- context.logger.error('Error processing request', error);
- return response.json({ error: 'Failed to process request' });
- }
-};
-
-export default handler;
-```
-
-## Context API
-
-The `AgentContext` provides access to various capabilities and services within your agent handler. In addition to storage APIs and logging, it offers background task management and stream creation capabilities.
-
-### Background Tasks (waitUntil)
-
-The `waitUntil` method allows you to execute background tasks that don't need to block the immediate response to the client. These tasks will be completed after the main response is sent.
-
-#### waitUntil
-
-`waitUntil(callback: WaitUntilCallback): void`
-
-Defers the execution of a background task until after the main response has been sent.
-
-**Parameters**
-
-- `callback`: A function that will be executed asynchronously in the background
-
-**Example**
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-
-const handler: AgentHandler = async (request, response, context) => {
- const { userId, message } = await request.data.json();
-
- // Send immediate response
- const responseData = { status: 'received', timestamp: Date.now() };
-
- // Schedule background tasks
- context.waitUntil(async () => {
- // Log the message asynchronously
- await logMessageToDatabase(userId, message);
- });
-
- context.waitUntil(async () => {
- // Send notification email in the background
- await sendNotificationEmail(userId, message);
- });
-
- context.waitUntil(async () => {
- // Update analytics in the background
- await updateAnalytics(userId, 'message_received');
- });
-
- // Return immediately without waiting for background tasks
- return response.json(responseData);
-};
-
-export default handler;
-```
-
-**Use Cases**
-
-- Logging and analytics that don't affect the user experience
-- Sending notifications or emails
-- Database cleanup or maintenance tasks
-- Third-party API calls that don't impact the response
-- Background data processing or enrichment
-
-## Storage APIs
-
-The Agentuity SDK provides four storage APIs: Key-Value Storage, Vector Storage, Object Storage, and Stream Storage.
-
-### Key-Value Storage
-
-The Key-Value Storage API provides a simple way to store and retrieve data. It is accessed through the `context.kv` object.
-
-#### get
-
-`get(name: string, key: string): Promise`
-
-Retrieves a value from the key-value storage.
-
-**Parameters**
-
-- `name`: The name of the key-value storage
-- `key`: The key to retrieve the value for
-
-**Return Value**
-
-Returns a Promise that resolves to a DataResult object. The DataResult has an `exists` boolean property and a `data` property containing the value if found.
-
-**Example**
-
-```typescript
-// Retrieve a value from key-value storage
-const result = await context.kv.get('user-preferences', 'user-123');
-if (result.exists) {
- // Access data using the Data interface methods
- const valueString = await result.data.text();
- console.log(`User preferences: ${valueString}`);
-} else {
- console.log('User preferences not found');
-}
-```
-
-#### set
-
-`set(name: string, key: string, value: ArrayBuffer | string | Json, ttl?: number): Promise`
-
-Stores a value in the key-value storage.
-
-**Parameters**
-
-- `name`: The name of the key-value storage
-- `key`: The key to store the value under
-- `value`: The value to store (can be an ArrayBuffer, string, or JSON object)
-- `ttl` (optional): Time-to-live in seconds (minimum 60 seconds)
-
-**Return Value**
-
-Returns a Promise that resolves when the value has been stored.
-
-**Example**
-
-```typescript
-// Store a string value
-await context.kv.set('user-preferences', 'user-123', JSON.stringify({ theme: 'dark' }));
-
-// Store a JSON value
-await context.kv.set('user-preferences', 'user-123', { theme: 'dark' });
-
-// Store a binary value
-const binaryData = new Uint8Array([1, 2, 3, 4]).buffer;
-await context.kv.set('user-data', 'user-123', binaryData);
-
-// Store a value with TTL (expires after 1 hour)
-await context.kv.set('session', 'user-123', 'active', 3600);
-```
-
-#### delete
-
-`delete(name: string, key: string): Promise`
-
-Deletes a value from the key-value storage.
-
-**Parameters**
-
-- `name`: The name of the key-value storage
-- `key`: The key to delete
-
-**Return Value**
-
-Returns a Promise that resolves when the value has been deleted.
-
-**Example**
-
-```typescript
-// Delete a value
-await context.kv.delete('user-preferences', 'user-123');
-```
-
-### Vector Storage
-
-The Vector Storage API provides a way to store and search for data using vector embeddings. It is accessed through the `context.vector` object.
-
-#### upsert
-
-`upsert(name: string, ...documents: VectorUpsertParams[]): Promise`
-
-Inserts or updates vectors in the vector storage.
-
-**Parameters**
-
-- `name`: The name of the vector storage
-- `documents`: One or more documents to upsert. Each document must include a unique `key` and either embeddings or text
-
-**Return Value**
-
-Returns a Promise that resolves to an array of string IDs for the upserted vectors.
-
-**Example**
-
-```typescript
-// Upsert documents with text
-const ids = await context.vector.upsert(
- 'product-descriptions',
- { key: 'chair-001', document: 'Ergonomic office chair with lumbar support', metadata: { category: 'furniture' } },
- { key: 'headphones-001', document: 'Wireless noise-cancelling headphones', metadata: { category: 'electronics' } }
-);
-
-// Upsert documents with embeddings
-const ids2 = await context.vector.upsert(
- 'product-embeddings',
- { key: 'embed-123', embeddings: [0.1, 0.2, 0.3, 0.4], metadata: { productId: '123' } },
- { key: 'embed-456', embeddings: [0.5, 0.6, 0.7, 0.8], metadata: { productId: '456' } }
-);
-```
-
-#### search
-
-`search(name: string, params: VectorSearchParams): Promise`
-
-Searches for vectors in the vector storage.
-
-**Parameters**
-
-- `name`: The name of the vector storage
-- `params`: Search parameters object with the following properties:
- - `query` (string, required): The text query to search for. This will be converted to embeddings and used to find semantically similar documents.
- - `limit` (number, optional): Maximum number of search results to return. Must be a positive integer. If not specified, the server default will be used.
- - `similarity` (number, optional): Minimum similarity threshold for results (0.0-1.0). Only vectors with similarity scores greater than or equal to this value will be returned. 1.0 means exact match, 0.0 means no similarity requirement.
- - `metadata` (object, optional): Metadata filters to apply to the search. Only vectors whose metadata matches all specified key-value pairs will be included in results. Must be a valid JSON object.
-
-**Return Value**
-
-Returns a Promise that resolves to an array of search results, each containing an ID, key, metadata, and similarity score.
-
-**Examples**
-
-```typescript
-// Basic search with query only
-const results = await context.vector.search('product-descriptions', {
- query: 'comfortable office chair'
-});
-
-// Search with limit and similarity threshold
-const results = await context.vector.search('product-descriptions', {
- query: 'comfortable office chair',
- limit: 5,
- similarity: 0.7
-});
-
-// Search with metadata filtering
-const results = await context.vector.search('product-descriptions', {
- query: 'comfortable office chair',
- limit: 10,
- similarity: 0.6,
- metadata: { category: 'furniture', inStock: true }
-});
-
-// Process search results
-for (const result of results) {
- console.log(`Product ID: ${result.id}, Similarity: ${result.similarity}`);
- console.log(`Key: ${result.key}`);
- console.log(`Metadata: ${JSON.stringify(result.metadata)}`);
-}
-```
-
-#### get
-
-`get(name: string, key: string): Promise`
-
-Retrieves a specific vector from the vector storage using its key.
-
-**Parameters**
-
-- `name`: The name of the vector storage
-- `key`: The unique key of the vector to retrieve
-
-**Return Value**
-
-Returns a Promise that resolves to a `VectorSearchResult` object if found, or `null` if the key doesn't exist.
-
-**Example**
-
-```typescript
-// Retrieve a specific vector by key
-const vector = await context.vector.get('product-descriptions', 'chair-001');
-
-if (vector) {
- console.log(`Found vector: ${vector.id}`);
- console.log(`Key: ${vector.key}`);
- console.log(`Metadata:`, vector.metadata);
-} else {
- console.log('Vector not found');
-}
-```
-
-#### delete
-
-`delete(name: string, ...keys: string[]): Promise`
-
-Deletes one or more vectors from the vector storage.
-
-**Parameters**
-
-- `name`: The name of the vector storage
-- `keys`: One or more keys of the vectors to delete
-
-**Return Value**
-
-Returns a Promise that resolves to the number of vectors that were deleted.
-
-**Examples**
-
-```typescript
-// Delete a single vector by key
-const deletedCount = await context.vector.delete('product-descriptions', 'chair-001');
-console.log(`Deleted ${deletedCount} vector(s)`); // Output: Deleted 1 vector(s)
-
-// Delete multiple vectors in bulk (more efficient than individual calls)
-const deletedCount = await context.vector.delete('product-descriptions', 'chair-001', 'headphones-001', 'desk-002');
-console.log(`Deleted ${deletedCount} vector(s)`); // Output: Deleted 3 vector(s)
-
-// Delete with array spread
-const keysToDelete = ['chair-001', 'headphones-001', 'desk-002'];
-const deletedCount = await context.vector.delete('product-descriptions', ...keysToDelete);
-
-// Handle cases where some vectors might not exist
-const deletedCount = await context.vector.delete('product-descriptions', 'existing-key', 'non-existent-key');
-console.log(`Deleted ${deletedCount} vector(s)`); // Output: Deleted 1 vector(s)
-```
-
-### Object Storage
-
-The Object Storage API provides a way to store and retrieve objects (files, documents, media) with support for public URL generation. It is accessed through the `context.objectstore` object.
-
-#### get
-
-`get(bucket: string, key: string): Promise`
-
-Retrieves an object from the object storage.
-
-**Parameters**
-
-- `bucket`: The bucket to get the object from
-- `key`: The key of the object to get
-
-**Return Value**
-
-Returns a Promise that resolves to a DataResult object. The DataResult has an `exists` boolean property and a `data` property containing the object data if found.
-
-**Example**
-
-```typescript
-// Retrieve an object from object storage
-const result = await context.objectstore.get('user-uploads', 'profile-123.jpg');
-if (result.exists) {
- // Access data using the Data interface methods
- const imageData = await result.data.binary();
- console.log(`Image size: ${imageData.byteLength} bytes`);
-} else {
- console.log('Image not found');
-}
-```
-
-#### put
-
-`put(bucket: string, key: string, data: DataType, params?: ObjectStorePutParams): Promise`
-
-Stores an object in the object storage.
-
-**Parameters**
-
-- `bucket`: The bucket to put the object into
-- `key`: The key of the object to put
-- `data`: The data to store (can be ArrayBuffer, string, or other DataType)
-- `params` (optional): Additional parameters for the object. The following properties map to canonical HTTP headers: `contentType` (Content-Type), `contentEncoding` (Content-Encoding), `cacheControl` (Cache-Control), `contentDisposition` (Content-Disposition), and `contentLanguage` (Content-Language). The optional `metadata` property accepts a dictionary of arbitrary key-value pairs that will be stored as metadata with the object but not returned as part of HTTP results when the object is fetched. The `contentType` parameter is optional - if not provided, the content type will be automatically detected based on the data type (e.g., objects will be set to `application/json`). If the content type cannot be determined, it defaults to `application/octet-stream`.
-
-**Return Value**
-
-Returns a Promise that resolves when the object has been stored.
-
-**Example**
-
-```typescript
-// Store a text file with explicit content type
-await context.objectstore.put('documents', 'readme.txt', 'Hello, world!', {
- contentType: 'text/plain'
-});
-
-// Store an object (content type auto-detected as application/json)
-const userData = { name: 'John', age: 30 };
-await context.objectstore.put('users', 'user-123.json', userData);
-
-// Store a binary file
-const imageData = new Uint8Array([/* image bytes */]).buffer;
-await context.objectstore.put('images', 'photo.jpg', imageData, {
- contentType: 'image/jpeg'
-});
-
-// Store without specifying content type (will default to application/octet-stream if unknown)
-await context.objectstore.put('files', 'unknown-data', someData);
-
-// Store with custom encoding and cache control
-await context.objectstore.put('compressed', 'data.gz', compressedData, {
- contentType: 'application/octet-stream',
- contentEncoding: 'gzip',
- cacheControl: 'max-age=3600'
-});
-
-// Store with metadata (not returned in HTTP results when fetched)
-await context.objectstore.put('uploads', 'document.pdf', pdfData, {
- contentType: 'application/pdf',
- contentDisposition: 'attachment; filename="report.pdf"',
- contentLanguage: 'en-US',
- metadata: {
- 'user-id': '12345',
- 'upload-source': 'web-app',
- 'version': '2.0'
- }
-});
-```
-
-#### delete
-
-`delete(bucket: string, key: string): Promise`
-
-Deletes an object from the object storage.
-
-**Parameters**
-
-- `bucket`: The bucket to delete the object from
-- `key`: The key of the object to delete
-
-**Return Value**
-
-Returns a Promise that resolves to a boolean indicating whether the object was deleted (true) or didn't exist (false).
-
-**Example**
-
-```typescript
-// Delete an object
-const wasDeleted = await context.objectstore.delete('user-uploads', 'old-file.pdf');
-if (wasDeleted) {
- console.log('File deleted successfully');
-} else {
- console.log('File did not exist');
-}
-```
-
-#### createPublicURL
-
-`createPublicURL(bucket: string, key: string, expiresDuration?: number): Promise`
-
-Creates a time-limited public URL for accessing an object.
-
-**Parameters**
-
-- `bucket`: The bucket containing the object
-- `key`: The key of the object
-- `expiresDuration` (optional): Duration in milliseconds until the URL expires. Defaults to 1 hour (3600000ms) if not provided. Minimum value is 1 minute (60000ms) - values less than 1 minute will be set to 1 minute.
-
-**Return Value**
-
-Returns a Promise that resolves to a public URL string that can be used to access the object.
-
-**Example**
-
-```typescript
-// Create a public URL that expires in 1 hour
-const publicUrl = await context.objectstore.createPublicURL(
- 'user-uploads',
- 'document.pdf',
- 3600000 // 1 hour in milliseconds
-);
-
-// Share the URL with users
-console.log(`Download link: ${publicUrl}`);
-
-// Create a URL with default expiration (1 hour)
-const defaultUrl = await context.objectstore.createPublicURL('images', 'photo.jpg');
-
-// Create a URL with minimum expiration (1 minute)
-const shortUrl = await context.objectstore.createPublicURL(
- 'temp-files',
- 'quick-access.txt',
- 60000 // 1 minute in milliseconds
-);
-
-// Values less than 1 minute will be automatically set to 1 minute
-const autoMinUrl = await context.objectstore.createPublicURL(
- 'temp-files',
- 'auto-min.txt',
- 30000 // Will be set to 60000ms (1 minute)
-);
-```
-
-### Stream Storage
-
-The Stream Storage API provides first-class support for creating and managing server-side streams, enabling efficient data streaming within your agents. Streams are accessible via the `context.stream` object.
-
-#### create
-
-`create(name: string, props?: StreamCreateProps): Promise`
-
-Creates a new, named, writable stream.
-
-**Parameters**
-
-- `name`: A string identifier for the stream
-- `props` (optional): Configuration object with the following properties:
- - `metadata`: An optional object containing key-value pairs to help identify, search, or tag specific information about the stream (e.g., `customerId`, `type`, `requestId`, `userId`)
- - `contentType`: Specifies the content type of the stream (defaults to `application/octet-stream`)
- - `compress`: Enable automatic gzip compression (defaults to `false`)
-
-**Return Value**
-
-Returns a Promise that resolves to a `Stream` object with the following properties:
-- `id`: The unique identifier of the stream
-- `url`: The URL to consume the stream
-- Extends `WritableStream` for standard stream operations
-
-**Stream Characteristics**
-
-- **Read-Many**: Streams can be read by multiple consumers simultaneously
-- **Re-readable**: Streams can be read multiple times - each new request starts from the beginning
-- **Resumable**: Streams support HTTP Range requests for resuming from specific byte offsets
-- **Persistent**: Stream URLs remain accessible until the stream expires
-- **HTTP Range Support**: Clients can request specific byte ranges using standard HTTP Range headers
-
-**Example**
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const handler: AgentHandler = async (request, response, context) => {
- const { prompt, userId, sessionId } = await request.data.json();
-
- // Create a stream with metadata for identification and searching
- const stream = await context.stream.create('llm-response', {
- contentType: 'text/plain',
- metadata: {
- userId,
- sessionId,
- requestId: context.sessionId,
- type: 'llm-generation',
- model: 'gpt-4o',
- category: 'chat-completion',
- promptLength: String(prompt?.length ?? 0)
- }
- });
-
- // Use waitUntil to pipe data in the background
- context.waitUntil(async () => {
- const { textStream } = streamText({
- model: openai('gpt-4o'),
- prompt
- });
-
- // Pipe the LLM stream to our created stream
- await textStream.pipeTo(stream);
- });
-
- // Return stream info immediately
- return response.json({
- streamId: stream.id,
- streamUrl: stream.url,
- status: 'streaming'
- });
-};
-
-export default handler;
-```
-
-**Writing to Streams**
-
-```typescript
-// Direct write() method (recommended)
-const stream = await context.stream.create('progress-updates', {
- contentType: 'application/json'
-});
-
-context.waitUntil(async () => {
- try {
- await stream.write(JSON.stringify({ status: 'starting' }) + '\n');
- await stream.write(JSON.stringify({ status: 'processing' }) + '\n');
- context.logger.info(`Bytes written: ${stream.bytesWritten}`);
- } finally {
- await stream.close();
- }
-});
-
-// Manual writer management (advanced use)
-const writer = stream.getWriter();
-try {
- // SDK auto-converts strings (standard streams require TextEncoder)
- await writer.write('data');
-} finally {
- await writer.releaseLock();
- await stream.close();
-}
-```
-
-**Stream Compression**
-
-```typescript
-// Enable compression for large text or JSON data
-const stream = await context.stream.create('large-dataset', {
- contentType: 'application/json',
- compress: true,
- metadata: { type: 'export' }
-});
-
-context.waitUntil(async () => {
- try {
- for (const record of dataset) {
- await stream.write(JSON.stringify(record) + '\n');
- }
- context.logger.info(`Written: ${stream.bytesWritten} bytes, Compressed: ${stream.compressed}`);
- } finally {
- await stream.close();
- }
-});
-```
-
-#### list
-
-`list(params?: ListStreamsParams): Promise`
-
-Lists and searches through your streams with flexible filtering and pagination options.
-
-**Parameters**
-
-- `params` (optional): Configuration object with the following properties:
- - `name` (optional): Filter streams by name
- - `metadata` (optional): An object with key-value pairs to filter streams by their metadata
- - `limit` (optional): Maximum number of streams to return (1-1000, defaults to 100)
- - `offset` (optional): Number of streams to skip for pagination
-
-**Return Value**
-
-Returns a Promise that resolves to a `ListStreamsResponse` object:
-- `success`: Boolean indicating if the request succeeded
-- `streams`: Array of stream objects, each containing:
- - `id`: The unique identifier of the stream
- - `name`: The name of the stream
- - `metadata`: The metadata associated with the stream
- - `url`: The URL of the stream
- - `sizeBytes`: The size of the stream in bytes
-- `total`: Total count of streams matching your filters (useful for pagination)
-- `message`: Optional error message if the request failed
-
-**Examples**
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-
-const handler: AgentHandler = async (request, response, context) => {
- // List all streams
- const result = await context.stream.list();
- console.log(`Found ${result.total} streams`);
- result.streams.forEach(stream => {
- console.log(`${stream.name}: ${stream.url} (${stream.sizeBytes} bytes)`);
- });
-
- // Filter by name
- const namedStreams = await context.stream.list({
- name: 'llm-response'
- });
-
- // Filter by metadata
- const userStreams = await context.stream.list({
- metadata: { userId: 'user-123', type: 'llm-generation' }
- });
-
- // Paginate results
- const page1 = await context.stream.list({ limit: 10, offset: 0 });
- const page2 = await context.stream.list({ limit: 10, offset: 10 });
-
- // Combine filters
- const filtered = await context.stream.list({
- name: 'analytics',
- metadata: { department: 'sales' },
- limit: 50
- });
-
- return response.json({ streams: filtered.streams });
-};
-
-export default handler;
-```
-
-#### delete
-
-`delete(id: string): Promise`
-
-Deletes a stream by its ID when it's no longer needed.
-
-**Parameters**
-
-- `id` (required): The stream ID to delete. Must be a non-empty string.
-
-**Return Value**
-
-Returns a Promise that resolves to void on success.
-
-**Error Handling**
-
-- Throws an error if the stream ID is invalid or empty
-- Throws a "Stream not found" error if the stream with the given ID does not exist
-
-**Examples**
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-
-const handler: AgentHandler = async (request, response, context) => {
- const { streamId } = await request.data.json();
-
- // Delete a stream
- await context.stream.delete(streamId);
-
- // Handle deletion with error checking
- try {
- await context.stream.delete(streamId);
- context.logger.info('Stream deleted successfully');
- return response.json({ success: true });
- } catch (error) {
- if (error.message.includes('not found')) {
- return response.json({ error: 'Stream does not exist' }, { status: 404 });
- }
- throw error;
- }
-};
-
-export default handler;
-```
-
-**Complete Workflow Example**
-
-This example demonstrates creating streams, listing them by metadata, and cleaning up old streams:
-
-```typescript
-import { AgentHandler } from '@agentuity/sdk';
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const handler: AgentHandler = async (request, response, context) => {
- const { prompt, userId } = await request.data.json();
-
- // Create a stream with metadata
- const stream = await context.stream.create('user-export', {
- contentType: 'text/plain',
- metadata: { userId, format: 'csv', timestamp: Date.now() }
- });
-
- context.waitUntil(async () => {
- await stream.write('Name,Email\n');
- await stream.write('John,john@example.com\n');
- await stream.close();
- });
-
- // List streams by metadata
- const userStreams = await context.stream.list({
- metadata: { userId }
- });
-
- context.logger.info(`Found ${userStreams.total} streams for user ${userId}`);
-
- // Clean up old streams (older than 1 day)
- const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
- for (const oldStream of userStreams.streams) {
- const timestamp = Number(oldStream.metadata?.timestamp);
- if (timestamp && timestamp < oneDayAgo) {
- await context.stream.delete(oldStream.id);
- context.logger.info(`Deleted old stream: ${oldStream.name}`);
- }
- }
-
- return response.json({
- streamId: stream.id,
- streamUrl: stream.url,
- totalStreams: userStreams.total
- });
-};
-
-export default handler;
-```
-
-#### Stream Interface
-
-The `Stream` interface extends `WritableStream` and provides additional properties:
-
-```typescript
-interface Stream extends WritableStream {
- /**
- * The unique identifier of the stream
- */
- id: string;
-
- /**
- * The URL to consume the stream
- */
- url: string;
-
- /**
- * Total bytes written to the stream (readonly)
- */
- bytesWritten: number;
-
- /**
- * Whether compression is enabled for this stream (readonly)
- */
- compressed: boolean;
-
- /**
- * Write data directly to the stream
- * @param chunk - Data to write (string, Uint8Array, ArrayBuffer, Buffer, or object)
- */
- write(chunk: string | Uint8Array | ArrayBuffer | Buffer | object): Promise;
-
- /**
- * Close the stream gracefully
- */
- close(): Promise;
-
- /**
- * Get a reader for consuming the stream
- */
- getReader(): ReadableStream;
-}
-```
-
-**Consuming Streams**
-
-Streams can be consumed in two ways:
-
-**1. Complete Stream Reads**
-
-Each request to the stream URL starts from the beginning and reads the entire stream:
-
-```bash
-# Read the entire stream from the beginning (can be repeated multiple times)
-curl "https://streams.agentuity.cloud/stream_abc1234567890"
-
-# Multiple consumers can read the same stream simultaneously
-curl "https://streams.agentuity.cloud/stream_abc1234567890" &
-curl "https://streams.agentuity.cloud/stream_abc1234567890" &
-```
-
-**2. Range-Based Reads (Resumable/Partial)**
-
-Use HTTP Range requests for resuming from specific positions or accessing partial content:
-
-```bash
-# Get the first 1024 bytes
-curl -H "Range: bytes=0-1023" "https://streams.agentuity.cloud/stream_abc1234567890"
-
-# Resume from byte 1024 to the end (useful for interrupted downloads)
-curl -H "Range: bytes=1024-" "https://streams.agentuity.cloud/stream_abc1234567890"
-
-# Get specific byte range
-curl -H "Range: bytes=2048-4095" "https://streams.agentuity.cloud/stream_abc1234567890"
-```
-
-**Stream Reading with getReader() Example**
-
-```typescript
-const handler: AgentHandler = async (request, response, context) => {
- const { action, streamId } = await request.data.json();
-
- if (action === 'read-direct') {
- // Create or get an existing stream
- const stream = await context.stream.create('data-source', {
- contentType: 'text/plain',
- metadata: { type: 'data-processing', sourceId: streamId }
- });
-
- // Use getReader() to get a direct reader from the stream
- const reader = stream.getReader();
- const chunks = [];
-
- try {
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- chunks.push(value);
- }
-
- // Process collected data
- const data = new TextDecoder().decode(
- new Uint8Array(chunks.reduce((acc, chunk) => [...acc, ...chunk], []))
- );
-
- return response.json({
- data,
- totalBytes: chunks.reduce((total, chunk) => total + chunk.length, 0),
- chunksReceived: chunks.length
- });
- } finally {
- reader.releaseLock();
- }
- }
-
- if (action === 'stream-reader-response') {
- // Create a stream with some data
- const sourceStream = await context.stream.create('source-data', {
- contentType: 'application/json',
- metadata: { type: 'generated-data', requestId: context.sessionId }
- });
-
- // Populate the stream with data in the background
- context.waitUntil(async () => {
- // Stream implements WritableStream, so we write directly to it
- try {
- for (let i = 1; i <= 5; i++) {
- await sourceStream.write(JSON.stringify({
- id: i,
- message: `Data chunk ${i}`,
- timestamp: new Date().toISOString()
- }) + '\n');
- await new Promise(resolve => setTimeout(resolve, 500));
- }
- } finally {
- await sourceStream.close();
- }
- });
-
- // Return the stream reader directly as the response
- // This pipes the stream content directly to the client
- return response.stream(sourceStream.getReader());
- }
-
- return response.json({ error: 'Invalid action. Use "read-direct" or "stream-reader-response"' });
-};
-```
-
-**Piping Between Streams with getReader()**
-
-```typescript
-const handler: AgentHandler = async (request, response, context) => {
- const { sourceData } = await request.data.json();
-
- // Create a source stream with input data
- const sourceStream = await context.stream.create('input-stream', {
- contentType: 'text/plain',
- metadata: { type: 'input-processing' }
- });
-
- // Create a processing stream for transformed output
- const processedStream = await context.stream.create('processed-output', {
- contentType: 'text/plain',
- metadata: { type: 'processed-data', transformation: 'uppercase' }
- });
-
- context.waitUntil(async () => {
- // Write source data to the input stream
- try {
- await sourceStream.write(sourceData);
- } finally {
- await sourceStream.close();
- }
-
- // Read from source stream and write processed data to output stream
- const reader = sourceStream.getReader();
- // Note: processedStream is written to directly, no writer needed
-
- try {
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- // Transform the data (convert to uppercase)
- const text = new TextDecoder().decode(value);
- const processedText = text.toUpperCase();
- const processedBuffer = new TextEncoder().encode(processedText);
-
- await processedStream.write(processedBuffer);
- }
- } finally {
- reader.releaseLock();
- await processedStream.close();
- }
- });
-
- // Return the processed stream reader as the response
- return response.stream(processedStream.getReader());
-};
-```
-
-**Stream as Return Value**
-
-Agent handlers can return a `Stream` object directly, which will cause the router to issue a 302 redirect to the stream's URL:
-
-```typescript
-const handler: AgentHandler = async (request, response, context) => {
- const { prompt } = await request.data.json();
-
- const stream = await context.stream.create('direct-stream', {
- contentType: 'text/plain',
- metadata: {
- type: 'direct-response',
- timestamp: new Date().toISOString()
- }
- });
-
- context.waitUntil(async () => {
- const { textStream } = streamText({
- model: openai('gpt-4o'),
- prompt
- });
- await textStream.pipeTo(stream);
- });
-
- // Return the stream directly - client will be redirected to stream URL
- return stream;
-};
-```
-
-## Agent Communication
-
-The Agentuity SDK allows agents to communicate with each other through the `context.getAgent()` method and agent redirection.
-
-#### getAgent
-
-`getAgent(params: GetAgentRequestParams): Promise`
-
-Retrieves a handle to a remote agent that can be invoked.
-
-**Parameters**
-
-- `params`: Parameters to identify the agent, either by ID or by name and project ID
-
-**Return Value**
-
-Returns a Promise that resolves to a `RemoteAgent` object that can be used to invoke the agent.
-
-**Example**
-
-```typescript
-// Get an agent by ID
-const agent = await context.getAgent({ id: 'agent-123' });
-
-// Get an agent by name
-const agent2 = await context.getAgent({
- name: 'data-processing-agent',
- projectId: 'project-456'
-});
-
-// Invoke the agent
-const result = await agent.run({ data: 'process this' }, 'application/json');
-```
-
-### Agent Handoff
-
-The `response.handoff()` method allows an agent to handoff the request to another agent.
-
-#### handoff
-
-`handoff(agent: GetAgentRequestParams, payload?: Json | ArrayBuffer | string, contentType?: string, metadata?: Record): AgentRedirectResponse`
-
-Redirects the current request to another agent.
-
-**Parameters**
-
-- `agent`: Parameters to identify the target agent
-- `payload` (optional): The payload to send to the target agent
-- `contentType` (optional): The content type of the payload
-- `metadata` (optional): Additional metadata to include with the request
-
-**Return Value**
-
-Returns an `AgentRedirectResponse` object.
-
-**Examples**
-
-```typescript
-// By ID
-return response.handoff({
- id: 'agent_9e478ebc1b6b58f921725e2f6f0025ab',
-});
-
-// By Name
-return response.handoff({
- name: 'my agent',
-});
-
-// By Name Scoped to a Project
-return response.handoff({
- name: 'my agent',
- projectId: 'proj_fc9a68c544c486cebf982c9843b9032b',
-});
-
-// With payload and metadata
-return response.handoff(
- { name: 'data-processing-agent' },
- { data: 'process this' },
- 'application/json',
- { source: 'web-agent' }
-);
-```
-
-## Response Types
-
-The Agentuity SDK provides various methods for creating different types of responses through the `response` object.
-
-### Stream Method
-
-The `stream` method allows you to stream responses back to the client, supporting both `ReadableStream` and `AsyncIterable` inputs with optional transformer functions for filtering and transforming stream data.
-
-#### Method Signature
-
-```typescript
-stream(
- stream: ReadableStream | AsyncIterable,
- contentType?: string,
- metadata?: M,
- transformer?:
- | ((item: T) => U | null | undefined)
- | ((item: T) => Generator)
-): Promise
-```
-
-#### Parameters
-
-- `stream`: The stream to return - can be a `ReadableStream` or `AsyncIterable`
-- `contentType` (optional): The content type of the stream. If not provided, the SDK will auto-detect based on the stream content
-- `metadata` (optional): Metadata to return as headers
-- `transformer` (optional): Function or generator to transform/filter each stream item
- - **Function transformer**: `(item: T) => U | null | undefined` - returns single value or skips with null/undefined
- - **Generator transformer**: `(item: T) => Generator` - yields transformed values
-
-#### Auto-Conversion Features
-
-The stream method automatically detects object streams and converts them to JSON newline format with the appropriate `application/json` content type. This makes it seamless to work with structured data from AI SDKs.
-
-#### Basic Usage
-
-```typescript
-import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
-
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- // Stream from another source
- const dataStream = getDataStream();
-
- return resp.stream(dataStream);
-}
-```
-
-#### Vercel AI SDK Integration
-
-The stream method works seamlessly with Vercel AI SDK's `streamObject` for structured streaming:
-
-```typescript
-import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
-import { openai } from '@ai-sdk/openai';
-import { streamObject } from 'ai';
-import { z } from 'zod';
-
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const { elementStream } = streamObject({
- model: openai('gpt-4o'),
- output: 'array',
- schema: z.object({
- name: z.string(),
- class: z
- .string()
- .describe('Character class, e.g. warrior, mage, or thief.'),
- description: z.string(),
- }),
- prompt: 'Generate 3 hero descriptions for a fantasy role playing game.',
- });
-
- return resp.stream(elementStream);
-}
-```
-
-#### Function Transformers
-
-Use function transformers to filter and transform stream items:
-
-```typescript
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const dataStream = getUserStream();
-
- // Transform and filter items
- const transformer = (user: any) => {
- // Filter out inactive users (return null to skip)
- if (!user.active) return null;
-
- // Transform the user object
- return {
- id: user.id,
- name: user.name.toUpperCase(),
- timestamp: Date.now()
- };
- };
-
- return resp.stream(dataStream, undefined, {}, transformer);
-}
-```
-
-#### Generator Transformers
-
-Use generator transformers for more complex transformations:
-
-```typescript
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const batchStream = getBatchStream();
-
- // Generator that can yield multiple items or filter
- function* transformer(batch: any) {
- if (batch.type === 'user_batch') {
- // Yield multiple items from a batch
- for (const user of batch.users) {
- if (user.active) {
- yield { ...user, processed: true };
- }
- }
- } else if (batch.valid) {
- // Yield single transformed item
- yield { ...batch, enhanced: true };
- }
- // Return nothing to filter out invalid batches
- }
-
- return resp.stream(batchStream, undefined, {}, transformer);
-}
-```
-
-#### Error Handling
-
-Transformer errors are propagated when the stream is consumed:
-
-```typescript
-export default async function Agent(
- req: AgentRequest,
- resp: AgentResponse,
- ctx: AgentContext,
-) {
- const dataStream = getDataStream();
-
- const transformer = (item: any) => {
- // Validate item before transformation
- if (!item || typeof item !== 'object') {
- throw new Error(`Invalid item: ${JSON.stringify(item)}`);
- }
-
- return { ...item, validated: true };
- };
-
- return resp.stream(dataStream, undefined, {}, transformer);
-}
-```
-
-#### Backward Compatibility
-
-The transformer parameter is optional, so all existing stream usage continues to work unchanged:
-
-```typescript
-// This continues to work exactly as before
-return resp.stream(textStream);
-return resp.stream(dataStream, 'application/json');
-return resp.stream(binaryStream, 'application/octet-stream', { version: '1.0' });
-```
-
-### JSON Responses
-
-`json(data: Json, metadata?: Record): AgentResponseType`
-
-Creates a JSON response.
-
-**Parameters**
-
-- `data`: The JSON data to include in the response
-- `metadata` (optional): Additional metadata to include with the response
-
-**Return Value**
-
-Returns an `AgentResponseType` object with the JSON data.
-
-**Example**
-
-```typescript
-return response.json({
- message: 'Success',
- data: { id: 123, name: 'Example' }
-});
-```
-
-### Text Responses
-
-`text(data: string, metadata?: Record): AgentResponseType`
-
-Creates a text response.
-
-**Parameters**
-
-- `data`: The text to include in the response
-- `metadata` (optional): Additional metadata to include with the response
-
-**Return Value**
-
-Returns an `AgentResponseType` object with the text data.
-
-**Example**
-
-```typescript
-return response.text('Hello, world!');
-```
-
-### Binary Responses
-
-`binary(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-
-Creates a binary response.
-
-**Parameters**
-
-- `data`: The binary data to include in the response
-- `metadata` (optional): Additional metadata to include with the response
-
-**Return Value**
-
-Returns an `AgentResponseType` object with the binary data.
-
-**Example**
-
-```typescript
-const binaryData = new Uint8Array([1, 2, 3, 4]).buffer;
-return response.binary(binaryData, { filename: 'data.bin' });
-```
-
-### Media Type Responses
-
-The SDK provides specialized methods for various media types:
-
-- `pdf(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `png(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `jpeg(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `gif(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `webp(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `mp3(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `mp4(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `m4a(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `m4p(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `webm(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `wav(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `ogg(data: ArrayBuffer, metadata?: Record): AgentResponseType`
-- `data(data: Json | ArrayBuffer | string, contentType: string, metadata?: Record): AgentResponseType`
-- `markdown(content: string, metadata?: Record): AgentResponseType`
-
-Each method works similarly to the `binary()` method but sets the appropriate content type. The `data` method allows setting specific data with an exact content type, while the `markdown` method provides a convenient way to return markdown content.
-
-**Example**
-
-```typescript
-// Return a PNG image
-return response.png(imageData, { filename: 'chart.png' });
-
-// Return an MP3 audio file
-return response.mp3(audioData, { duration: 120 });
-```
-
-### HTML Responses
-
-`html(data: string, metadata?: Record): AgentResponseType`
-
-Creates an HTML response.
-
-**Parameters**
-
-- `data`: The HTML content to include in the response
-- `metadata` (optional): Additional metadata to include with the response
-
-**Return Value**
-
-Returns an `AgentResponseType` object with the HTML content.
-
-**Example**
-
-```typescript
-return response.html('Hello, world! This is an HTML response.
');
-```
-
-### Empty Responses
-
-`empty(metadata?: Record): AgentResponseType`
-
-Creates an empty response.
-
-**Parameters**
-
-- `metadata` (optional): Additional metadata to include with the response
-
-**Return Value**
-
-Returns an `AgentResponseType` object with no payload.
-
-**Example**
-
-```typescript
-return response.empty();
-```
-
-## Request Handling
-
-The Agentuity SDK provides various methods for accessing request data through the `request` object.
-
-### Accessing Request Data
-
-#### get trigger
-
-`get trigger(): string`
-
-Gets the trigger type of the request.
-
-**Return Value**
-
-Returns a string representing the trigger type (webhook, cron, manual, agent, etc.).
-
-**Example**
-
-```typescript
-const triggerType = request.trigger;
-console.log(`Request triggered by: ${triggerType}`);
-```
-
-#### get
-
-`get(key: string, defaultValue?: Json): Json`
-
-Gets a value from the request. The available properties depend on the trigger type.
-
-**Parameters**
-
-- `key`: The key to retrieve
-- `defaultValue` (optional): A default value to return if the key does not exist
-
-**Return Value**
-
-Returns the value for the specified key, or the default value if the key does not exist.
-
-**Trigger-specific Properties**
-
-Different trigger types provide different properties:
-
-- **Webhook**: Includes a `headers` property containing the HTTP headers from the webhook request.
-
-**Example**
-
-```typescript
-// For webhook triggers, access headers
-const headers = request.get('headers');
-// Access a specific header
-const githubSignature = headers['x-hub-signature'];
-
-// Get a user ID with a default value
-const userId = request.get('userId', 'anonymous');
-```
-
-#### metadata
-
-`metadata(key: string, defaultValue?: Json): Json`
-
-**Note:** This method is deprecated. Use `get(key, defaultValue)` instead.
-
-Gets metadata associated with the request.
-
-**Parameters**
-
-- `key`: The metadata key to retrieve
-- `defaultValue` (optional): A default value to return if the key does not exist
-
-**Return Value**
-
-Returns the metadata value for the specified key, or the default value if the key does not exist.
-
-#### json
-
-`json(): Promise