Use Bun for an in-process agent and the HTTP SDK for Node.js or an existing service. Each runtime owns an explicit data directory. Embedding selects its components explicitly and does not inherit components from a user's installation.
Install only the host and selected components; a source checkout is unnecessary:
bun add @ericsanchezok/synergy-agent-runtime @ericsanchezok/synergy-mcp @ericsanchezok/synergy-lspimport { openAgentRuntime } from "@ericsanchezok/synergy-agent-runtime"
import { localRuntime } from "@ericsanchezok/synergy-local-runtime/component"
import { mcp } from "@ericsanchezok/synergy-mcp/component"
import { lsp } from "@ericsanchezok/synergy-lsp/component"
await using runtime = await openAgentRuntime({
home: "./.agent-data",
components: [localRuntime({ workers: false }), mcp(), lsp()],
})
const client = runtime.client({ directory: process.cwd() })home is the data directory itself. The required component list selects every capability, including Local Runtime and Plugin Host. An empty list has no default execution Environment. HTTP, Browser, Library and other optional domains require their component factories. The component graph validates versions and dependencies before opening storage. See the Agent Runtime API for session execution.
For the complete backend, install @ericsanchezok/synergy-presets and use its explicit composition. The programmatic preset does not assume a repository or bundled Web directory:
import { PresetRuntimeHandle } from "@ericsanchezok/synergy-presets"
import { createLocalHost } from "@ericsanchezok/synergy-local-runtime"
await using runtime = await PresetRuntimeHandle.open({
mode: "server",
host: createLocalHost({ home: "./.agent-data", root: "./.agent-data" }),
network: { hostname: "127.0.0.1", port: 0 },
webAppDirectory: "/srv/company-agent/web",
})Omit webAppDirectory for an API-only backend; openTask() selects one-shot execution without an HTTP listener. The shared lifecycle publishes the active component configuration schema for editors. A host may explicitly supply configSchemaPath to override it.
The SDK manages a separate Bun runtime process or attaches to an existing HTTP service. It does not run the Harness inside Node.js.
import { createSynergy } from "@ericsanchezok/synergy-sdk"
const { client, server } = await createSynergy({
mode: "managed",
executable: process.env.SYNERGY_EXECUTABLE!,
version: process.env.SYNERGY_VERSION!,
home: "./.agent-data",
components: { server: process.env.SYNERGY_VERSION! },
client: { directory: process.cwd() },
})
try {
const capabilities = await client.global.capabilities()
console.log(capabilities.data?.components)
} finally {
await server.close()
}Supply the absolute installed executable path and exact host/component versions. Components must already be installed. The managed selection enables exactly those components plus their declared requirements and the core host; unselected installed mechanisms stay inactive. args supplies executable-prefix arguments when explicitly running a source or module entry. The SDK uses a dynamic loopback port by default, gives the child a private bearer credential through its environment, and checks the versioned readiness record's process ID, version, home, endpoint and requested components. It does not parse a human startup banner. Timeout, abort and failed readiness drain only the process it created; close() is asynchronous and idempotent.
To attach to a running service:
const { client, server } = await createSynergy({
mode: "attach",
url: "http://127.0.0.1:4096",
headers: { authorization: `Bearer ${process.env.SYNERGY_TOKEN}` },
client: { scopeID: "home" },
})
await server.close() // The attached service remains running.Caller fetch implementations, headers and Scope selectors remain supported. HTTP clients for other languages can consume OpenAPI; session-owned operations must keep the same explicit directory or Scope selector as the TypeScript client.
Run a selected HTTP composition, then use the same API and explicit Scope headers from any language. This Python standard-library example attaches to an existing authenticated service and creates a Home session:
import json
import os
from urllib.request import Request, urlopen
base = os.environ["SYNERGY_URL"].rstrip("/")
headers = {
"Authorization": "Bearer " + os.environ["SYNERGY_TOKEN"],
"Content-Type": "application/json",
"x-synergy-scope-id": "home",
}
def request(route, body=None):
data = None if body is None else json.dumps(body).encode()
with urlopen(Request(base + route, data=data, headers=headers), timeout=30) as response:
return json.load(response)
print(request("/global/capabilities")["components"])
session = request("/session", {"title": "Company agent"})
print(session["id"])This client does not own the service. For a filesystem project, resolve its Scope through the API and retain that Scope selector across session operations. Use the OpenAPI contract for input submission, streaming and cancellation rather than launching an independent agent loop in the client.
GET /global/capabilities reports the active component IDs, versions and component API versions for this runtime. Use the generated client.global.capabilities() method before calling optional APIs. The endpoint requires no project Scope. Installed changes take effect at the next runtime start; the active response never claims that a newly installed component is already running. Component availability is distinct from permission approval.
Managed SDK processes require the private bearer credential on HTTP requests. Existing service deployments retain their configured transport/authentication boundary; attaching does not create or replace credentials.
The Web application discovers this selection before optional requests. Navigation, settings, composer mechanisms and workbench panels follow the active components; reconnecting replaces the previous selection. A Web client can therefore attach to a core server or a selected subset without polling absent component routes.
Environment selection and resource ownership follow Environments. Embedded hosts select localRuntime({ environment: false }) when they need native services without a default execution destination. openLocalRuntime accepts environment: false directly.