OpenWorker Service

One agent API.
Three deployment choices.

Choose where the harness runs and where its tools execute.

Architecture review · 27 October 2026. Local SDK calls below exist today; Harness.connect(), RuntimeProfiles and service management are the proposed contract. No implementation change is implied.

1. Local managed harness process

Your backend owns a Rust child process. The browser talks to your application; the harness has no public API port.

Start with a self-contained application. For a prototype, an internal tool, or a coding lab with one container per learner, the application can run its own harness and tools together. You get a working agent without operating a separate agent service. This fits when the application and its agent workload can be deployed and scaled as one unit.

One application host / dedicated development containerApplication backendTypeScript SDKOwns the child processHarness processAgent loop · policy · sessionsLocal ToolRunnerFile / shell operationsWorkspace filesprivate stdioevents / resultstool requesttool resultSession storageOutside the tool workspaceModel endpointCloud or local providermodel API
Commands / controlResults / event data
  1. StartThe SDK launches the harness and connects over private stdio.
  2. SubmitYour backend creates an agent/session and sends a message.
  3. ExecuteThe harness calls the model and ToolRunner, recording execution state.
  4. ReturnEvents and results flow back through the SDK to your UI.
Minimal TypeScript
import { Harness } from "@openworker/harness";

const harness = await Harness.start({
  stateDir: "/state/openworker",
  sandbox: "off", // Explicit dedicated-container development profile.
  modelProviders: [primaryProvider],
});
const coder = harness.createAgent({
  name: "coder",
  instructions: "Build and test browser applications.",
  tools: ["coding.read_file", "coding.write_file", "coding.run_shell"],
  defaultModel: selectedModel,
});
const session = await coder.newSession({ workspace: "/workspace" });

const run = await session.send("Build and test a quiz app.");
for await (const event of run.events()) {
  forwardToUI(event); // Text, tools, plans and pending interactions.
}
const result = await run.result();

Linux development example: primaryProvider and selectedModel are application-supplied configuration. Model keys stay in the backend. sandbox: "off" adds no OS isolation; use a dedicated container or select a supported sandbox for the workload. The app supervises the child, and shutdown stops its execution resources.

2. Service cluster: compute and execution on one node

Your backend connects to the service. A harness worker and its OpenShell sandbox share a node, while remaining separate execution boundaries.

Scale agent capacity independently of your web application. As more users submit tasks, your web servers and agent workers may need different amounts of capacity. A service cluster lets several application backends submit work to a shared worker pool. Keeping each worker and its sandbox on the same node gives you a straightforward execution layout while you scale the pool.

Application backendAuthenticated service SDKUI / CLI use the same APIService control plane — not tied to one workerREST API + SSEAdmission and event replayPostgreSQLCommands · leases · eventsRESTSSEadmit / readdurable stateOne execution node — separate worker and sandbox boundariesHarness workerAgent loop · model callsTool policy and approvalsOpenShell sandboxToolRunner + workspacePersistent storage bindingOpenShell gatewayPrivate authenticated channeltool requestresultsWorker claims commands; persists events before API replayGateway placement is independent. Provisioning/attachment use the registered provider adapter.
Commands / controlResults / event data
  1. AdmitThe API checks caller, agent release, RuntimeProfile and idempotency key.
  2. SchedulePostgreSQL records the request. A compatible worker claims the session.
  3. AttachThe profile places the sandbox beside the worker; tools run inside it.
  4. ObserveThe worker records events. Any API replica can replay them over SSE.
Minimal TypeScript
import { Harness } from "@openworker/harness";

const service = await Harness.connect({
  url: process.env.OPENWORKER_URL,
  namespace: "my-product",
  credentials: { tokenEnv: "OPENWORKER_TOKEN" },
});
const coder = await service.agent("coder@v1"); // Already deployed + active.
const session = await coder.newSession({
  runtimeProfile: "openshell-colocated",
  idempotencyKey: "project-42-coder", // Reuse only for this creation intent.
});
await saveProjectEnvironment(session.environmentId);

const run = await session.send("Build and test a quiz app.");
for await (const event of run.events()) {
  forwardToUI(event); // Text, tools, plans and pending interactions.
}
const result = await run.result();

Proposed service API. An administrator has already deployed coder@v1, configured its model provider, and granted access to the profile. Strict same-node placement needs provider/scheduler support and verification; it must not be inferred from “same cluster” or silently relaxed.

3. Service cluster: execution on separate compute

The agent loop stays on service workers. ToolRunner and files live on a separate execution node, cluster or provider.

Give workspaces their own resources and lifetime. An app builder may keep a project workspace around between conversations, while some builds need far more CPU or memory than the agent loop. Separate execution lets you size sandbox capacity independently and retain project storage when execution stops. It also gives you a place to add specialized or external execution providers without moving your application backend.

Application backendAuthenticated service SDKUI / CLI use the same APIService control plane — not tied to one workerREST API + SSEAdmission and event replayPostgreSQLCommands · leases · eventsRESTSSEadmit / readdurable stateService worker nodeSeparate execution node / cluster / VPCHarness workerAgent loop · model callsTool policy and approvalsOpenShell sandboxToolRunner + workspacePersistent storage bindingOpenShell gatewayPrivate authenticated channeltool requestresultsWorker claims commands; persists events before API replayGateway placement is independent. Provisioning/attachment use the registered provider adapter.
Commands / controlResults / event data
  1. SelectThe application chooses an approved remote RuntimeProfile.
  2. BindThe service provisions or verifies the original execution and storage identities.
  3. ExecuteThe provider channel carries tool requests/results across the boundary.
  4. RecoverA lost result becomes an explicit unknown outcome; no blind tool replay.
Minimal TypeScript
import { Harness } from "@openworker/harness";

const service = await Harness.connect({
  url: process.env.OPENWORKER_URL,
  namespace: "my-product",
  credentials: { tokenEnv: "OPENWORKER_TOKEN" },
});
const coder = await service.agent("coder@v1"); // Already deployed + active.
const session = await coder.newSession({
  runtimeProfile: "openshell-remote",
  idempotencyKey: "project-42-coder", // Reuse only for this creation intent.
});
await saveProjectEnvironment(session.environmentId);

const run = await session.send("Build and test a quiz app.");
for await (const event of run.events()) {
  forwardToUI(event); // Text, tools, plans and pending interactions.
}
const result = await run.result();

OpenShell first. External-provider adapters require separate qualification. Model credentials stay on workers; execution receives only scoped tool credentials. A lost execution connection may leave a process running. Switching profiles does not migrate live files/processes.

One workspace, multiple agents.

The returned environment ID hides provider details. A coder and verifier can share a sandbox while keeping separate conversations and session memory.

Let a coding agent and verifier work on the same project. A coding agent can implement a change while a verifier checks the resulting revision in another worktree within the same sandbox. Other teammates can use separate directories on that machine. They share the project environment while keeping their conversations separate. This is a sharing choice within a deployment, not a fourth deployment mode; the selected provider and RuntimeProfile must support it.

const coding = await coder.newSession({
  runtimeProfile: "team-workspace", // Explicit shared profile.
  workingDirectory: "worktrees/coder",
});
const verification = await verifier.newSession({
  environmentId: coding.environmentId,
  workingDirectory: "worktrees/verifier",
});

Proposed service API. Directories/worktrees must already exist through authorized setup. The service checks access, sharing policy and compatibility on every attachment. Directory separation is not a security boundary, and agents must coordinate ports and edits.

Service identityProvider executionProvider storage
environmentId
Stable application reference
Verified sandbox/pod identity
Binding revision and generation
Workspace/volume references
Mounts, ownership and retention

Compute and storage have separate lifetimes. Replacing a pod must not silently replace its retained workspace. Cancelling one agent must not destroy another agent’s attachment.

Data and control use separate durable paths

InformationLocal processService cluster
Message / new runPrivate stdio requestAuthenticated REST → durable admission → worker
Text, tools, plans, resultsSDK event streamWorker → durable journal → API SSE → app/UI
Approval, answer, cancellationTyped SDK control requestREST → priority control path → active worker
Workspace filesConfigured local workspaceBound execution storage; not the API filesystem
ReconnectResume the saved session/referenceAny API replica + session reference and event cursor

Closing a remote SDK connection does not cancel work. A control receipt means “accepted”, not “applied”. Service-generated session/run/environment IDs identify resources; an optional caller idempotencyKey deduplicates mutations. requestId traces a single HTTP attempt.

Who authorizes the first administrator?

The trusted installer. This works on cloud infrastructure, local Kubernetes and individual machines.

1. Install privately

The operator uses existing cloud, Kubernetes or host-admin permissions.

2. Bootstrap once

A private job creates an administrator record and a random, expiring token. Only its hash enters the auth registry.

3. Deliver securely

The token goes to a restricted secret store or owner-only file. The installer retrieves it using existing authority.

4. Log in normally

The CLI presents the token over TLS. Set up normal identities, test another administrator, then revoke bootstrap.

DeploymentInstaller authorityToken destination
Cloud KubernetesCloud / Kubernetes credentialsRestricted secret manager or Kubernetes Secret
Local KubernetesKubernetes administrator credentialsRestricted Kubernetes Secret
Docker / bare metalHost administrator accessOwner-only private local file
# Proposed CLI; token was delivered privately by installation.
ows login --url https://agents.example.com   --token-file /private/bootstrap-token

No public “first caller becomes admin” endpoint. Repeating installation must not replace the administrator. Bootstrap retries reconcile the original operation; expired credentials do not reopen registration.

Terraform configures infrastructure, certificate integration and secret-store access—not a long-lived admin token in its state. Local clusters use trusted TLS certificates too; only explicit loopback development allows HTTP. Service tokens, model credentials and internal mTLS identities are separate.

Who controls cluster size?

LayerOwns
Terraform / infrastructure operatorCluster, node types, node-count bounds, IAM, storage and database
HelmInstalled service, worker pools, UI and controllers
Kubernetes autoscalersCapacity adjustments within configured bounds
ows / REST / management UIWorker capacity, admission quotas, RuntimeProfiles and configuration revisions

Customers may bring an existing cluster; Terraform is optional. A pool has one scaling authority—manual, autoscaled or GitOps—to avoid competing writes. The UI uses the same REST API, with no direct database or cluster-admin access.