Quickstart
Introduction
Section titled “Introduction”This page builds the smallest useful setup: a NestJS server that serves one agent with one tool, and a React page that chats with it. The demo apps in the repository do the same with more around it.
You need the repository built as described in Installation, a PostgreSQL database and an API key for one model provider. To run on one machine with no PostgreSQL, use the Local backend instead.
For a throwaway database, one container is enough. The server creates its tables on first boot.
docker run -d --name pilotoo-db -e POSTGRES_PASSWORD=pass -e POSTGRES_DB=pilotoo -p 5432:5432 postgres:16-
Add the server packages
Depend on
@pilotoo/server, plus@langchain/coreandzodfor the tool in step 3. The NestJS packages are peers, so your app supplies them:@nestjs/common,@nestjs/core,@nestjs/platform-express,@nestjs/platform-socket.io,@nestjs/websockets,reflect-metadataandrxjs. This page also uses@nestjs/configto load a.envfile. -
Create the configuration folder
Agents, model profiles and providers are YAML files in a
.pilotoo/folder. Copy the repository’s, or write these three files. The folder is described in Directory structure..pilotoo/providers/deepseek.yaml kind: deepseekapiKeyEnv: DEEPSEEK_API_KEY.pilotoo/profiles/default.yaml name: Defaultmodel: deepseek:deepseek-v4-flashparams:temperature: 0.pilotoo/agents/assistant.yaml id: assistantname: Assistantdescription: A general-purpose assistant.status: activeruntime:systemPrompt: You are a concise, helpful assistant.profileId: defaulttools: [get_weather]builtinTools: []skills: []knowledge: []presentation: {} -
Assemble the module
PilotooModule.forRootwires the REST routes, the streaming gateway, persistence, the identity guard and every port. You supply the tools.src/app.module.ts import { Module } from '@nestjs/common';import { ConfigModule } from '@nestjs/config';import { tool } from '@langchain/core/tools';import { PilotooModule } from '@pilotoo/server';import { z } from 'zod';@Module({imports: [ConfigModule.forRoot({ isGlobal: true }),PilotooModule.forRoot({env: process.env,tools: (registry) => {registry.register(tool(async ({ city }) => `It is sunny in ${city}.`, {name: 'get_weather',description: 'Reads the weather of a city.',schema: z.object({ city: z.string() }),}),);},}),],})export class AppModule {}A registered tool is only available to agents that list its name in
runtime.tools, which is whyassistantlistsget_weather.src/main.ts import 'reflect-metadata';import { NestFactory } from '@nestjs/core';import type { NestExpressApplication } from '@nestjs/platform-express';import { configureBodyLimit } from '@pilotoo/server';import { AppModule } from './app.module';const app = await NestFactory.create<NestExpressApplication>(AppModule);configureBodyLimit(app);app.enableCors({ origin: true, credentials: false });await app.listen(4317); -
Set the environment and start
.env DATABASE_URL=postgres://postgres:pass@localhost:5432/pilotooPILOTOO_CONFIG_DIR=/absolute/path/to/.pilotooAGENT_DEFAULT_ID=assistantDEEPSEEK_API_KEY=...Start the server, then check it:
GET /healthanswers, andGET /protocolreturns the protocol version the gateway serves. -
Connect a client
@pilotoo/ui/chatgives you a ready chat.ChatProvideropens the connection andChatPanelrenders the thread and the composer.src/App.tsx import { ChatPanel, ChatProvider } from '@pilotoo/ui/chat';export function App() {return (<ChatProvider baseUrl="http://localhost:4317"><ChatPanel /></ChatProvider>);}src/App.tsx import { ChatSessionProvider } from '@pilotoo/chat-core';import { createSocketIoTransport } from '@pilotoo/chat-core/socket-io';const transport = createSocketIoTransport('http://localhost:4317');export function App() {return <ChatSessionProvider transport={transport}>{/* your own UI */}</ChatSessionProvider>;}If your server requires a token, pass
getTokentoChatProvider: a function that returns the bearer token, called for every request and socket connection.
Next steps
Section titled “Next steps”- Tools: register tools that call your own API.
- Agents: define more agents and choose models.
- Authentication: tell the kit who the caller is.
- The life of a run: what happens when you press send.