On this page

On this page

Plugin SDK reference

Plugin entry points

Every plugin exports a default entry object. The SDK provides a helper for each entry shape: defineToolPlugin, definePluginEntry, defineChannelPluginEntry, defineSetupPluginEntry.

All plugin APIs are experimental, including these entry helpers. Pin and test the OpenClaw host versions your plugin supports.

Gateway adapters use the existing core or gateway-runtime GatewayRequestHandlerOptions.context.githubPublicationService contract for GitHub publication. Prepare its required capabilities with prepareGitHubPublicationRequesterV2 or preparePersonalGitHubSessionActionV2 from gateway-runtime, using admitted handler options, and release them after the operation settles. The host's worker and source-fence modules remain private. Migrate wrappers and lifecycle calls using the GitHub publication method mapping, without adding imports from Gateway internals.

Where each section moved

Every section of the single-page version now lives on this page or on one of the eight child pages below. The anchors from the single-page version still resolve here.

Plugin shapes

OpenClaw classifies loaded plugins by their registration behavior:

Shape Description
plain-capability One capability type (e.g. provider-only)
hybrid-capability Multiple capability types (e.g. provider + speech)
hook-only Only hooks, no capabilities
non-capability Tools/commands/services but no capabilities

Use openclaw plugins inspect <id> to see a plugin's shape.

Managed agent-database schema extension belongs to private worker backends, not the typed public Plugin SDK. Bundled backend authors should follow the private worker schema-extension contract.

Offline worker runtime artifacts

Image-preparation tools can import openclaw/runtime-artifacts to export the canonical node runtime and worker archives from a built OpenClaw installation:

ts
import {  prepareWorkerRuntimeArtifacts,  qualifyWorkerRuntimePlugins,  resolveNodeBootstrapPlugins,  workerBundleArchiveRelativePath,} from "openclaw/runtime-artifacts"; const selection = await qualifyWorkerRuntimePlugins({ packageRoot, config });const artifacts = await prepareWorkerRuntimeArtifacts({  packageRoot,  runningBuildId,  plugins: resolveNodeBootstrapPlugins(selection),  outputDirectory,});const workerPath = workerBundleArchiveRelativePath(artifacts.workerBundle.tarballSha256);

Qualification inspects only this installation's bundled plugins, prefers their built entrypoints, and releases its inspection registry without publishing it to a Gateway. Configured external plugin paths are not loaded, and inspection cannot mutate the configuration.

The output directory must not exist, its parent must exist, and it must be outside the installed package. The result records the build, selected plugins, platform, architecture, archive paths, sizes, and SHA-256 digests. Both archive producers settle before failure cleanup removes the owned output. A successful export belongs to the caller; keep it until transfer finishes. This API always exports a preassembled dependency bundle, not an npm-install archive.

The Crabbox plugin's lazy cli-runtime-api artifact exposes createCrabboxOfflineRuntimeSetup. Pass the transferred archives' absolute local paths with their expected sizes, digests, build and manifest identity, plus workerPath as the worker archive's packageRelativePath. Execute the returned command as the intended runtime user on a matching prepared platform. It checks the local archives before installing them and returns no forwarded credentials. It does not allocate a machine, enroll a node, create a logical lease, or grant execution authority. Node and archive extraction tools must already be present.

For a retained cache, createCrabboxRuntimeCacheVerification takes the same artifact identity without local archive paths and returns a credential-free command. It rejects missing or corrupt caches without installing, pruning archives, binding runtime Node, or creating enrollment state. It checks the package/build/manifest identity, CLI version, and retained worker archive digest; it does not hash every installed runtime file or grant live execution authority.

After a successful bundle install or verification command, pass its stdout and expected identity to readCrabboxRuntimeInstallation. It accepts exactly one openclaw.runtime-installed: result line of at most 16 KiB and rejects mismatched artifacts. This stdout protocol marker is not an environment variable. parseCrabboxRuntimeInstallation validates an already decoded result against that identity. The receipt records installed or existing-verified; it is evidence of the completed check, not permission to skip future verification.

Code Mode executor runtime

Use openclaw/plugin-sdk/code-mode-executor-runtime to implement the quickjs executor choice. Code Mode has two selectable IDs: node, owned by core, and quickjs, supplied by an executor plugin. The plugin's installation ID can differ from its executor ID. Declare quickjs in contracts.codeModeExecutors and export codeModeExecutor from the plugin's top-level code-mode-executor-api artifact. The host resolves this artifact only when QuickJS is selected; ordinary plugin registration remains lightweight.

Selected bundled executors preserve core runtime availability despite global plugin disablement or a restrictive allowlist. Explicit owner denies and disabled entries still apply. External executors retain the full plugin policy.

CodeModeExecutor.execute(input, options) receives the guest source, tool declarations, namespace descriptors, resource limits, and a scoped host bridge. Return a bounded completion or failure, or a waiting result containing an executor-owned CodeModeExecutorContinuation. Its resume method transfers custody once, retainedBytes reports a diagnostic size estimate, and dispose joins cleanup and keeps failed cleanup retryable. Disposing an already consumed continuation has no effect. The selected executor stays attached to the continuation across configuration changes.

The SDK supplies the common guest controller, source preparation, result capture, bounded error text, and worker protocol types. Executors own their engine and suspended state. Core owns permissions, approvals, tool dispatch, settlement receipts, output delivery, expiry, and cancellation. Missing or disabled executors fail explicitly; the host never substitutes a less isolated executor.

The controller's __openclaw* hook protocol is experimental and changes with the controller source. Bridge settlement is host-only: before evaluating CODE_MODE_CONTROLLER_SOURCE, register an __openclawHostTakeBridgeReply callback next to __openclawHostRequest (the controller captures and removes both). To settle, stage the replies host-side and call __openclawSettleBridge() with no arguments; the controller pulls each reply from the callback until it returns undefined. Return each reply as an object with own data properties id, ok, and json, never through ordinary property assignment on a guest object. Executors that called __openclawSettleBridge(id, ok, payload) must move to this pull form.

Native MCP App adapters

An agent harness that owns MCP connections can implement acquireMcpAppRuntime alongside loadMcpToolCatalog. The acquisition receives the exact session identity, configured server names, session tool overrides, requester identity, and an assertCurrent invocation guard. Return a SessionMcpRuntimeLease over the existing connection; do not create a second client to launch an App.

For a cold session, call the optional lazy prepareSession callback. Core returns a versioned session-preparation envelope (version: 1, purpose: "mcp-app"), whose params carry required admitted host capabilities, prepared credentials, environment and session facts. Execute the existing native session/thread lifecycle inside its run callback, then borrow the resulting thread-owned connection. This is a session preparation operation, not a model attempt: it has no prompt or transcript artifact and must not submit a model turn. Warm sessions do not call the preparer. Retained callbacks must honor the source and host closure; return undefined only when no supported preparation or existing native binding is available.

The current Codex app-server mcpServer/resource/read contract does not accept _meta. Native remote MCP resource reads therefore cannot request metadata-selected representations; OpenClaw reports that limitation rather than sending unsupported wire fields. Managed MCP clients still forward resource _meta, and host-file representations remain available through the local host-file owner.

The runtime retains the native connection and thread subscription for each App view, exposes assertOwnerCurrent to revalidate its exact thread/client binding, and preserves server, tool, and connector boundaries. callTool accepts optional _meta and assertCurrent; run the guard immediately before upstream I/O after any preparation awaits. The host separately enforces session sharing, requester identity, effective tool policy, and approval policy. Metadata does not grant permission.

Harness adapters publish supported entrypoints, structured settings, and mention discovery in McpToolCatalog without adding model tools. The bundled Codex adapter reuses the core metadata and approval-hint parsers through its existing private codex-mcp-projection façade; these implementation helpers are not additional public SDK exports.

The bundled adapter’s private createHarnessMcpFormResourceContext accepts AgentHarnessMcpFormResourceParamsV1 (version: 1) and binds rich previews and uploads to the exact originating runtime, server, requester and pending question. Its tool preparer receives only the tool name, input, cancellation signal, and current-authority assertion; Gateway dispatch options and upload implementations remain private to the host. A runtime may expose canReadLocalFiles(serverName) only for a current transport that can read host-local files. The shared form adapter uses that fact to select workspace uploads; remote transports do not receive unusable host file: URIs. Native no-turn tool elicitations use the originating request scope, separately from model-turn elicitation routing.

MCP subprocess runtime

Import: mcpStdioRuntime from openclaw/plugin-sdk/agent-harness-runtime using dynamic import() when opening a connection. Its frozen object lazily loads one factory:

ts
const { mcpStdioRuntime } = await import("openclaw/plugin-sdk/agent-harness-runtime");const { createMcpStdioClient } = await mcpStdioRuntime.load();

Use createMcpStdioClient(params) for a caller-owned MCP proxy subprocess fronting a stateful driver. OpenClaw owns the subprocess and its descendants, newline framing and JSON-RPC validation, initialization, request admission, deadlines, and shutdown. The client starts connecting when the factory returns. Keep this runtime out of plugin registration and paths that do not open MCP connections.

Supply command, optional args, and an exact env. The child inherits no other environment variables. Set clientInfo (name and version), the required protocolVersion, startupTimeoutMs, maxPendingRequests, and maxFrameBytes. The server must return exactly the requested protocol version. OpenClaw retains a fixed 32 KiB stderr tail for unexpected-exit diagnostics. The decoder applies maxFrameBytes to each message, including its terminating newline, so a single stdout chunk can contain several valid messages. It rejects an oversized frame before retaining any bytes from that chunk, preserves fragmented UTF-8, skips empty lines, and requires safe integer response IDs.

The caller supplies errors.unavailable(message, cause?) and errors.protocol(message, cause?), each returning an Error. The first classifies process, lifecycle, admission, deadline, and cancellation failures. The second classifies malformed frames, non-timeout JSON-RPC errors, and handshake contract violations. Plugin-specific tool-result normalization stays with the caller.

The returned client exposes three methods:

  • isAvailable() synchronously reports whether initialization completed and the connection remains usable.
  • request(method, params, { timeoutMs, signal? }) waits for startup and returns the object result. An already-aborted signal or a full pending-request limit rejects only that call. After admission, cancellation or timeout retires the entire connection and rejects pending requests with the retained fatal error. The client suppresses SDK cancellation notifications because it terminates the process instead. A non-timeout JSON-RPC error response rejects only its matching request through errors.protocol.
  • stop() closes admission, retires pending requests, and awaits startup settlement and owned-process cleanup. It rejects through errors.unavailable with proxy cleanup could not be confirmed if cleanup is uncertain. It never stops a separately started service reached through the proxy's socket.

After successful stop(), the optional read-only cleanupResult records forced relay retirement: reason: "forced-relay-exit", signalRequested, the observed relay exit code and signal, durationMs, and escalationAfterMs. It retains signalError when signal delivery reported failure but exit was subsequently confirmed. It is absent for ordinary cleanup. Closed control/output/lineage pipes and a matching closing receipt admit escalation; pending force requests are reconsidered as closure and group-exit facts arrive. A live anchor is killed and reaped through its relay. Confirmed anchor-group absence permits direct native termination of an unresponsive relay. Actual relay exit and server-group disappearance must then be confirmed within the original hard deadline. Uncertain cleanup retains missing closure facts and timing or signal-delivery details in the error's cause chain.

Malformed frames, incompatible initialization, write failures, and unexpected process exit also retire the whole connection. The first fatal error is retained. Create a new client to reconnect. Timeout classification follows the SDK error code, so a timeout-coded server error also retires the connection.

Workspace access

Use openclaw/plugin-sdk/agent-workspace-runtime to declare, register, and acquire AgentWorkspaceAccess without loading the agent execution runtime. Declare a configured remote workspace during registration so callers cannot fall back to local files before its service starts. Register its bridge when ready and release it when the service stops. Callers keep their existing document authorization.

The bridge's optional createFileExclusive operation publishes a complete file only if its path does not exist, returning "created" or "exists". It must use an atomic exclusive-create operation, never a separate existence check followed by an ordinary write. Workspace access forwards this capability with the same service-lifetime checks as other bridge operations. Providers that omit it still support their existing reads and writes, but agents.files.set with expectedMissing: true visibly refuses creation without changing the file. Update the provider, or create the file on its host and reload it before editing.

createWorkspaceBootstrapFilePolicy({ workspaceDir, config }) lets adapters restrict this bridge to native bootstrap documents and the configured bootstrap-extra-files patterns. Check canList for directory metadata, canRead for file bytes, and canWrite for the four owner-editable documents. Directory access does not grant reads of other files. The underlying bridge still enforces filesystem containment and returns the read's resolved source.

Workspace access that has not started or has stopped throws WorkspaceAccessUnavailableError. Use isWorkspaceAccessUnavailableError(error) to recognize this condition through wrapped errors or separate SDK instances. The error code is WORKSPACE_ACCESS_UNAVAILABLE; do not match message text.

The optional memoryFiles provider keeps workspace Memory files on the host while the native index, embedding providers and original sessions stay on Gateway. It supplies discovery, file inspection, reads and change notifications. Both indexing and memory_get use it; index publication rechecks the host file. The resolved source returned with a read supplies provenance, without resolving a stale Gateway copy. Stopping the workspace binding revokes retained file access and subscriptions. The Memory file worker supports --files <workspace> for native file operations without opening a host index or receiving embedding credentials. A provider can invoke it through its existing subprocess transport. createWorkspaceMemoryFileClient maps Gateway/host paths and preserves native errors for this worker. Supply request for one JSON exchange and subscribe for the --watch-files JSON-line stream, plus the binding's abort signal. Neither callback depends on Codex; providers own transport and authorization.

memoryFiles.maintenance routes existing dreaming, promotion, corpus and forget file operations to the host. Compound writes reuse native atomic publication and conflict handling; maintenance decisions, locks and SQLite state stay on Gateway. A remote binding without maintenance support fails instead of using Gateway files. The file worker implements these operations and native change notifications. The paired-node file-transfer adapter connects these operations through the existing service-owned node channel and node file policy. Requester-scoped writeDreams and appendCorpus calls carry assertCurrent separately from the serialized request. Transports must retain that callback in node dispatch and recheck it after preparation, immediately before starting the remote write. Refusal closes the prepared channel and waits for accepted cleanup.

Task-time Skill preparation uses remote discovery. Channel-native menus use Gateway-owned Skills without waiting for the Harness; remote menu support is tracked in Enterprise #241.

The optional skillResources provider handles Skill reads separately from Agent document access. Its readInstructions reads the selected instruction file for Code Mode; readSkillFiles supplies a bundle for worker delivery. Gateway-owned bundled, plugin, Library, Workshop and user-level sources keep their Gateway paths. Workspace-owned sources use the remote provider. Gateway preserves source precedence and uses existing resource delivery for workers. Discovery assigns file ownership; a provider cannot request Gateway-local reads by returning source or path metadata. Stopping the binding revokes retained host readers.

The Skills worker also runs install and ClawHub operations. Install/remove use an authenticated adapter's duplex channel so Gateway policy and mutation checks run before the native filesystem operation. The adapter admits source roots and uploads; the worker uses its host account's permissions.

For a remote workspace, dependency installation uses installSkillDependencies. Gateway selects the recipe and runs install policy; the host runs the existing installer through the worker's installDependencies operation. Requests contain the Skill key, recipe, installation preferences and timeout. Recipe choices use the host's OS and binaries. Missing host support fails without installing on Gateway. File-inspecting Gateway policies receive a temporary tree from the existing Skill resource reader; Gateway-owned sources remain local. Resource bundle limits apply.

readWorkspaceSkillResources lazily reuses the bounded native bundle reader. File-transfer adapters can check each file's requested and verified resolved filesystem paths before returning a bundle; admitting the Skill directory alone does not admit every child.

Hosts can provide watchSkills(request, onChange, signal) to notify the existing snapshot cache when admitted Skill sources change. Keep the subscription alive until aborted, and send change after the initial scan and later edits. Send unavailable if file watching stops: preparation then refreshes on each call, without reopening the subscription. After recovery, send available only when all subscribed sources have verified watch coverage and edits made during the outage have been reconciled. This restores snapshot reuse without adding a content revision. A change alone never clears unavailable state. Hosts that only send change and unavailable retain preparation fallback after an outage. Hosts without watchSkills always use that fallback. skills.load.watch: false disables the subscription and this fallback. Gateway watches Workshop locally under the same snapshot invalidation lifecycle.

The paired-node file-transfer adapter also connects Skill discovery, resource reads, watching and dependency installation through workspace.skills. Its native worker launcher uses resolveWorkspaceWorkerArgv("memory" | "skills") from agent-workspace-runtime, then appends the operation arguments. Worker-thread callers use resolveWorkspaceWorkerUrl and resolveWorkspaceWorkerExecArgv from the same owner to keep the declared target separate from loader flags. Use the same OpenClaw version on Gateway and node.

This adapter does not implement remote Skill source install/update/remove or ClawHub lifecycle operations; those remain tracked in Enterprise #242.

Agent workspace context

Native harnesses use prepareAgentWorkspaceContext from openclaw/plugin-sdk/agent-harness-runtime to prepare bounded workspace context. The shared owner runs the existing bootstrap hooks, privacy filters, and character budgets. scope: "full" separates the agent instruction snapshot, persona, remaining project context, and tool-routed memory references. It prepares recall guidance through the active memory plugin without inventing fallback policy. scope: "instructions-only" selects the configured workspace's root AGENTS.md before budgeting and does not prepare persona or memory guidance.

Provider adapters own native project-document discovery, available memory tools, path projection, context order, instruction carriers, and session/turn lifetimes. Optional projectPath projects file paths after budgeting without changing their contents or personal-user provenance. It describes existing execution placement; it does not transfer or mount files. Root instruction selection uses source paths before projection, preserving the bounded snapshot when a sandbox remaps the workspace. The selected document is excluded from project context without granting the agent source-file access.

buildAgentWorkspaceInstructionSnapshot(contextFiles, workspaceDir) selects and renders that root instruction document from already-bounded context, including hook-free child preparation. An empty instruction string is a successful capture; preparation failures must remain distinguishable and retryable.

Agents API can consume the instruction-only snapshot at session creation. Its current client does not implement per-turn developer instructions, persona and personal-overlay refresh, turn-scoped project or memory guidance, native forks, or Gateway-to-hosted-workspace path projection. Those remain MVP integration gaps; shared preparation does not enable those operations.

Tool failure diagnostics

Agent harnesses can import readToolOperatorHint(error) from openclaw/plugin-sdk/agent-harness-runtime to read optional operator advice attached to a tool failure. Include it only in the operator log. Keep it out of model responses, tool-result callbacks, and serialized transcripts, and preserve the original error message. An unannotated or immutable error needs no substitute hint; the reader returns undefined when no advice is available.

ACP harness turns

Pass optional currentInboundContext to resolveAgentHarnessBeforePromptBuildResult from openclaw/plugin-sdk/agent-harness-runtime. It combines the prompt with its inbound context and channel-provided joiner before prompt hooks run. Frame ordinary chat with prose section labels so a leading file path cannot become a native slash command. Keep one admitted user turn while assigning each provider attempt its own request and reply identity.

The result's developerInstructions includes plugin system context. When that context is present, threadDeveloperInstructions contains the policy without the context, and turnDeveloperInstructions contains the wrapped context. Harnesses with separate persistent and per-turn instruction carriers can use these fields to refresh context without reloading their session. Hook systemPrompt replacements remain part of threadDeveloperInstructions.

Host requestApproval normalizes the title and description within the shared display bounds and preserves full action evidence in detail. Its response acknowledges the request with an ID. Call waitForApproval with that ID to obtain the decision, then recheck the turn's signal and authority before allowing the native operation.

Use the plugin approval timeout independently of the agent-run timeout. Authenticated Control UI reviewers can inspect detail, while channel messages retain the bounded description. Oversized detail is rejected by the existing request schema.

Session persistence

agent-sessions exposes awaited SessionManager mutations and versioned extension actions. session-store-runtime provides prepareSessionEntryPatch for host preparation followed by a conditional worker commit, and applySessionEntryPatch for already prepared data. session-transcript-runtime provides withSessionTranscriptWrite and duplicate-aware message preparation. Released synchronous and opaque transaction callback forms remain deprecated through 2026-12-31, with removal in the first January 2027 stable release. See session entry migration and transcript migration.

To post a notice into a session's chat without sending it to the model, call appendAssistantMirrorMessageByIdentity with text and deliveryMirror: { kind: "plugin-notice", pluginId, type, data }. Every client shows the text. data is JSON that a client can use to render a richer row for a notice type it knows. The row is never replayed to the model. For a notice from background work that must skip a reset session or also reach the session's channel, use api.runtime.system.postSessionNotice; see background session notices.

For ordinary session preparation, await getSessionEntryAsync, readSessionUpdatedAtAsync, getConversationSessionAsync, or readAmbientTranscriptWatermarkAsync from session-store-runtime. Native command preparation uses resolveStoredModelOverrideAsync and resolveCommandArgMenuAsync from command-auth-native; the menu helper is also available from native-command-registry. Their synchronous compatibility APIs remain deprecated through 2026-12-31. See session and command preparation.

For descriptive metadata, use listSessionEntriesAsync. For bounded disclosure after awaited preparation, use runtime.agent.session.withSessionEntriesAsync (also exported by session-store-runtime) with stores: [{ agentId, storePath, sessionKeys }]. It retains all selected physical sources until its synchronous callback returns. An optional involvingProfileId matches exact canonical owners or direct profile participants, including merge aliases; it never matches mentions or display prefixes. After preparing the selected stores, the shared-state worker reads a fresh canonical profile snapshot, without reusing an earlier inspection snapshot or resident catalog. Local identity changes invalidate that prepared selection. Final native reads observe the selected session rows after the last await. Profile and session reads are separate snapshots, not atomic serialization across databases. Revalidate current configuration, selected groups, exact session IDs and any other caller-owned policy inside the callback, then serialize without awaiting. Returning a Promise is rejected. Returned metadata is not retained authority.

When awaiting further preparation after readSessionTranscriptCatalogPage, its optional second argument captures an actor-currentness assertion. Call it at final serialization along with the caller's session/source checks. It does not grant access to the transcript or extend the session reader's lifetime.

Skill authoring

skill-authoring-runtime is a private official-plugin runtime for plugins that keep learned skills in the per-agent folder their manifest names in agentSkillsDir. Skill loading already reads that folder; this subpath writes it.

The host resolves the skills root from the calling plugin's own manifest. Calls take the target agent ({ config, agentId }) and a skill name, never a folder or path, so a plugin cannot name another plugin's skills. A plugin without agentSkillsDir gets SkillAuthoringError with code no_skills_root.

  • resolveSkillsRoot({ config, agentId }) returns the calling plugin's folder for one agent, for listing its skills.
  • readSkillFile({ config, agentId, skillName, filePath }) and listSkillFiles read with byte limits and refuse links.
  • normalizeSkillFilePath(path) accepts SKILL.md or a relative path below assets/, examples/, references/, scripts/, or templates/.
  • parseSkillFrontmatter parses strictly; splitSkillFrontmatter returns the frontmatter record and body and never throws.
  • validateSkillFile({ skillName, filePath, content, maxSkillBytes }) checks the support path, the SKILL.md frontmatter (name must match the folder, description must be 1 to 1,024 bytes), the size limits, and the skill security scan. It returns the description.
  • writeSkillFile and removeSkillFile validate, then change one file of one skill. A skill name that is not one plain folder name, or a skill folder that a link moves outside the root, is refused.
  • commitSkillChange({ config, agentId, skillName, apply }) runs apply, refreshes skill discovery, and dispatches one skill_changed hook with source: "plugin", the calling plugin's pluginId, and the before and after artifacts. A failed apply dispatches nothing. Serialize overlapping changes to one skill in the plugin.

These calls must run inside a plugin call (a tool, hook, command, service, or api.lifecycle.runInBackgroundContext work). They carry the calling plugin's live authority from the host and check it after each awaited step and immediately before each file change and the skill_changed dispatch. When the plugin is disabled, replaced, or unloaded, they throw PluginInstanceUnavailableError and commit nothing.

Refusals throw SkillAuthoringError. Its message says what to change, and its code (invalid_path, path_escape, too_large, invalid_frontmatter, unsafe_content, or no_skills_root) lets the plugin add its own guidance. Versioning, drafts, and naming rules stay with the plugin.

Stateful CLI commands

openclaw/plugin-sdk/cli-state-owner exports runWithLocalStateOwner. Supply the Gateway method, serializable params, a diagnostic target, and runLocal. Open databases and load mutation-capable runtime state only inside runLocal; its scope supplies the admitted config, environment, abort signal, and current owner assertion. Close plugin-owned stores before the callback returns.

Commands that use configured database families set databaseEngine: "configured". The helper resolves the selected config's engines after acquiring offline ownership, before runtime config can write state, and retains that selection through resource settlement. Commands routed to a running Gateway use its engines and do not need the PostgreSQL credentials in the CLI process.

The helper routes to the local Gateway with its expected owner ID, or retains exclusive offline ownership through resource settlement. It never replays an uncertain Gateway mutation locally. Use onForeignOwner: "refuse" for commands that require an offline Gateway. Optional scopes preserves the command's existing authorization contract; the default is operator.admin. After a multi-request operation has started on the Gateway, reject runLocal before accessing config or performing local work if a later request loses its owner.

Gateway handlers can use captureLocalStateMutationGuard from openclaw/plugin-sdk/gateway-runtime to bind the expected owner and current request authority, then pass the returned assertion to their existing writer admission and privileged-effect boundaries. isImplicitLocalGatewayTargetFromCli from that same entrypoint preserves explicit and configured remote CLI targets. runWithLocalStateMutationOwner adds the existing channel authority scope for plugin transport effects and disclosure; pass its assertion into the plugin's database writer and file publication boundaries too. Versioned owner-bound RPC names let CLI callers require updated plugin handlers without assuming that an updated Gateway also upgraded an independently installed plugin.

OpenAI-compatible Decisions runtime

openclaw/plugin-sdk/decisions-openai-runtime supplies the shared native Decisions codec and HTTP executor used by OpenAI and ClawRouter. Import it only from a lazy decision runtime, not a plugin's eager entrypoint.

evaluateOpenAICompatibleDecision(batch, context, route) accepts a host-prepared V2 context and a provider-owned { provider, baseUrl, modelId? } route. The base URL is the API prefix before /decisions; an optional upstream model ID changes only the wire model, preserving the prepared model's transport binding. The helper uses the prepared credential, headers, proxy/TLS policy, abort signal, deadline, and live admission assertion. It never discovers credentials or constructs conversation history. Consumers own endpoint eligibility and any account-specific route grant before calling it.

executeOpenAIDecision(batch, execution) accepts those same prepared facts as explicit fields: provider, model ID, base URL, headers, auth, request overrides, signal, deadline, admission assertion, and optional reasoning. Use it when a provider has already projected its execution inputs. Pass the full prepared request overrides, including auth metadata used to reject credential reflection. The context-based helper remains supported and delegates to this executor.

supportsOpenAIDecisionBatch(batch, reasoning) gates protocol kinds, image and question bounds, and automatic reasoning before transport/discovery. Malformed caller contracts throw; structurally valid requests outside protocol support or bounds return false. Results preserve Boolean/choice/score distributions, token usage, and per-question refusals; invalid or credential-reflecting responses fail closed.

The lightweight decisions subpath exports ModelInferenceCapabilitiesSchema for provider-owned catalog augmentation using the canonical capability schema rather than a competing normalizer. Static capability declarations do not confer account entitlement.

Runtime request headers

openclaw/plugin-sdk/provider-request-headers exports the ModelRequestHeaders type and omitNullRequestHeaders. Runtime headers can contain null deletion markers; preserve them through header merges and OpenAI SDK calls. Use the helper after the final merge when a direct HTTP client needs a string-only header map. This entrypoint loads no provider policy, transport host, or credential runtime.

Node workspace process environment

A node-host workspace lease may expose processEnvironment. Call prepare after generic environment sanitization and assertCurrent synchronously immediately before a process effect. The lease and invocation own its lifetime; saved copies do not survive release or cancellation. Use redactOutput at diagnostic egress. This capability is host-local and is never a wire environment override.

process-runtime exports createBoundedLineFramer for bounded LF-delimited byte streams. It preserves incomplete lines and leaves CR handling to the consumer. Node duplex calls may supply assertCurrent to compose caller-owned liveness with the runtime's existing dispatch and delivery authority.

Was this useful?