Local backend
Introduction
Section titled “Introduction”@pilotoo/local-server is the backend for a user’s own machine. It speaks the same REST and socket.io protocol as a shared gateway, so a chat-core client works unchanged, with no PostgreSQL, no remote identity and no shared gateway. Use it to build a desktop app. The repository’s apps/desktop is one, and any app that can run a Node 22 process can do the same (Hosting it from another app).
Starting the server
Section titled “Starting the server”One call starts it. It listens on 127.0.0.1 and hands back the address.
import { startLocalServer } from '@pilotoo/local-server';
const server = await startLocalServer({ configDir: '/path/to/app-data/config', // agents/, profiles/, providers/, skills/, templates/ dataDir: '/path/to/app-data/data', // local.db workspaceDir: '/path/to/app-data/workspace', // where the agent's shell works execution: 'local-unsandboxed', // required defaultAgentId: 'orchestrator', // recommended allowedOrigins: ['tauri://localhost'], // the page's origin(s) host: { tools: myToolRegistry }, // optional: PilotooModule options a host may set});// server.url 'http://127.0.0.1:51234'// server.token 'per-launch secret'await server.close(); // stops listening, then closes the SQLite file; safe to call twiceIt resolves to { url, token, close() }. Everything that can be refused is refused before anything is opened: a missing execution, a missing directory, a bad port, a weak token.
Connecting a client
Section titled “Connecting a client”Pass the base URL and the token to chat-core. It sends the token as Authorization: Bearer on REST and as auth.authorization in the socket handshake.
<ChatProvider baseUrl={server.url} getToken={() => server.token}>A relaunch gets a new port and a new token, so hand the address over again each launch. The desktop app does this with a {url, token} hand-off: see Hosting it from another app.
Naming a default agent
Section titled “Naming a default agent”Without defaultAgentId, a conversation starts on the agent AGENT_DEFAULT_ID names (the built-in seed agent when it is unset), if the folder has it, and otherwise on the first active agent in the folder, without any error.
Adding tools and skills
Section titled “Adding tools and skills”Server-side tools are registered in code through host.tools. The desktop sidecar registers web_search and an opt-in ask_human this way (apps/desktop/sidecar/host-tools.mjs). Tools the webview serves are client tools and need nothing here.
A skill is <skillsDir>/<name>/SKILL.md with a name and a description in its frontmatter.
More on skills: Skills.
Options
Section titled “Options”| Option | Meaning |
|---|---|
configDir, dataDir, workspaceDir |
Required, made absolute, never searched for. Nothing is derived from a repository layout, so it works from node_modules. dataDir and workspaceDir are created when missing. |
skillsDir |
Where skills are read from. Default <configDir>/skills. |
globalSkillsDir |
A read-only skills folder beside it, for a shared layer a host syncs onto the machine. It ranks after skillsDir, so a local skill wins a name both hold. The skill config tools see skillsDir only. |
configLocation |
How a client names configDir in the path of a profile, provider or agent record. Default .pilotoo; a host whose folder is the user’s own passes e.g. ~/.myapp/assistant. Never derived from configDir. |
execution |
Required, no default. The only value today is 'local-unsandboxed'. See Security. |
defaultAgentId |
The agent a conversation without one starts on (AGENT_DEFAULT_ID). |
port |
Default 0: the OS picks a free port, so several apps or instances never collide. |
token |
Default: 256 random bits per launch (base64url). A host token under 16 characters is refused. There is no option to turn the token off. |
allowedOrigins |
Required. See Security. |
printTo |
A stream. When given, one line {"url":"...","token":"..."} is written once the server listens, for a host that starts this in a child process. |
env |
The environment providers read API keys from. Default process.env; copied, never modified. DATABASE_URL and AUTH_IDENTITY_URL are always dropped. |
logger |
Nest’s logger. Default errors and warnings (Nest writes warnings to stdout). false silences it. |
host |
tools, serviceName, usageSink, modelProviders, skillSources, knowledge, attachmentStore, modelProfileSource, modelGateway of PilotooModule.forRoot, unchanged. |
Next steps
Section titled “Next steps”- Hosting it from another app for the process model and the hand-off.
- Security for tokens and origins.
- Storage and restarts for what is kept on disk.