Embedded built-ins
The CLI commands electric agents start-builtin and electric agents quickstart run the built-in Horton and worker runtime for you. If you need to host those built-ins inside your own process, use the exported APIs from @electric-ax/agents.
BuiltinAgentsServer
BuiltinAgentsServer starts an HTTP webhook server, registers horton and worker, and forwards Electric Agents webhook wakes to the built-in handler.
import { BuiltinAgentsServer } from "@electric-ax/agents"
const server = new BuiltinAgentsServer({
agentServerUrl: "http://localhost:4437",
port: 4448,
workingDirectory: process.cwd(),
})
await server.start()
console.log(server.url)
console.log(server.registeredBaseUrl)
// Later, during shutdown:
await server.stop()Options
import type { RuntimeRouterConfig } from "@electric-ax/agents-runtime"
type CreateElectricTools = RuntimeRouterConfig["createElectricTools"]
interface BuiltinAgentsServerOptions {
agentServerUrl: string
baseUrl?: string
port: number
host?: string
workingDirectory?: string
mockStreamFn?: StreamFn
webhookPath?: string
createElectricTools?: CreateElectricTools
// MCP integration
extraMcpServers?: ReadonlyArray<McpServerConfig>
loadProjectMcpConfig?: boolean
mcpOAuthRedirectBase?: string
openAuthorizeUrl?: (url: string, server: string) => void
onConfigError?: (error: unknown) => void
}| Field | Description |
|---|---|
agentServerUrl | Electric Agents coordinator server URL. |
baseUrl | Public base URL used when registering the webhook. Defaults to local URL. |
port | Local webhook server port. |
host | Bind host. Defaults to 127.0.0.1. |
workingDirectory | Directory used by Horton and worker file tools. Defaults to process.cwd(). |
mockStreamFn | Optional test stream function. Lets you run without ANTHROPIC_API_KEY. |
webhookPath | Webhook path. Defaults to /_electric/builtin-agent-handler. |
createElectricTools | Optional factory for extra tools injected into built-in agent handlers. |
extraMcpServers | MCP servers contributed by the embedder. On name conflict with mcp.json, mcp.json wins. authorizationCode servers are auto-wired with keychainPersistence. |
loadProjectMcpConfig | Load <workingDirectory>/mcp.json (and watch it). Off by default — stdio MCP servers can spawn local commands, so the embedder must opt in. The Electron desktop and electric-ax CLI opt in. |
mcpOAuthRedirectBase | Base for OAuth redirect URIs (full URI is <base>/oauth/callback/<server-name>). MUST be stable across restarts so DCR client info stays valid; required when listening on port: 0. The runtime never listens at this URI — the embedder intercepts the redirect. |
openAuthorizeUrl | Hook invoked when an authorizationCode MCP server first needs user consent. Receives the SDK-generated authorize URL. The desktop opens it in a sandboxed BrowserWindow; headless embedders can read the URL from the authenticating envelope of addServer and surface it themselves. |
onConfigError | Invoked when applying an MCP config (initial boot or watcher reload) fails. Errors are always logged; this hook is for surfacing them programmatically. |
Without mockStreamFn, ANTHROPIC_API_KEY must be present before the built-in handler starts.
createBuiltinAgentHandler
Use createBuiltinAgentHandler() when you already have an HTTP server and only need the request handler and runtime objects.
import {
createBuiltinAgentHandler,
registerBuiltinAgentTypes,
} from "@electric-ax/agents"
const bootstrap = await createBuiltinAgentHandler({
agentServerUrl: "http://localhost:4437",
serveEndpoint: "https://example.com/_electric/builtin-agent-handler",
workingDirectory: process.cwd(),
})
if (!bootstrap) {
throw new Error("ANTHROPIC_API_KEY is required for built-in agents")
}
await registerBuiltinAgentTypes(bootstrap)
// In your HTTP server:
await bootstrap.handler(req, res)Result
interface AgentHandlerResult {
handler(req: IncomingMessage, res: ServerResponse): Promise<void>
runtime: RuntimeHandler
registry: EntityRegistry
typeNames: string[]
skillsRegistry: SkillsRegistry | null
}Extra Electric Tools
Both BuiltinAgentsServer and createBuiltinAgentHandler() accept createElectricTools. The factory receives the same context shape as RuntimeRouterConfig.createElectricTools and can add host-specific tools to Horton.
import { Type } from "@sinclair/typebox"
const server = new BuiltinAgentsServer({
agentServerUrl: "http://localhost:4437",
port: 4448,
createElectricTools: ({ entityUrl, upsertCronSchedule }) => [
{
name: "schedule_daily_summary",
label: "Schedule daily summary",
description: "Schedule a daily summary wake for this entity.",
parameters: Type.Object({
hour: Type.Number(),
}),
execute: async (_id, params) => {
const { hour } = params as { hour: number }
await upsertCronSchedule({
id: "daily-summary",
expression: `0 ${hour} * * *`,
payload: `Run daily summary for ${entityUrl}`,
})
return { content: [{ type: "text", text: "Scheduled." }], details: {} }
},
},
],
})Entrypoint Helpers
runBuiltinAgentsEntrypoint() reads environment variables, creates a BuiltinAgentsServer, and starts it. This is what the electric-agents package binary uses.
import {
resolveBuiltinAgentsEntrypointOptions,
runBuiltinAgentsEntrypoint,
} from "@electric-ax/agents"
const options = resolveBuiltinAgentsEntrypointOptions(process.env)
const { server, url } = await runBuiltinAgentsEntrypoint()
console.log(options.agentServerUrl, url)
await server.stop()Environment variables:
| Variable | Description |
|---|---|
ELECTRIC_AGENTS_SERVER_URL | Required coordinator server URL. |
ELECTRIC_AGENTS_BUILTIN_BASE_URL | Public webhook base URL for the built-in server. |
ELECTRIC_AGENTS_BUILTIN_HOST | Bind host. |
ELECTRIC_AGENTS_BUILTIN_PORT | Built-in server port. Defaults to 4448. |
ELECTRIC_AGENTS_WORKING_DIRECTORY | Working directory for file tools. |
Built-in Agent APIs
The built-in agent exports are also available if you want to compose your own runtime:
| Export | Purpose |
|---|---|
registerHorton() | Register the horton type on an EntityRegistry. |
registerWorker() | Register the worker type on an EntityRegistry. |
HORTON_MODEL | Default model id used by Horton and worker. |
buildHortonSystemPrompt() | Build Horton's system prompt for a working directory. |
createHortonTools() | Create Horton's base shell/file/search/worker tools. |
createSpawnWorkerTool() | Create the spawn_worker tool for another agent. |
WORKER_TOOL_NAMES | Valid primitive tool names for workers. |
createHortonDocsSupport() | Create Horton's docs knowledge-base support. |
For the behavior of horton and worker, see Horton and Worker.