Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

The OpenClaw App SDK is the public client API for apps outside the OpenClaw process. Use @openclaw/sdk when a script, dashboard, CI job, IDE extension, or other external app wants to connect to the Gateway, start agent runs, stream events, wait for results, cancel work, or inspect Gateway resources.
The App SDK is different from the Plugin SDK. @openclaw/sdk talks to the Gateway from outside OpenClaw. openclaw/plugin-sdk/* is only for plugins that run inside OpenClaw and register providers, channels, tools, hooks, or trusted runtimes.

What Ships Today

@openclaw/sdk ships with:
SurfaceStatusWhat it does
OpenClawReadyMain client entry point. Owns transport, connection, requests, and events.
GatewayClientTransportReadyWebSocket transport backed by the Gateway client.
oc.agentsReadyLists, creates, updates, deletes, and gets agent handles.
Agent.run()ReadyStarts a Gateway agent run and returns a Run.
oc.runsReadyCreates, gets, waits for, cancels, and streams runs.
Run.events()ReadyStreams normalized per-run events with replay for fast runs.
Run.wait()ReadyCalls agent.wait and returns a stable RunResult.
Run.cancel()ReadyCalls sessions.abort by run id, with session key when available.
oc.sessionsReadyCreates, resolves, sends to, patches, compacts, and gets session handles.
Session.send()ReadyCalls sessions.send and returns a Run.
oc.modelsReadyCalls models.list and the current models.authStatus status RPC.
oc.toolsPartialLists tool catalog and effective tools; direct tool invocation is not wired.
oc.approvalsReadyLists and resolves exec approvals through Gateway approval RPCs.
oc.rawEvents()ReadyExposes raw Gateway events for advanced consumers.
normalizeGatewayEvent()ReadyConverts raw Gateway events into the stable SDK event shape.
The SDK also exports the core types used by those surfaces: AgentRunParams, RunResult, RunStatus, OpenClawEvent, OpenClawEventType, GatewayEvent, OpenClawTransport, GatewayRequestOptions, SessionCreateParams, SessionSendParams, RuntimeSelection, EnvironmentSelection, WorkspaceSelection, ApprovalMode, and related result types.

Connect To A Gateway

Create a client with an explicit Gateway URL, or inject a custom transport for tests and embedded app runtimes.
import { OpenClaw } from "@openclaw/sdk";

const oc = new OpenClaw({
  url: "ws://127.0.0.1:14565",
  token: process.env.OPENCLAW_GATEWAY_TOKEN,
  requestTimeoutMs: 30_000,
});

await oc.connect();
new OpenClaw({ gateway: "ws://..." }) is equivalent to url. The gateway: "auto" option is accepted by the constructor, but automatic Gateway discovery is not a separate SDK feature yet; pass url when the app does not already know how to discover the Gateway. For tests, pass an object that implements OpenClawTransport:
const oc = new OpenClaw({
  transport: {
    async request(method, params) {
      return { method, params };
    },
    async *events() {},
  },
});

Run An Agent

Use oc.agents.get(id) when the app wants an agent handle, then call agent.run().
const agent = await oc.agents.get("main");

const run = await agent.run({
  input: "Review this pull request and suggest the smallest safe fix.",
  model: "openai/gpt-5.5",
  sessionKey: "main",
  timeoutMs: 30_000,
});

for await (const event of run.events()) {
  const data = event.data as { delta?: unknown };
  if (event.type === "assistant.delta" && typeof data.delta === "string") {
    process.stdout.write(data.delta);
  }
}

const result = await run.wait({ timeoutMs: 120_000 });
console.log(result.status);
Provider-qualified model refs such as openai/gpt-5.5 are split into Gateway provider and model overrides. timeoutMs stays milliseconds in the SDK and is converted to Gateway timeout seconds for the agent RPC. run.wait() uses the Gateway agent.wait RPC. A wait deadline that expires while the run is still active returns status: "accepted" instead of pretending the run itself timed out. Runtime timeouts, aborted runs, and cancelled runs are normalized into timed_out or cancelled.

Create And Reuse Sessions

Use sessions when the app wants durable transcript state.
const session = await oc.sessions.create({
  agentId: "main",
  label: "release-review",
});

const run = await session.send("Prepare release notes from the current diff.");
await run.wait();
Session.send() calls sessions.send and returns a Run. Session handles also support:
await session.abort(run.id);
await session.patch({ label: "renamed-session" });
await session.compact({ maxLines: 200 });

Stream Events

The SDK normalizes raw Gateway events into a stable OpenClawEvent envelope:
type OpenClawEvent = {
  version: 1;
  id: string;
  ts: number;
  type: OpenClawEventType;
  runId?: string;
  sessionId?: string;
  sessionKey?: string;
  taskId?: string;
  agentId?: string;
  data: unknown;
  raw?: GatewayEvent;
};
Common event types include:
Event typeSource Gateway event
run.startedagent lifecycle start
run.completedagent lifecycle end
run.failedagent lifecycle error
run.cancelledAborted/cancelled lifecycle end
run.timed_outTimeout lifecycle end
assistant.deltaAssistant streaming delta
assistant.messageAssistant message
thinking.deltaThinking or plan stream
tool.call.startedTool/item/command start
tool.call.deltaTool/item/command update
tool.call.completedTool/item/command completion
tool.call.failedTool/item/command failure or blocked status
approval.requestedExec or plugin approval request
approval.resolvedExec or plugin approval resolution
session.createdsessions.changed create
session.updatedsessions.changed update
session.compactedsessions.changed compaction
task.updatedTask update events
artifact.updatedPatch stream events
rawAny event without a stable SDK mapping yet
Run.events() filters events to one run id and replays already-seen events for fast runs. That means the documented flow is safe:
const run = await agent.run("Summarize the latest session.");

for await (const event of run.events()) {
  if (event.type === "run.completed") {
    break;
  }
}
For app-wide streams, use oc.events(). For raw Gateway frames, use oc.rawEvents().

Models, Tools, And Approvals

Model helpers map to current Gateway methods:
await oc.models.list();
await oc.models.status({ probe: false }); // calls models.authStatus
Tool helpers expose the Gateway catalog and effective tool view:
await oc.tools.list();
await oc.tools.effective({ sessionKey: "main" });
Approval helpers use the exec approval RPCs:
const approvals = await oc.approvals.list();
await oc.approvals.respond("approval-id", { decision: "approve" });

Explicitly Unsupported Today

The SDK includes names for the product model we want, but it does not silently pretend Gateway RPCs exist. These calls currently throw explicit unsupported errors:
await oc.tasks.list();
await oc.tasks.get("task-id");
await oc.tasks.cancel("task-id");

await oc.tools.invoke("tool-name", {});

await oc.artifacts.list();
await oc.artifacts.get("artifact-id");
await oc.artifacts.download("artifact-id");

await oc.environments.list();
await oc.environments.create({});
await oc.environments.status("environment-id");
await oc.environments.delete("environment-id");
Per-run workspace, runtime, environment, and approvals fields are typed as future shape, but the current Gateway does not support those overrides on the agent RPC. If callers pass them, the SDK throws before submitting the run so work does not accidentally execute with default workspace, runtime, environment, or approval behavior.

App SDK Versus Plugin SDK

Use the App SDK when code lives outside OpenClaw:
  • Node scripts that start or observe agent runs
  • CI jobs that call a Gateway
  • dashboards and admin panels
  • IDE extensions
  • external bridges that do not need to become channel plugins
  • integration tests with fake or real Gateway transports
Use the Plugin SDK when code runs inside OpenClaw:
  • provider plugins
  • channel plugins
  • tool or lifecycle hooks
  • agent harness plugins
  • trusted runtime helpers
App SDK code should import from @openclaw/sdk. Plugin code should import from documented openclaw/plugin-sdk/* subpaths. Do not mix the two contracts.