On this page

On this page

Plugin SDK reference

Register an agent harness

The registration call itself, and the two optional capabilities a registered harness can add: one fresh tool-free inference call, and consent for a trusted delegate to execute an existing model-locked session. Part of the Agent harness plugins reference.

Register a harness

Import: openclaw/plugin-sdk/agent-harness

typescript
import type { AgentHarnessV2 } from "openclaw/plugin-sdk/agent-harness";import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; const myHarness: AgentHarnessV2 = {  id: "my-harness",  label: "My native agent harness",   supports(ctx) {    const routeSupportsHarness =      ctx.modelProvider?.runtimePolicy?.compatibleIds.includes("my-harness") === true;    const canReproduceRequest = ctx.modelProvider?.requestTransportOverrides !== "present";    return ctx.provider === "my-provider" && routeSupportsHarness && canReproduceRequest      ? { supported: true, priority: 100 }      : { supported: false, reason: "effective route is not harness-compatible" };  },   async runAttempt(params) {    // Start or resume your native thread.    // Use params.prompt, params.tools, params.images, params.onPartialReply,    // params.onAgentEvent, and the other prepared attempt fields.    return await runMyNativeTurn(params);  },}; export default definePluginEntry({  id: "my-native-agent",  name: "My Native Agent",  description: "Runs selected models through a native agent daemon.",  register(api) {    api.registerAgentHarness(myHarness);  },});

authBootstrap is intentionally absent from this generic example. Add authBootstrap: "harness" only when the harness meets the harness-owned auth bootstrap contract.

Hosted workspaces and executor lifecycle

A harness with a provider-managed workspace may declare workspaceEnvironment: { kind: "provider-hosted", label: "Provider workspace" }. The Gateway projects this metadata on configured model/runtime choices so the Control UI can distinguish hosted workspaces from local folders and cloud workers. Declare it only for the active hosted configuration, not a self-hosted executor. This presentation metadata grants no availability, authentication, placement, or file-synchronization capability; those stay with their existing owners.

api.registerAgentExecutorController has been removed. For Agents API self-hosted execution, configure an external lifecycle owner for session-scoped startup, reconnection, and cleanup; see the self-hosted execution guide. This does not automatically replace an existing controller plugin. Before upgrading, retire its controlled sessions using the previous OpenClaw version and original plugin, verify their executors stopped, then remove executorController configuration. Saved controlled bindings are retained and refused until that cleanup is complete.

The published AgentExecutorController, AgentExecutorBinding, and AgentExecutorContext types remain available for compatibility. resolveAgentExecutorController(pluginId) now reports that the capability has been removed; it cannot resolve an active executor controller.

A harness whose reset cannot settle required native work throws AgentHarnessSessionCleanupError from openclaw/plugin-sdk/agent-harness-runtime. The host waits for the other cleanup callbacks, then rejects the reset before replacing the local session. Ordinary reset-hook errors remain best effort. Reply-driven resets use the same required-cleanup check before committing their session boundary.

Isolated completion

The optional runIsolatedCompletionV2(params) capability serves product paths that require one fresh prompt-only inference call with a literal empty model-callable tool surface. Core passes provider and model ids, prompts, deadline controls, and one prepared authorization:

  • owner: "host" contains the exact transport model and resolved auth.
  • owner: "harness" contains the prepared runtime auth plan and a credential snapshot restricted to the single profile selected for that call. Core owns automatic fallback order and invokes the harness separately for each candidate.

When supplied, onRequestComplete(durationMs) reports inference dispatch through settlement, including a dispatched failure. Measure at the runtime's request boundary, not around its entire completion method: credential, model, client, and session preparation and post-request cleanup are excluded. Preparation failures must not report request timing. Core does not invent a duration when a harness does not report one.

Agents API is a documented exception to the literal empty tool surface: it creates a fresh session without an executor, supplied functions, web search, vaults, or subagents, but the service may retain built-in helpers. This restricted mode is enabled by default. Rejecting tool-bearing output does not prevent a helper from acting during inference. Callers requiring a literal zero-tool guarantee must select a runtime that provides it.

Each new isolated completion uses the configuration and agent/workspace directories of its admitted runtime generation. Explicit model, auth-profile, and runtime selections remain fixed while that generation is prepared. Registry preparation selects provider and harness owners, including their declared harness dependencies. Preparation does not add memory or context-engine plugins merely because the agent selects them, or unrelated startup plugins, and does not adopt Gateway agent capabilities.

Host-authorized calls must use the supplied model and credential without substitution. Harnesses using the shared host-prepared completion helper preserve the exact route, deadline, sampling options, and empty tool surface. Harness-authorized calls may resolve only the supplied prepared route and scoped profiles, or the harness's native account when the plan leaves auth to the harness. The harness must not switch routes, reuse a native thread, attach tools, invoke agent lifecycle hooks, or deliver output.

To report the same execution route in utility-model settings, a harness may add resolveIsolatedCompletionRuntime({ authorizationOwner }), where the owner is "host" or "harness". Return "openclaw" when that authorization owner uses the shared host-prepared completion helper, or "self" when the harness executes the call. Without this hook, the settings report the harness itself. Keep the selector synchronous and side-effect-free, and reuse it in isolated dispatch so the reported route follows execution.

When supplied, call params.assertCurrent() after preparation awaits and immediately before each credential handoff, inference request, or process start, including retries. It revalidates the caller's live authority and expires when the completion ends. A thrown assertion ends execution; do not treat it as a credential failure or retry with another profile. Continue to honor abortSignal; cleanup must remain available after authority expires.

Return { assistant: AssistantMessage }. Core accepts only terminal text/thinking content with a stop or length stop reason; tool calls, failed stops, and empty output are rejected. Title requests set outputTextPolicy: "strict-visible": keep reasoning separate without recovering ambiguous reasoning as visible text; an empty visible result is valid. The host-prepared helper maps this policy to strict parsing before recovery. Omission preserves ordinary recovery behavior. CLI-backed title calls also allow clean empty output without a silent-reply token; ordinary CLI calls still reject empty responses. Older external harnesses may ignore the policy; a final title filter cannot restore provenance that a harness already discarded, so this is not a universal reasoning-privacy guarantee. Except for the documented Agents API limitation, if the harness cannot enforce isolation, omit the capability. Callers that require isolated completion then reject the run before invoking that harness; OpenClaw does not replay the request through another runtime.

outputSchema, when present, carries an advisory JSON Schema for native final-output constraint. The host forwards the schema by reference only when its JSON encoding fits within 1 KiB; otherwise it is not forwarded natively. Callers must not mutate it after handoff. Harnesses may use the schema when their transport supports structured output. A harness may retry with a prompt-level constraint when its transport explicitly rejects the schema dialect; callers remain responsible for validating the returned value.

Plugin callers request isolated execution through api.runtime.llm.complete({ execution: { mode: "isolated-agent-runtime" } }); the harness callback is the provider-side enforcement SPI, not a second caller API.

The legacy runIsolatedCompletion(params) host-auth-only capability is deprecated and remains available for external plugins through 2026-10-12. Implement V2 for harness-owned or native authentication; OpenClaw never invents a host credential when only the legacy capability is present.

Native agent servers often have ambient built-in tools even when OpenClaw sends an empty tool list. Disable and attest those native capabilities for the fresh turn, use a separate transport that can serialize a true zero-tool request, or leave the capability unsupported. Agents API retains the documented exception above until its service can enforce that boundary.

Audit evidence follows the same boundary. OpenClaw can record registered plugin ownership and run admission, but it cannot claim an external native side effect from an ACP update or transcript. A side effect wholly inside that runtime is unsupported unless an adapter invokes an OpenClaw-owned callback before the action. Do not reconstruct the callback from native tool status events.

Delegated execution

A harness owner may set delegatedExecutionPluginIds to the ids of trusted plugins that need to execute an existing model-locked session, such as a voice transport continuing a Codex-backed conversation. This is static owner consent, not a core allowlist. Keep it narrow.

Delegates receive only work admission and embedded execution. OpenClaw requires the exact stored session key, store path, and session id; modelSelectionLocked: true; and matching agentHarnessId and agentHarnessRuntimeOverride values. The run is then scoped through the harness owner. Session creation, patching, reset, deletion, archive, and Gateway mutation remain owner-only.

Was this useful?