7. The orchestrator
The orchestrator is a Deno/TypeScript service that sits above the kernel and handles three responsibilities the kernel cannot embed directly:
- IO component dispatch — invoke external systems (LLM APIs, HTTP services) on the kernel’s behalf when a program executes.
- LLM adapter — talk to the actual model provider (Anthropic via Vercel AI SDK).
- MCP server — expose Eigenius operations as Model Context Protocol tools so external LLM agents can query the knowledge graph and run programs.
The full architectural rationale is in D6 — Execution architecture. This chapter is the operational view.
7.1. When you need it
| Operation | Orchestrator required? |
|---|---|
eigenius load, validate, compile, inspect | No |
eigenius query against in-process or remote kernel | No (queries are read-only) |
eigenius program-validate | No (static checks run in-process) |
eigenius run against a program with no IO components | No |
eigenius run against a program that calls CompleteText, CompleteJson, or any IO component | Yes |
Serving the notebook SPA (EIGENIUS_NOTEBOOK_STATIC) | Yes (the orchestrator serves it under /notebooks) |
| MCP-driven workflows (LLM agent calling Eigenius operations) | Yes |
If your workload is purely structural — load, query, type-check — you can skip the orchestrator entirely. As soon as a program dispatches an IO component, the kernel needs the orchestrator endpoint.
7.2. Starting the orchestrator
The orchestrator is a Deno program in orchestration/. Three ways to start it:
Direct (real LLM):
cd orchestrationANTHROPIC_API_KEY=sk-ant-... deno run --allow-net --allow-env --allow-sys=hostname src/main.tsDirect (mock LLM):
EIGENIUS_MOCK_LLM=true deno run --allow-net --allow-env --allow-sys=hostname src/main.tsVia just:
just orchestrator # real LLMjust orchestrator-mock # mock LLMVia Docker Compose: docker compose up brings both services up; see chapter 5.
7.3. Configuration via environment variables
Read at startup; no config file:
| Variable | Default | Effect |
|---|---|---|
EIGENIUS_KERNEL_ENDPOINT | http://localhost:50051 | gRPC endpoint for the kernel (the orchestrator calls back into the kernel for read-access and query-access host imports) |
EIGENIUS_ORCHESTRATOR_PORT | 8080 | HTTP port the orchestrator binds to |
EIGENIUS_MOCK_LLM | false | Compared strictly against the string true; when it matches, the two LLM handlers are swapped for canned ones |
ANTHROPIC_API_KEY | none | Read by the Anthropic SDK, not by orchestrator code. There is no startup check — a missing key starts cleanly and fails at the first LLM dispatch with a provider error |
EIGENIUS_NOTEBOOK_STATIC | none | Directory of a built notebook bundle; when set, the SPA is served under /notebooks |
When the kernel starts, it expects the orchestrator’s endpoint via --orchestrator <url> or EIGENIUS_ORCHESTRATOR_ENDPOINT. The two endpoints (kernel and orchestrator) are independent and known to each other through these flags.
7.4. Built-in components
The orchestrator ships with two LLM-backed components, both registered at startup:
CompleteText
IRI: urn:eigenius:program:components:CompleteText
Plain text completion. Takes a TextInput resource (with a prompt property) plus configuration (model, temperature, max_tokens); returns the completion as a string-typed resource.
Source: orchestration/src/components/complete_text.ts.
In ESL:
program ex:summarize : ex:Document -> ex:Document { let summary : core:string = CompleteText(input); Construct ex:Document { ex:text = summary }}The bare name CompleteText resolves to the registered component IRI at compile time.
CompleteJson
IRI: urn:eigenius:program:components:CompleteJson
Structured-output completion. Takes a JsonInput resource (prompt + target class) plus configuration; the orchestrator generates JSON Schema from the target class via eigenius get-schema and constrains the LLM to produce a structured result conforming to it.
Source: orchestration/src/components/complete_json.ts. Spec: D8 — CompleteJson Component.
In ESL:
program ex:extract : ex:Document -> ex:Entities { CompleteJson(input)}7.5. Mock mode
Setting EIGENIUS_MOCK_LLM=true swaps the real handlers for mock implementations:
CompleteTextreturns a canned[MOCK COMPLETION] ...string.CompleteJsonreturns a minimal JSON object matching the target schema’s required fields with placeholder values.
Mock mode is what CI uses (no API key) and what the demo scripts default to (docker compose up defaults to mock unless an ANTHROPIC_API_KEY is exported).
The mock paths are in the same files as the real paths — createMockCompleteTextHandler in complete_text.ts, createMockCompleteJsonHandler in complete_json.ts.
7.6. The component registry
orchestration/src/components/registry.ts maintains a map from component IRI to handler function. On startup, main.ts registers the two built-in handlers. The registry is fixed at startup — there is no install-at-runtime path.
There is no /dispatch route. The request handler has four branches — /health, /mcp, the notebook static route when EIGENIUS_NOTEBOOK_STATIC is set, and the Connect service paths — and everything else returns 404. Component dispatch is the ComponentExecutor Connect service; the orchestrator registers three services in total (ComponentExecutor, NotebookService, and a passthrough of the kernel’s own EigeniusKernel surface). The kernel calls ComponentExecutor, the handler runs, and the CBOR-encoded response goes back over the same call.
7.7. The MCP server
The orchestrator exposes a curated subset of the kernel surface as Model Context Protocol tools so LLM agents (Claude Code, Claude Desktop, Cursor, IDE agents) can drive Eigenius as part of their reasoning.
Two transports are wired:
- HTTP —
http://localhost:8080/mcpon the orchestrator’s existing port, mounted alongside the notebook SPA and Connect RPC. This is the right path fordocker compose upworkflows — the agent client connects directly without a host-side subprocess. - stdio —
cd orchestration && deno task mcpruns a standalone process that talks MCP over stdin/stdout against an already-running kernel. Useful when you want a kernel on the host (e.g.,eigenius serve --port 50051) without bringing up the orchestrator container.
Source: orchestration/src/mcp/server.ts (tools), orchestration/src/mcp/http.ts (HTTP transport), orchestration/src/mcp_main.ts (stdio entry point).
7.7.1. The tool surface (14 tools)
Each tool wraps one or two kernel RPCs and surfaces the response as JSON. Categories follow the platform’s natural division:
Explore (read-only chain navigation):
eigenius_query— execute an EigenQL query; rows decoded from Eigon-CBOR to JSONeigenius_inspect— resolve a single resource by IRIeigenius_list_branches— branches with head LayerId + commit timeeigenius_list_tags— immutable tag refseigenius_list_institutions— D14 institutions with their QueryClasses + comorphisms + runtime kindeigenius_get_schema— JSON Schema for an ontology class, derived from the chaineigenius_layer_topology— graph (nodes + edges) of classes / properties / institutions per layer
Mutate (commit-shaped operations):
eigenius_load— load Eigon-JSON; supportspolicy: "reject" | "cascadeTombstone",branch,explicitTombstones(D41)eigenius_validate_program— type-check a program without executingeigenius_run_program— execute program + input (both inline as Eigon-JSON)eigenius_run_program_by_iri— execute a program already loaded in the chain
Observe (state and tasks):
eigenius_health— kernel version, layer count, resource count, D21 resume-sweep stateeigenius_list_tasks— D21 tasks (running, suspended, completed, failed)eigenius_get_task_status— detail for one task UUID
Out of scope (deliberately). Branch / tag mutation, merge submission, chain consolidation, GC, task cancellation. These are stateful multi-turn flows or destructive operations — they belong in the notebook UI or operator CLI, not in a single-turn agent invocation. Use the CLI or the notebook workspace rail for those.
7.7.2. Setup — Docker Compose path (recommended)
Bring the stack up:
EIGENIUS_MOCK_LLM=true docker compose up -d# kernel on :50051, orchestrator on :8080 (notebook + /mcp + RPC)Then register the MCP server with your client of choice. For Claude Code (CLI or VS Code extension):
claude mcp add --transport http eigenius http://localhost:8080/mcpclaude mcp list # verify it shows ✓ ConnectedFor Claude Desktop, edit claude_desktop_config.json (%APPDATA%\Claude\ on Windows, ~/Library/Application Support/Claude/ on macOS, ~/.config/Claude/ on Linux). Claude Desktop’s native HTTP transport support is uneven across builds — use the mcp-remote stdio bridge to be safe (requires Node.js on the host):
{ "mcpServers": { "eigenius": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:8080/mcp"] } }}Some builds accept { "type": "http", "url": "http://localhost:8080/mcp" } directly — try that first if you’d rather skip the bridge. If the app reports “MCP failed to connect,” fall back to the mcp-remote form above.
Restart the app. The 14 eigenius_* tools appear in the tool list (look for the hammer icon in the input area).
7.7.3. Setup — stdio path (kernel-on-host development)
When you want a kernel running on your host (faster iteration, no rebuild for kernel changes) but don’t want to bring up the orchestrator container, use stdio. Start the kernel directly:
eigenius serve --port 50051 --db /var/lib/eigenius/dbThen configure your client to launch the MCP stdio entry point on demand. Claude Desktop config:
{ "mcpServers": { "eigenius": { "command": "deno", "args": ["task", "mcp"], "cwd": "/absolute/path/to/eigenius/orchestration", "env": { "EIGENIUS_KERNEL_ENDPOINT": "http://localhost:50051" } } }}deno task mcp is defined in orchestration/deno.json and runs src/mcp_main.ts. The orchestrator container does not need to be running for this path.
7.7.4. The agent guide
docs/method/eigenius.md teaches a coding agent how to use the platform correctly: the mental model, the three surface languages, the MCP tool selection table, minimal Eigon-JSON / ESL / EigenQL shapes, common workflows, and the pitfalls that trip agents up (mandatory is_a, synthesized IRI row keys in query results, persistent-backend requirements, D41 multi-layer outcomes, …).
It is a reference document, not an auto-loaded agent skill — point the agent at the path, or paste the section you need. Two companions sit beside it: reasoning.md, the method for capturing reasoning as a typed chain of graded, witnessed propositions, and grounding.md, the retrieval-and-citation method its anchoring step uses.
7.7.5. Smoke-test with the MCP Inspector
Before wiring into a client, confirm the server works against the MCP Inspector:
npx @modelcontextprotocol/inspector --url http://localhost:8080/mcpOpens a local web UI where you can list tools and invoke them interactively. If eigenius_health returns { healthy: true, version: "...", ... }, the orchestrator → kernel path is good.
7.7.6. Debugging
If a client says “MCP server failed to connect,” walk the chain bottom-up:
- Kernel reachable? —
curl http://localhost:50051/(gRPC will reject the bare GET but the connection should establish; “connection refused” means the kernel isn’t running). - Orchestrator reachable? —
curl http://localhost:8080/healthshould return{"healthy":true,...}. - MCP endpoint live? —
curl -X POST http://localhost:8080/mcp -H "Accept: application/json, text/event-stream" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'should return a JSON-RPC response withserverInfo.name === "eigenius". - Client wiring —
claude mcp list(Claude Code) or check~/Library/Logs/Claude/mcp.log/%APPDATA%\Claude\Logs\mcp.log(Claude Desktop) for handshake errors.
The orchestrator logs each MCP request to stderr; pipe it through jq when running against a real client to see what the agent is calling.
7.7.7. Architecture and scope notes
- Mode: stateless + JSON-response.
WebStandardStreamableHTTPServerTransportfrom the SDK withsessionIdGenerator: undefinedandenableJsonResponse: true. Each POST is one tool invocation, one JSON-RPC response. No SSE streaming, no session bookkeeping. - Per-request lifecycle: the SDK requires a fresh
McpServer+Transportpair per request in stateless mode; the orchestrator’s HTTP handler builds them on demand and tears them down when the response resolves. The underlyingKernelClient(Connect RPC over gRPC-Web) is long-lived. - CORS: not configured. Native MCP clients don’t need it; if you want a browser-based agent to call MCP from a different origin, add CORS headers to the
/mcpbranch inorchestration/src/server/mod.ts. - Authentication: none. The current model assumes the orchestrator port is reachable only to trusted callers (local docker stack, dev environment). Production deployment should front the orchestrator with a proxy that enforces auth before forwarding to
/mcp.
7.8. WASM IO components (removed)
WASM extensibility was removed on 2026-07-08. There is no orchestration/src/wasm/ directory, no WASM addon, no capability install, and wasmtime is not a dependency of the workspace. The examples/wasm-* directories were emptied in the same change.
The live extension paths are the built-in TypeScript components (§7.10) and the runtime substrate, whose native addon the orchestrator loads to spawn sibling worker containers (chapter 11). Chapter 9 is retained as a historical record of the removed path.
7.9. Observability
The orchestrator logs each component dispatch to stdout:
[Orchestrator] Dispatching urn:eigenius:program:components:CompleteText input.bytes = 142 argument.bytes = 56 duration_ms = 1240Plus per-LLM-call metrics from the underlying Vercel AI SDK (token counts, model used). Pipe stdout to a file or your log aggregation tool to capture the full record.
The kernel records its own trace of each component dispatch for incremental re-evaluation; that trace lives in the kernel’s trace store, not in the orchestrator. See D6b — Reasoning trace schema.
7.10. Adding a TypeScript-side component
For non-WASM components implemented in TypeScript:
- Write a handler in
orchestration/src/components/<name>.tsmatching theComponentHandlershape fromregistry.ts. - Register it in
main.tsalongside the built-ins. - Declare the component in your ontology (a
Componentresource withinput_type,output_type, and the chosen IRI). - Reference it from your ESL programs by short name or by IRI.
This path is suitable for components that are best written in TypeScript (e.g., wrapping a TypeScript-only library). For anything that needs a full language ecosystem, or that should run in an isolated container, use the runtime substrate instead (chapter 11).
7.11. Stopping the orchestrator
Plain Ctrl-C for the foreground process, or docker compose down for the containerized setup. There is no persistent state on the orchestrator side — it is stateless between restarts. All persistent state lives in the kernel.
Next: 8. Worked demos →