From 78fc27fe7d5499dd62cd697bb2ea2b6fb5c48cc4 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 30 Apr 2026 01:58:58 +0100 Subject: [PATCH] docs: document shipped app sdk --- docs/.i18n/glossary.zh-CN.json | 8 + docs/concepts/openclaw-sdk.md | 492 ++++++++++++++------------------- 2 files changed, 212 insertions(+), 288 deletions(-) diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json index 820bb01a785..ba3bba70d65 100644 --- a/docs/.i18n/glossary.zh-CN.json +++ b/docs/.i18n/glossary.zh-CN.json @@ -35,6 +35,14 @@ "source": "Gateway", "target": "Gateway 网关" }, + { + "source": "Gateway RPC reference", + "target": "Gateway RPC 参考" + }, + { + "source": "Sessions", + "target": "会话" + }, { "source": "Pi", "target": "Pi" diff --git a/docs/concepts/openclaw-sdk.md b/docs/concepts/openclaw-sdk.md index 5bca17b1b9e..8e461a62814 100644 --- a/docs/concepts/openclaw-sdk.md +++ b/docs/concepts/openclaw-sdk.md @@ -1,142 +1,128 @@ --- -summary: "Public OpenClaw App SDK design for external apps, scripts, dashboards, CI jobs, and IDE extensions" +summary: "Public OpenClaw App SDK for external apps, scripts, dashboards, CI jobs, and IDE extensions" title: "OpenClaw App SDK" sidebarTitle: "App SDK" read_when: - - You are designing or implementing a public OpenClaw app SDK - - You are comparing OpenClaw agent APIs with Cursor, Claude Agent SDK, OpenAI Agents, Google ADK, OpenCode, Codex, or ACP - - You need to decide whether a feature belongs in the public App SDK, Plugin SDK, Gateway protocol, ACP backend, or managed environment layer + - You are building an external app, script, dashboard, CI job, or IDE extension that talks to OpenClaw + - You are choosing between the App SDK and the Plugin SDK + - You are integrating with Gateway agent runs, sessions, events, approvals, models, or tools --- -This page is a design proposal for the public **OpenClaw App SDK**. It is -separate from the existing [Plugin SDK](/plugins/sdk-overview). +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. - Use `@openclaw/sdk` when an external app, script, dashboard, CI job, or IDE - extension wants to run and observe OpenClaw agents through the Gateway. Use - `openclaw/plugin-sdk/*` only when writing a plugin that runs inside OpenClaw. + The App SDK is different from the [Plugin SDK](/plugins/sdk-overview). + `@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. -The Plugin SDK is for code that runs inside OpenClaw and extends providers, -channels, tools, hooks, and trusted runtimes. The App SDK should be for -external applications, scripts, dashboards, CI jobs, IDE extensions, and -automation systems that want to run and observe OpenClaw agents through a stable -public API. +## What Ships Today -## Status +`@openclaw/sdk` ships with: -Draft architecture. +| Surface | Status | What it does | +| ------------------------- | ------- | ---------------------------------------------------------------------------- | +| `OpenClaw` | Ready | Main client entry point. Owns transport, connection, requests, and events. | +| `GatewayClientTransport` | Ready | WebSocket transport backed by the Gateway client. | +| `oc.agents` | Ready | Lists, creates, updates, deletes, and gets agent handles. | +| `Agent.run()` | Ready | Starts a Gateway `agent` run and returns a `Run`. | +| `oc.runs` | Ready | Creates, gets, waits for, cancels, and streams runs. | +| `Run.events()` | Ready | Streams normalized per-run events with replay for fast runs. | +| `Run.wait()` | Ready | Calls `agent.wait` and returns a stable `RunResult`. | +| `Run.cancel()` | Ready | Calls `sessions.abort` by run id, with session key when available. | +| `oc.sessions` | Ready | Creates, resolves, sends to, patches, compacts, and gets session handles. | +| `Session.send()` | Ready | Calls `sessions.send` and returns a `Run`. | +| `oc.models` | Ready | Calls `models.list` and the current `models.authStatus` status RPC. | +| `oc.tools` | Partial | Lists tool catalog and effective tools; direct tool invocation is not wired. | +| `oc.approvals` | Ready | Lists and resolves exec approvals through Gateway approval RPCs. | +| `oc.rawEvents()` | Ready | Exposes raw Gateway events for advanced consumers. | +| `normalizeGatewayEvent()` | Ready | Converts raw Gateway events into the stable SDK event shape. | -This document captures the design direction from a comparative review of these -agent SDK and runtime surfaces: +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. -| Project | Useful lesson | -| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Cursor SDK cookbook | Best high-level product API: `Agent`, `Run`, local and cloud runtimes, streaming, cancellation, model discovery, repositories, artifacts, and cloud pull request flows. | -| Claude Agent SDK | Strong bidirectional session client, interrupt and steer support, permission modes, hooks, custom tools, session stores, and resumable transcripts. | -| OpenAI Agents SDK | Strong workflow concepts: handoffs, guardrails, human approvals, tracing, run state, streaming result objects, and resume after interruptions. | -| Google ADK | Strong internal architecture: runner, session service, memory service, artifact service, credential service, plugins, event actions, and long running tool confirmations. | -| OpenCode | Strong client/server shape: generated API client, REST plus SSE, sessions, workspaces, worktrees, permissions, questions, files, VCS, PTY, tools, agents, skills, and MCP. | -| Codex | Strong local runtime boundary: approvals, sandboxing, network policy, local and remote exec servers, structured protocol events, and thread aware app-server sessions. | -| ACP and acpx | Strong interoperability layer for external coding harnesses with named sessions, prompt queues, cooperative cancellation, and runtime adapters. | +## Connect To A Gateway -The recommendation is to build a Cursor-simple public facade on top of an -OpenCode-style generated Gateway client, while keeping Claude, OpenAI Agents, -ADK, Codex, and ACP concepts as internal design references where they fit. - -## Goals - -- Give app developers a tiny high-level API for running OpenClaw agents. -- Keep local-first OpenClaw as the default runtime. -- Make cloud or managed environments an additive environment provider, not a - different agent API. -- Preserve existing OpenClaw boundaries: Gateway owns public protocol, plugin - SDK owns in-process extensions, ACP owns external harness interop. -- Support `stream`, `wait`, `cancel`, `resume`, `fork`, artifacts, approvals, - and background tasks as first-class operations. -- Expose stable normalized events while preserving runtime-native raw events for - advanced consumers. -- Make SDK permissions, secret forwarding, approvals, sandboxing, and remote - environments explicit. -- Keep the public contract small enough to document, test, version, and - generate. - -## Non goals - -- Do not expose `openclaw/plugin-sdk/*` as the app SDK. -- Do not make ACP the only runtime model. -- Do not require a cloud service before the SDK is useful. -- Do not clone Cursor, Claude, OpenAI, ADK, OpenCode, Codex, or ACP APIs - exactly. -- Do not expose unbounded `any` event payloads as the only public contract. -- Do not promise sandbox or network isolation for an external harness unless - the selected environment can actually enforce it. -- Do not make plugin authors depend on app SDK objects inside plugin runtime - code. - -## Current OpenClaw fit - -OpenClaw already has most of the substrate: - -| Existing surface | What it contributes | -| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| [Agent loop](/concepts/agent-loop) | `agent` and `agent.wait` run lifecycle, streaming, timeout, and session serialization. | -| [Agent runtimes](/concepts/agent-runtimes) | Provider, model, runtime, and channel separation. | -| [ACP agents](/tools/acp-agents) | External harness sessions for Claude Code, Cursor, Gemini CLI, OpenCode, explicit Codex ACP, and similar tools. | -| [Background tasks](/automation/tasks) | Detached activity ledger for ACP, subagents, cron, CLI operations, and async media jobs. | -| [Sub-agents](/tools/subagents) | Isolated background agent runs, optional forked context, delivery back to requester sessions. | -| [Agent harness plugins](/plugins/sdk-agent-harness) | Trusted native runtime registration for embedded harnesses such as Codex. | -| Gateway protocol schemas | Current typed method and event definitions for agent params, sessions, subscriptions, aborts, compaction, and checkpoints. | - -The gap is not agent execution. The gap is a stable, friendly public facade over -these pieces. - -## Core model - -The app SDK should use a small set of durable nouns. - -| Noun | Meaning | -| ------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `OpenClaw` | Client entry point. Owns Gateway discovery, auth, low-level client access, and namespace factories. | -| `Agent` | Configured actor. Carries agent id, default model, default runtime, default tool policy, and app-facing helpers. | -| `Session` | Durable transcript, routing, workspace, context, and runtime binding. | -| `Run` | One submitted turn or task. Streams events, waits for result, cancels, and exposes artifacts. | -| `Task` | Detached or background activity ledger entry. Covers subagents, ACP spawns, cron jobs, CLI runs, and async jobs. | -| `Artifact` | Files, patches, diffs, media, logs, trajectories, pull requests, screenshots, and generated bundles. | -| `Environment` | Where the run executes: local Gateway, local workspace, node host, ACP harness, managed runner, or future cloud workspace. | -| `ToolSpace` | The effective tool surface: OpenClaw tools, MCP servers, channel tools, app tools, approval rules, and tool metadata. | -| `Approval` | Human or policy decision requested by a run, tool, environment, or harness. | - -These nouns map cleanly to existing OpenClaw concepts but avoid leaking -implementation-specific names such as PI runner internals, plugin harness -registration, or ACP adapter details. - -## Product shape - -The high-level SDK should feel like this: +Create a client with an explicit Gateway URL, or inject a custom transport for +tests and embedded app runtimes. ```typescript import { OpenClaw } from "@openclaw/sdk"; -const oc = new OpenClaw({ gateway: "auto" }); +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`: + +```typescript +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()`. + +```typescript 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()) { - if (event.type === "assistant.delta") { - process.stdout.write(event.text); + 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(); +const result = await run.wait({ timeoutMs: 120_000 }); console.log(result.status); ``` -The same app should be able to use a durable session: +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. ```typescript const session = await oc.sessions.create({ @@ -148,227 +134,157 @@ const run = await session.send("Prepare release notes from the current diff."); await run.wait(); ``` -Current implementation note: `@openclaw/sdk` starts with the Gateway-backed -surface that exists today. Provider-qualified model refs such as -`openai/gpt-5.5` are split into Gateway `provider` and `model` overrides. -Per-run `workspace`, `runtime`, `environment`, and `approvals` selections are -still design targets; the client throws when callers set them so requests do not -silently execute with defaults. Task, artifact, environment, and generic tool -invocation helpers are also scaffolded as future API shape and throw explicit -unsupported errors until Gateway RPCs exist for them. - -And the same API should be able to use an external ACP harness: +`Session.send()` calls `sessions.send` and returns a `Run`. Session handles also +support: ```typescript -const run = await oc.runs.create({ - input: "Deep review this repository and return only high-risk findings.", - workspace: { cwd: process.cwd() }, - runtime: { type: "acp", harness: "claude" }, - mode: "task", -}); +await session.abort(run.id); +await session.patch({ label: "renamed-session" }); +await session.compact({ maxLines: 200 }); ``` -Managed environments should not change the top-level API: +## Stream Events + +The SDK normalizes raw Gateway events into a stable `OpenClawEvent` envelope: ```typescript -const run = await agent.run({ - input: "Run the full changed gate and summarize failures.", - workspace: { repo: "openclaw/openclaw", ref: "main" }, - runtime: { - type: "managed", - provider: "testbox", - timeoutMinutes: 90, - }, -}); +type OpenClawEvent = { + version: 1; + id: string; + ts: number; + type: OpenClawEventType; + runId?: string; + sessionId?: string; + sessionKey?: string; + taskId?: string; + agentId?: string; + data: unknown; + raw?: GatewayEvent; +}; ``` -## Runtime selection +Common event types include: -The app SDK should expose runtime selection as a normalized union: +| Event type | Source Gateway event | +| --------------------- | ------------------------------------------- | +| `run.started` | `agent` lifecycle start | +| `run.completed` | `agent` lifecycle end | +| `run.failed` | `agent` lifecycle error | +| `run.cancelled` | Aborted/cancelled lifecycle end | +| `run.timed_out` | Timeout lifecycle end | +| `assistant.delta` | Assistant streaming delta | +| `assistant.message` | Assistant message | +| `thinking.delta` | Thinking or plan stream | +| `tool.call.started` | Tool/item/command start | +| `tool.call.delta` | Tool/item/command update | +| `tool.call.completed` | Tool/item/command completion | +| `tool.call.failed` | Tool/item/command failure or blocked status | +| `approval.requested` | Exec or plugin approval request | +| `approval.resolved` | Exec or plugin approval resolution | +| `session.created` | `sessions.changed` create | +| `session.updated` | `sessions.changed` update | +| `session.compacted` | `sessions.changed` compaction | +| `task.updated` | Task update events | +| `artifact.updated` | Patch stream events | +| `raw` | Any 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: ```typescript -type RuntimeSelection = - | "auto" - | { type: "embedded"; id: "pi" | "codex" | string } - | { type: "cli"; id: "claude-cli" | string } - | { type: "acp"; harness: "claude" | "cursor" | "gemini" | "opencode" | string } - | { type: "managed"; provider: "local" | "node" | "testbox" | "cloud" | string }; +const run = await agent.run("Summarize the latest session."); + +for await (const event of run.events()) { + if (event.type === "run.completed") { + break; + } +} ``` -Rules: +For app-wide streams, use `oc.events()`. For raw Gateway frames, use +`oc.rawEvents()`. -- `auto` follows OpenClaw runtime selection rules. -- `embedded` targets trusted in-process harnesses registered through the plugin - SDK, such as `pi` or `codex`. -- `cli` targets OpenClaw-owned CLI backend execution where available. -- `acp` targets external harnesses through ACP/acpx. -- `managed` targets an environment provider and may still run an embedded, - CLI, or ACP runtime inside that environment. +## Models, Tools, And Approvals -The runtime selection object should be descriptive. It should not be the place -where secret handling, sandbox policy, or workspace provisioning hides. - -## Environment model - -The environment is the execution substrate. It should be explicit because local -CLI runs, external harnesses, node hosts, and cloud workspaces have different -safety and lifecycle properties. +Model helpers map to current Gateway methods: ```typescript -type EnvironmentSelection = - | { type: "local"; cwd?: string } - | { type: "gateway"; url?: string; cwd?: string } - | { type: "node"; nodeId: string; cwd?: string } - | { type: "managed"; provider: string; repo?: string; ref?: string } - | { type: "ephemeral"; provider: string; repo?: string; ref?: string }; +await oc.models.list(); +await oc.models.status({ probe: false }); // calls models.authStatus ``` -The environment owns: +Tool helpers expose the Gateway catalog and effective tool view: -- checkout or workspace preparation -- process and file access -- sandbox and network enforcement -- environment variables and secret references -- logs, traces, and artifacts -- cleanup and retention -- runtime availability +```typescript +await oc.tools.list(); +await oc.tools.effective({ sessionKey: "main" }); +``` -This separation makes managed agents a natural extension of the SDK. A managed -agent is a normal run in a managed environment, not a special product fork. +Approval helpers use the exec approval RPCs: -The detailed namespace, event, result, approval, artifact, security, package, -and environment provider contracts live in -[OpenClaw App SDK API design](/reference/openclaw-sdk-api-design). +```typescript +const approvals = await oc.approvals.list(); +await oc.approvals.respond("approval-id", { decision: "approve" }); +``` -## Cookbook plan +## Explicitly Unsupported Today -The SDK should ship with a cookbook, not just reference docs. +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: -Recommended examples: +```typescript +await oc.tasks.list(); +await oc.tasks.get("task-id"); +await oc.tasks.cancel("task-id"); -| Example | Shows | -| ---------------------------- | -------------------------------------------------------------------------------------------- | -| Quickstart | Create client, run an agent, stream output, wait for result. | -| Coding agent CLI | Local workspace, model picker, cancellation, approvals, JSON output. | -| Agent dashboard | Sessions, runs, background tasks, artifacts, event replay, status filters. | -| App builder | Agent edits a workspace while a preview server runs beside it. | -| Pull request reviewer | Run against a repository ref, collect diff comments and artifacts. | -| Approval console | Subscribe to approvals and answer them from a UI. | -| ACP harness runner | Run Claude Code, Cursor, Gemini CLI, or OpenCode through ACP using the same `Run` API. | -| Managed environment provider | Minimal provider that prepares a workspace, streams events, saves artifacts, and cleans up. | -| Slack or Discord bridge | External app receives events and posts progress summaries without becoming a channel plugin. | -| Multi-agent research | Spawn parallel runs, collect artifacts, and synthesize a final report. | +await oc.tools.invoke("tool-name", {}); -Cookbook examples should use the high-level API first. Low-level generated -client examples belong in an advanced section. +await oc.artifacts.list(); +await oc.artifacts.get("artifact-id"); +await oc.artifacts.download("artifact-id"); -## Phased implementation +await oc.environments.list(); +await oc.environments.create({}); +await oc.environments.status("environment-id"); +await oc.environments.delete("environment-id"); +``` -### Phase 0: RFC and vocabulary +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. -- Agree on public nouns and names. -- Decide package names. -- Define the first event taxonomy. -- Mark the current Plugin SDK as intentionally separate in docs. +## App SDK Versus Plugin SDK -### Phase 1: Low-level generated client +Use the App SDK when code lives outside OpenClaw: -- Generate a TypeScript client from Gateway protocol schemas. -- Cover `agent`, `agent.wait`, sessions, subscriptions, aborts, and tasks first. -- Add smoke tests that generated methods match Gateway method names and schema - shapes. -- Publish as experimental or internal package. +- 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 -### Phase 2: High-level run API +Use the Plugin SDK when code runs inside OpenClaw: -- Add `OpenClaw`, `Agent`, `Session`, and `Run`. -- Support `run.events()`, `run.wait()`, and `run.cancel()`. -- Support local Gateway discovery and explicit Gateway URLs. -- Support durable sessions and session send. +- provider plugins +- channel plugins +- tool or lifecycle hooks +- agent harness plugins +- trusted runtime helpers -### Phase 3: Normalized event projection +App SDK code should import from `@openclaw/sdk`. Plugin code should import from +documented `openclaw/plugin-sdk/*` subpaths. Do not mix the two contracts. -- Add Gateway-side normalized event projection beside existing raw events. -- Preserve raw runtime events where policy allows. -- Add replay cursors and reconnect behavior. -- Map PI, Codex, ACP, and task events into the stable taxonomy. - -### Phase 4: Artifacts and approvals - -- Add artifact listing and download. -- Add approval subscription and response helpers. -- Add question subscription and response helpers. -- Add cookbook approval console. - -### Phase 5: Environment providers - -- Introduce local, node, and managed environment provider contracts. -- Start with an environment that already exists operationally. -- Add workspace preparation, logs, artifacts, timeout, cleanup, and retention. - -### Phase 6: Cloud style workflows - -- Add repository and branch oriented runs. -- Add pull request artifacts. -- Add run boards grouped by repo, branch, status, and assignee. -- Add long-running managed sessions and retention policy. - -## Design choices to copy - -Copy these ideas: - -- From Cursor: `Agent` plus `Run`, local and cloud symmetry, model discovery, - artifacts, and cookbook-driven onboarding. -- From Claude Agent SDK: bidirectional clients, interrupt, permissions, hooks, - custom tools, session stores, and resume semantics. -- From OpenAI Agents: handoffs, guardrails, human approval resume, tracing, and - structured streamed result objects. -- From Google ADK: services behind runner, event actions, memory, artifacts, - credential services, and plugin interception around run lifecycle. -- From OpenCode: generated protocol client, REST plus SSE, sessions, - workspaces, questions, permissions, files, VCS, PTY, MCP, agents, and skills. -- From Codex: explicit sandbox, approval, network, local and remote exec, and - app-server thread boundaries. -- From ACP and acpx: adapter based external harness interoperability and named - prompt queues. - -## Design choices to avoid - -Avoid these traps: - -- A public SDK that is just a thin dump of Gateway internals. -- A public SDK that imports Plugin SDK subpaths. -- A public SDK where events are only `stream` plus `data`. -- A cloud-first API that makes local OpenClaw feel like a legacy mode. -- Runtime selection hidden in model id prefixes. -- Secret forwarding hidden in environment maps. -- ACP specific options at the top level of every run. -- Sandbox flags that cannot be enforced by the chosen runtime. -- One SDK object that tries to be provider plugin, channel plugin, app client, - and managed runner at once. - -## Open questions - -- Should the initial package live in this repo or a separate SDK repo? -- Should the generated low-level client be published publicly before the - high-level wrapper stabilizes? -- What is the first supported app auth mechanism: local token, admin token, - OAuth device flow, or signed app registration? -- How much session message history should the SDK expose by default? -- Should managed environments be configured only in Gateway config, or can SDK - callers request them directly with scoped tokens? -- What retention rules apply to artifacts generated by local runs? -- Which event payloads require redaction before app delivery? -- Should `Run` cover normal chat turns and detached tasks, or should detached - background work always return a `Task` wrapper with a nested `Run`? - -## Related docs +## Related Docs +- [OpenClaw App SDK API design](/reference/openclaw-sdk-api-design) +- [Gateway RPC reference](/reference/rpc) - [Agent loop](/concepts/agent-loop) - [Agent runtimes](/concepts/agent-runtimes) -- [Session](/concepts/session) -- [Sub-agents](/tools/subagents) +- [Sessions](/concepts/session) - [Background tasks](/automation/tasks) - [ACP agents](/tools/acp-agents) -- [Agent harness plugins](/plugins/sdk-agent-harness) - [Plugin SDK overview](/plugins/sdk-overview)