Zero-to-One Multi-Agent AI System in TypeScript
This guide gives you a concrete, working architecture for a zero-to-one multi-agent AI system in TypeScript — covering agent orchestration, tool registration, memory persistence with Supabase, and a streaming Next.js frontend, so you ship something real instead of another demo.
What 'Multi-Agent' Actually Means in Practice
A multi-agent system is not just multiple API calls. It is a set of specialized agents — each with a defined role, tool access, and context window — coordinated by an orchestrator that routes tasks, aggregates results, and decides when the job is done.
For indie builders, the practical split is: one Orchestrator agent that breaks down the user goal, two or three Worker agents that execute discrete subtasks (web search, code execution, data retrieval), and a Critic agent that validates outputs before they surface to the user. This pattern keeps each agent's prompt focused and its failure surface small.
Defining Agent Roles and Tool Schemas in TypeScript
Start by defining each agent as a typed object with a system prompt, an allowed tool list, and a max-token budget. TypeScript interfaces enforce this contract across your codebase and make it trivial to add agents later without breaking existing ones.
Tools follow Claude's tool-use schema: a name, a description the model reads at inference time, and a Zod-validated input schema. Keeping tool definitions co-located with their implementation functions prevents the common bug where the schema drifts from the actual handler.
// agent.types.ts
import { z } from 'zod';
export interface AgentTool<T extends z.ZodTypeAny> {
name: string;
description: string;
inputSchema: T;
handler: (input: z.infer<T>) => Promise<string>;
}
export interface AgentConfig {
id: string;
systemPrompt: string;
tools: AgentTool<z.ZodTypeAny>[];
maxTokens: number;
}
// Example worker agent
const searchAgent: AgentConfig = {
id: 'search-worker',
systemPrompt: 'You retrieve and summarize web content. Return only facts.',
tools: [webSearchTool],
maxTokens: 1024,
};Orchestrator Loop and Claude API Integration
The orchestrator runs a loop: it calls Claude with the current task and tool list, checks whether Claude returned a tool_use block or a final text response, executes the tool if needed, appends the result to the message history, and loops until Claude returns a stop reason of 'end_turn'.
One critical detail: pass the full message history on every turn, not just the last message. Claude's tool-use reliability drops sharply when it loses context about what it already tried. Cap history at a rolling window of the last 20 messages to stay within token limits.
Persisting Agent Memory with Supabase
Short-term memory lives in the in-process message array. Long-term memory — summaries, user preferences, completed task records — lives in Supabase. A simple agent_runs table with a JSONB messages column and pgvector embeddings for semantic recall covers most indie-scale use cases.
Use Supabase Row Level Security from day one. Each agent run is scoped to a user_id, so you never accidentally leak one user's agent history to another. Adding RLS after the fact on a populated table is painful.
-- supabase/migrations/001_agent_runs.sql
create table agent_runs (
id uuid primary key default gen_random_uuid(),
user_id uuid references auth.users not null,
goal text not null,
messages jsonb not null default '[]',
embedding vector(1536),
status text check (status in ('running','complete','failed')),
created_at timestamptz default now()
);
alter table agent_runs enable row level security;
create policy "Users see own runs"
on agent_runs for all
using (auth.uid() = user_id);Streaming Agent Output in a Next.js App Router Route
Wrap your orchestrator loop in a Next.js Route Handler that returns a ReadableStream. On the client, consume it with the Vercel AI SDK's useCompletion hook or a plain EventSource — both work. Stream each agent's intermediate reasoning steps, not just the final answer, so users see progress and trust the system.
Avoid the common mistake of awaiting the entire orchestrator run before responding. On long tasks, Vercel's 60-second function timeout will kill you. Stream early, flush often, and store the final result to Supabase so the client can poll for completion if the stream drops.
Open-Source Implementation: Pantheon
Pantheon is an open-source multi-agent starter kit built on exactly this stack — TypeScript, Claude, Next.js App Router, and Supabase. It ships with a working orchestrator loop, typed tool registration, Supabase migrations, and a streaming chat UI. You can clone it and have a running agent system in under an hour.
Find the repo, setup guide, and architecture notes at github.com/lewisallena17/pantheon. Issues and PRs are open — it is built for indie developers who want a real foundation, not a toy example.
Open-source implementation
Everything in this article runs in pantheon — a production-ready Next.js + Supabase + Claude starter. Clone it, deploy to Vercel, run PM2. The dashboard auto-commits every agent edit and reverts itself if TypeScript breaks.
◈ Tools mentioned
- Supabase — open-source Firebase alt
- Vercel — zero-config Next.js hosting
- Claude — AI assistant by Anthropic
- Gumroad — sell digital products
Some links may pay us a referral if you sign up. Never affects the price you pay.
Get the full starter kit
Clone the Pantheon starter kit at github.com/lewisallena17/pantheon, follow the README to wire up your Claude API key and Supabase project, and ship your first zero-to-one multi-agent AI system in TypeScript this week — not this quarter.