Skip to content
PricingBlog
✨ Markdown

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.

ts
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

ts
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
}
FieldDescription
agentServerUrlElectric Agents coordinator server URL.
baseUrlPublic base URL used when registering the webhook. Defaults to local URL.
portLocal webhook server port.
hostBind host. Defaults to 127.0.0.1.
workingDirectoryDirectory used by Horton and worker file tools. Defaults to process.cwd().
mockStreamFnOptional test stream function. Lets you run without ANTHROPIC_API_KEY.
webhookPathWebhook path. Defaults to /_electric/builtin-agent-handler.
createElectricToolsOptional factory for extra tools injected into built-in agent handlers.
extraMcpServersMCP servers contributed by the embedder. On name conflict with mcp.json, mcp.json wins. authorizationCode servers are auto-wired with keychainPersistence.
loadProjectMcpConfigLoad <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.
mcpOAuthRedirectBaseBase 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.
openAuthorizeUrlHook 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.
onConfigErrorInvoked 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.

ts
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

ts
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.

ts
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.

ts
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:

VariableDescription
ELECTRIC_AGENTS_SERVER_URLRequired coordinator server URL.
ELECTRIC_AGENTS_BUILTIN_BASE_URLPublic webhook base URL for the built-in server.
ELECTRIC_AGENTS_BUILTIN_HOSTBind host.
ELECTRIC_AGENTS_BUILTIN_PORTBuilt-in server port. Defaults to 4448.
ELECTRIC_AGENTS_WORKING_DIRECTORYWorking directory for file tools.

Built-in Agent APIs

The built-in agent exports are also available if you want to compose your own runtime:

ExportPurpose
registerHorton()Register the horton type on an EntityRegistry.
registerWorker()Register the worker type on an EntityRegistry.
HORTON_MODELDefault 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_NAMESValid primitive tool names for workers.
createHortonDocsSupport()Create Horton's docs knowledge-base support.

For the behavior of horton and worker, see Horton and Worker.