diff --git a/.openclaw-sync/source.json b/.openclaw-sync/source.json index 483953b85..3800e12ff 100644 --- a/.openclaw-sync/source.json +++ b/.openclaw-sync/source.json @@ -1,5 +1,5 @@ { "repository": "openclaw/openclaw", - "sha": "e28fca2e1124448503a0c9fcfedcff9bee768060", - "syncedAt": "2026-04-23T22:56:59.026Z" + "sha": "9cc67fecaf7a813b46c58e4c0cb4f2b065e3cb11", + "syncedAt": "2026-04-23T23:00:01.327Z" } diff --git a/docs/docs.json b/docs/docs.json index e36d40e68..301f94887 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1159,6 +1159,7 @@ "group": "SDK Reference", "pages": [ "plugins/sdk-overview", + "plugins/sdk-subpaths", "plugins/sdk-entrypoints", "plugins/sdk-runtime", "plugins/sdk-agent-harness", @@ -1201,6 +1202,7 @@ "tools/diffs", "tools/elevated", "tools/exec-approvals", + "tools/exec-approvals-advanced", "tools/exec", "tools/image-generation", "tools/llm-task", @@ -2550,6 +2552,7 @@ "group": "SDK Reference", "pages": [ "ja-JP/plugins/sdk-overview", + "ja-JP/plugins/sdk-subpaths", "ja-JP/plugins/sdk-entrypoints", "ja-JP/plugins/sdk-runtime", "ja-JP/plugins/sdk-agent-harness", @@ -2592,6 +2595,7 @@ "ja-JP/tools/diffs", "ja-JP/tools/elevated", "ja-JP/tools/exec-approvals", + "ja-JP/tools/exec-approvals-advanced", "ja-JP/tools/exec", "ja-JP/tools/image-generation", "ja-JP/tools/llm-task", @@ -3326,6 +3330,7 @@ "group": "SDK Reference", "pages": [ "es/plugins/sdk-overview", + "es/plugins/sdk-subpaths", "es/plugins/sdk-entrypoints", "es/plugins/sdk-runtime", "es/plugins/sdk-agent-harness", @@ -3368,6 +3373,7 @@ "es/tools/diffs", "es/tools/elevated", "es/tools/exec-approvals", + "es/tools/exec-approvals-advanced", "es/tools/exec", "es/tools/image-generation", "es/tools/llm-task", @@ -4102,6 +4108,7 @@ "group": "SDK Reference", "pages": [ "pt-BR/plugins/sdk-overview", + "pt-BR/plugins/sdk-subpaths", "pt-BR/plugins/sdk-entrypoints", "pt-BR/plugins/sdk-runtime", "pt-BR/plugins/sdk-agent-harness", @@ -4144,6 +4151,7 @@ "pt-BR/tools/diffs", "pt-BR/tools/elevated", "pt-BR/tools/exec-approvals", + "pt-BR/tools/exec-approvals-advanced", "pt-BR/tools/exec", "pt-BR/tools/image-generation", "pt-BR/tools/llm-task", @@ -4878,6 +4886,7 @@ "group": "SDK Reference", "pages": [ "ko/plugins/sdk-overview", + "ko/plugins/sdk-subpaths", "ko/plugins/sdk-entrypoints", "ko/plugins/sdk-runtime", "ko/plugins/sdk-agent-harness", @@ -4920,6 +4929,7 @@ "ko/tools/diffs", "ko/tools/elevated", "ko/tools/exec-approvals", + "ko/tools/exec-approvals-advanced", "ko/tools/exec", "ko/tools/image-generation", "ko/tools/llm-task", @@ -5654,6 +5664,7 @@ "group": "SDK Reference", "pages": [ "de/plugins/sdk-overview", + "de/plugins/sdk-subpaths", "de/plugins/sdk-entrypoints", "de/plugins/sdk-runtime", "de/plugins/sdk-agent-harness", @@ -5696,6 +5707,7 @@ "de/tools/diffs", "de/tools/elevated", "de/tools/exec-approvals", + "de/tools/exec-approvals-advanced", "de/tools/exec", "de/tools/image-generation", "de/tools/llm-task", @@ -6430,6 +6442,7 @@ "group": "SDK Reference", "pages": [ "fr/plugins/sdk-overview", + "fr/plugins/sdk-subpaths", "fr/plugins/sdk-entrypoints", "fr/plugins/sdk-runtime", "fr/plugins/sdk-agent-harness", @@ -6472,6 +6485,7 @@ "fr/tools/diffs", "fr/tools/elevated", "fr/tools/exec-approvals", + "fr/tools/exec-approvals-advanced", "fr/tools/exec", "fr/tools/image-generation", "fr/tools/llm-task", @@ -7206,6 +7220,7 @@ "group": "SDK Reference", "pages": [ "ar/plugins/sdk-overview", + "ar/plugins/sdk-subpaths", "ar/plugins/sdk-entrypoints", "ar/plugins/sdk-runtime", "ar/plugins/sdk-agent-harness", @@ -7248,6 +7263,7 @@ "ar/tools/diffs", "ar/tools/elevated", "ar/tools/exec-approvals", + "ar/tools/exec-approvals-advanced", "ar/tools/exec", "ar/tools/image-generation", "ar/tools/llm-task", @@ -7982,6 +7998,7 @@ "group": "SDK Reference", "pages": [ "it/plugins/sdk-overview", + "it/plugins/sdk-subpaths", "it/plugins/sdk-entrypoints", "it/plugins/sdk-runtime", "it/plugins/sdk-agent-harness", @@ -8024,6 +8041,7 @@ "it/tools/diffs", "it/tools/elevated", "it/tools/exec-approvals", + "it/tools/exec-approvals-advanced", "it/tools/exec", "it/tools/image-generation", "it/tools/llm-task", @@ -8758,6 +8776,7 @@ "group": "SDK Reference", "pages": [ "tr/plugins/sdk-overview", + "tr/plugins/sdk-subpaths", "tr/plugins/sdk-entrypoints", "tr/plugins/sdk-runtime", "tr/plugins/sdk-agent-harness", @@ -8800,6 +8819,7 @@ "tr/tools/diffs", "tr/tools/elevated", "tr/tools/exec-approvals", + "tr/tools/exec-approvals-advanced", "tr/tools/exec", "tr/tools/image-generation", "tr/tools/llm-task", @@ -9534,6 +9554,7 @@ "group": "SDK Reference", "pages": [ "uk/plugins/sdk-overview", + "uk/plugins/sdk-subpaths", "uk/plugins/sdk-entrypoints", "uk/plugins/sdk-runtime", "uk/plugins/sdk-agent-harness", @@ -9576,6 +9597,7 @@ "uk/tools/diffs", "uk/tools/elevated", "uk/tools/exec-approvals", + "uk/tools/exec-approvals-advanced", "uk/tools/exec", "uk/tools/image-generation", "uk/tools/llm-task", @@ -10310,6 +10332,7 @@ "group": "SDK Reference", "pages": [ "id/plugins/sdk-overview", + "id/plugins/sdk-subpaths", "id/plugins/sdk-entrypoints", "id/plugins/sdk-runtime", "id/plugins/sdk-agent-harness", @@ -10352,6 +10375,7 @@ "id/tools/diffs", "id/tools/elevated", "id/tools/exec-approvals", + "id/tools/exec-approvals-advanced", "id/tools/exec", "id/tools/image-generation", "id/tools/llm-task", @@ -11086,6 +11110,7 @@ "group": "SDK Reference", "pages": [ "pl/plugins/sdk-overview", + "pl/plugins/sdk-subpaths", "pl/plugins/sdk-entrypoints", "pl/plugins/sdk-runtime", "pl/plugins/sdk-agent-harness", @@ -11128,6 +11153,7 @@ "pl/tools/diffs", "pl/tools/elevated", "pl/tools/exec-approvals", + "pl/tools/exec-approvals-advanced", "pl/tools/exec", "pl/tools/image-generation", "pl/tools/llm-task", diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md index 3196bac51..61f5a9953 100644 --- a/docs/gateway/configuration-reference.md +++ b/docs/gateway/configuration-reference.md @@ -1214,7 +1214,7 @@ Time format in system prompt. Default: `auto` (OS preference). - `imageGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`). - Used by the shared image-generation capability and any future tool/plugin surface that generates images. - Typical values: `google/gemini-3.1-flash-image-preview` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, or `openai/gpt-image-2` for OpenAI Images. - - If you select a provider/model directly, configure the matching provider auth/API key too (for example `GEMINI_API_KEY` or `GOOGLE_API_KEY` for `google/*`, `OPENAI_API_KEY` for `openai/*`, `FAL_KEY` for `fal/*`). + - If you select a provider/model directly, configure matching provider auth too (for example `GEMINI_API_KEY` or `GOOGLE_API_KEY` for `google/*`, `OPENAI_API_KEY` or OpenAI Codex OAuth for `openai/gpt-image-2`, `FAL_KEY` for `fal/*`). - If omitted, `image_generate` can still infer an auth-backed provider default. It tries the current default provider first, then the remaining registered image-generation providers in provider-id order. - `musicGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`). - Used by the shared music-generation capability and the built-in `music_generate` tool. diff --git a/docs/plugins/sdk-overview.md b/docs/plugins/sdk-overview.md index 09aa754a3..fbbb88728 100644 --- a/docs/plugins/sdk-overview.md +++ b/docs/plugins/sdk-overview.md @@ -50,262 +50,12 @@ not recommended import paths for new third-party plugins. ## Subpath reference -The most commonly used subpaths, grouped by purpose. The generated full list of -200+ subpaths lives in `scripts/lib/plugin-sdk-entrypoints.json`; reserved -bundled-plugin helper subpaths appear there but are implementation detail -unless a doc page explicitly promotes them. +The plugin SDK is exposed as a set of narrow subpaths grouped by area (plugin +entry, channel, provider, auth, runtime, capability, memory, and reserved +bundled-plugin helpers). For the full catalog — grouped and linked — see +[Plugin SDK subpaths](/plugins/sdk-subpaths). -### Plugin entry - -| Subpath | Key exports | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| `plugin-sdk/plugin-entry` | `definePluginEntry` | -| `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` | -| `plugin-sdk/config-schema` | `OpenClawSchema` | -| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/channel-core` | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` | - | `plugin-sdk/config-schema` | Root `openclaw.json` Zod schema export (`OpenClawSchema`) | - | `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`, plus `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` | - | `plugin-sdk/setup` | Shared setup wizard helpers, allowlist prompts, setup status builders | - | `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` | - | `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` | - | `plugin-sdk/setup-tools` | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` | - | `plugin-sdk/account-core` | Multi-account config/action-gate helpers, default-account fallback helpers | - | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`, account-id normalization helpers | - | `plugin-sdk/account-resolution` | Account lookup + default-fallback helpers | - | `plugin-sdk/account-helpers` | Narrow account-list/account-action helpers | - | `plugin-sdk/channel-pairing` | `createChannelPairingController` | - | `plugin-sdk/channel-reply-pipeline` | `createChannelReplyPipeline` | - | `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` | - | `plugin-sdk/channel-config-schema` | Channel config schema types | - | `plugin-sdk/telegram-command-config` | Telegram custom-command normalization/validation helpers with bundled-contract fallback | - | `plugin-sdk/command-gating` | Narrow command authorization gate helpers | - | `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` | - | `plugin-sdk/channel-lifecycle` | `createAccountStatusSink`, draft stream lifecycle/finalization helpers | - | `plugin-sdk/inbound-envelope` | Shared inbound route + envelope builder helpers | - | `plugin-sdk/inbound-reply-dispatch` | Shared inbound record-and-dispatch helpers | - | `plugin-sdk/messaging-targets` | Target parsing/matching helpers | - | `plugin-sdk/outbound-media` | Shared outbound media loading helpers | - | `plugin-sdk/outbound-runtime` | Outbound identity, send delegate, and payload planning helpers | - | `plugin-sdk/poll-runtime` | Narrow poll normalization helpers | - | `plugin-sdk/thread-bindings-runtime` | Thread-binding lifecycle and adapter helpers | - | `plugin-sdk/agent-media-payload` | Legacy agent media payload builder | - | `plugin-sdk/conversation-runtime` | Conversation/thread binding, pairing, and configured-binding helpers | - | `plugin-sdk/runtime-config-snapshot` | Runtime config snapshot helper | - | `plugin-sdk/runtime-group-policy` | Runtime group-policy resolution helpers | - | `plugin-sdk/channel-status` | Shared channel status snapshot/summary helpers | - | `plugin-sdk/channel-config-primitives` | Narrow channel config-schema primitives | - | `plugin-sdk/channel-config-writes` | Channel config-write authorization helpers | - | `plugin-sdk/channel-plugin-common` | Shared channel plugin prelude exports | - | `plugin-sdk/allowlist-config-edit` | Allowlist config edit/read helpers | - | `plugin-sdk/group-access` | Shared group-access decision helpers | - | `plugin-sdk/direct-dm` | Shared direct-DM auth/guard helpers | - | `plugin-sdk/interactive-runtime` | Semantic message presentation, delivery, and legacy interactive reply helpers. See [Message Presentation](/plugins/message-presentation) | - | `plugin-sdk/channel-inbound` | Compatibility barrel for inbound debounce, mention matching, mention-policy helpers, and envelope helpers | - | `plugin-sdk/channel-mention-gating` | Narrow mention-policy helpers without the broader inbound runtime surface | - | `plugin-sdk/channel-location` | Channel location context and formatting helpers | - | `plugin-sdk/channel-logging` | Channel logging helpers for inbound drops and typing/ack failures | - | `plugin-sdk/channel-send-result` | Reply result types | - | `plugin-sdk/channel-actions` | Channel message-action helpers, plus deprecated native schema helpers kept for plugin compatibility | - | `plugin-sdk/channel-targets` | Target parsing/matching helpers | - | `plugin-sdk/channel-contract` | Channel contract types | - | `plugin-sdk/channel-feedback` | Feedback/reaction wiring | - | `plugin-sdk/channel-secret-runtime` | Narrow secret-contract helpers such as `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment`, and secret target types | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | - | `plugin-sdk/provider-setup` | Curated local/self-hosted provider setup helpers | - | `plugin-sdk/self-hosted-provider-setup` | Focused OpenAI-compatible self-hosted provider setup helpers | - | `plugin-sdk/cli-backend` | CLI backend defaults + watchdog constants | - | `plugin-sdk/provider-auth-runtime` | Runtime API-key resolution helpers for provider plugins | - | `plugin-sdk/provider-auth-api-key` | API-key onboarding/profile-write helpers such as `upsertApiKeyProfile` | - | `plugin-sdk/provider-auth-result` | Standard OAuth auth-result builder | - | `plugin-sdk/provider-auth-login` | Shared interactive login helpers for provider plugins | - | `plugin-sdk/provider-env-vars` | Provider auth env-var lookup helpers | - | `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`, `ensureApiKeyFromOptionEnvOrPrompt`, `upsertAuthProfile`, `upsertApiKeyProfile`, `writeOAuthCredentials` | - | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`, shared replay-policy builders, provider-endpoint helpers, and model-id normalization helpers such as `normalizeNativeXaiModelId` | - | `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`, `buildSingleProviderApiKeyCatalog`, `supportsNativeStreamingUsageCompat`, `applyProviderNativeStreamingUsageCompat` | - | `plugin-sdk/provider-http` | Generic provider HTTP/endpoint capability helpers, including audio transcription multipart form helpers | - | `plugin-sdk/provider-web-fetch-contract` | Narrow web-fetch config/selection contract helpers such as `enablePluginInConfig` and `WebFetchProviderPlugin` | - | `plugin-sdk/provider-web-fetch` | Web-fetch provider registration/cache helpers | - | `plugin-sdk/provider-web-search-config-contract` | Narrow web-search config/credential helpers for providers that do not need plugin-enable wiring | - | `plugin-sdk/provider-web-search-contract` | Narrow web-search config/credential contract helpers such as `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`, and scoped credential setters/getters | - | `plugin-sdk/provider-web-search` | Web-search provider registration/cache/runtime helpers | - | `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`, `buildProviderToolCompatFamilyHooks`, Gemini schema cleanup + diagnostics, and xAI compat helpers such as `resolveXaiModelCompatPatch` / `applyXaiModelCompat` | - | `plugin-sdk/provider-usage` | `fetchClaudeUsage` and similar | - | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`, stream wrapper types, and shared Anthropic/Bedrock/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot wrapper helpers | - | `plugin-sdk/provider-transport-runtime` | Native provider transport helpers such as guarded fetch, transport message transforms, and writable transport event streams | - | `plugin-sdk/provider-onboard` | Onboarding config patch helpers | - | `plugin-sdk/global-singleton` | Process-local singleton/map/cache helpers | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/command-auth` | `resolveControlCommandGate`, command registry helpers, sender-authorization helpers | - | `plugin-sdk/command-status` | Command/help message builders such as `buildCommandsMessagePaginated` and `buildHelpMessage` | - | `plugin-sdk/approval-auth-runtime` | Approver resolution and same-chat action-auth helpers | - | `plugin-sdk/approval-client-runtime` | Native exec approval profile/filter helpers | - | `plugin-sdk/approval-delivery-runtime` | Native approval capability/delivery adapters | - | `plugin-sdk/approval-gateway-runtime` | Shared approval gateway-resolution helper | - | `plugin-sdk/approval-handler-adapter-runtime` | Lightweight native approval adapter loading helpers for hot channel entrypoints | - | `plugin-sdk/approval-handler-runtime` | Broader approval handler runtime helpers; prefer the narrower adapter/gateway seams when they are enough | - | `plugin-sdk/approval-native-runtime` | Native approval target + account-binding helpers | - | `plugin-sdk/approval-reply-runtime` | Exec/plugin approval reply payload helpers | - | `plugin-sdk/command-auth-native` | Native command auth + native session-target helpers | - | `plugin-sdk/command-detection` | Shared command detection helpers | - | `plugin-sdk/command-surface` | Command-body normalization and command-surface helpers | - | `plugin-sdk/allow-from` | `formatAllowFromLowercase` | - | `plugin-sdk/channel-secret-runtime` | Narrow secret-contract collection helpers for channel/plugin secret surfaces | - | `plugin-sdk/secret-ref-runtime` | Narrow `coerceSecretRef` and SecretRef typing helpers for secret-contract/config parsing | - | `plugin-sdk/security-runtime` | Shared trust, DM gating, external-content, and secret-collection helpers | - | `plugin-sdk/ssrf-policy` | Host allowlist and private-network SSRF policy helpers | - | `plugin-sdk/ssrf-dispatcher` | Narrow pinned-dispatcher helpers without the broad infra runtime surface | - | `plugin-sdk/ssrf-runtime` | Pinned-dispatcher, SSRF-guarded fetch, and SSRF policy helpers | - | `plugin-sdk/secret-input` | Secret input parsing helpers | - | `plugin-sdk/webhook-ingress` | Webhook request/target helpers | - | `plugin-sdk/webhook-request-guards` | Request body size/timeout helpers | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/runtime` | Broad runtime/logging/backup/plugin-install helpers | - | `plugin-sdk/runtime-env` | Narrow runtime env, logger, timeout, retry, and backoff helpers | - | `plugin-sdk/channel-runtime-context` | Generic channel runtime-context registration and lookup helpers | - | `plugin-sdk/runtime-store` | `createPluginRuntimeStore` | - | `plugin-sdk/plugin-runtime` | Shared plugin command/hook/http/interactive helpers | - | `plugin-sdk/hook-runtime` | Shared webhook/internal hook pipeline helpers | - | `plugin-sdk/lazy-runtime` | Lazy runtime import/binding helpers such as `createLazyRuntimeModule`, `createLazyRuntimeMethod`, and `createLazyRuntimeSurface` | - | `plugin-sdk/process-runtime` | Process exec helpers | - | `plugin-sdk/cli-runtime` | CLI formatting, wait, and version helpers | - | `plugin-sdk/gateway-runtime` | Gateway client and channel-status patch helpers | - | `plugin-sdk/config-runtime` | Config load/write helpers and plugin-config lookup helpers | - | `plugin-sdk/telegram-command-config` | Telegram command-name/description normalization and duplicate/conflict checks, even when the bundled Telegram contract surface is unavailable | - | `plugin-sdk/text-autolink-runtime` | File-reference autolink detection without the broad text-runtime barrel | - | `plugin-sdk/approval-runtime` | Exec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers | - | `plugin-sdk/reply-runtime` | Shared inbound/reply runtime helpers, chunking, dispatch, heartbeat, reply planner | - | `plugin-sdk/reply-dispatch-runtime` | Narrow reply dispatch/finalize helpers | - | `plugin-sdk/reply-history` | Shared short-window reply-history helpers such as `buildHistoryContext`, `recordPendingHistoryEntry`, and `clearHistoryEntriesIfEnabled` | - | `plugin-sdk/reply-reference` | `createReplyReferencePlanner` | - | `plugin-sdk/reply-chunking` | Narrow text/markdown chunking helpers | - | `plugin-sdk/session-store-runtime` | Session store path + updated-at helpers | - | `plugin-sdk/state-paths` | State/OAuth dir path helpers | - | `plugin-sdk/routing` | Route/session-key/account binding helpers such as `resolveAgentRoute`, `buildAgentSessionKey`, and `resolveDefaultAgentBoundAccountId` | - | `plugin-sdk/status-helpers` | Shared channel/account status summary helpers, runtime-state defaults, and issue metadata helpers | - | `plugin-sdk/target-resolver-runtime` | Shared target resolver helpers | - | `plugin-sdk/string-normalization-runtime` | Slug/string normalization helpers | - | `plugin-sdk/request-url` | Extract string URLs from fetch/request-like inputs | - | `plugin-sdk/run-command` | Timed command runner with normalized stdout/stderr results | - | `plugin-sdk/param-readers` | Common tool/CLI param readers | - | `plugin-sdk/tool-payload` | Extract normalized payloads from tool result objects | - | `plugin-sdk/tool-send` | Extract canonical send target fields from tool args | - | `plugin-sdk/temp-path` | Shared temp-download path helpers | - | `plugin-sdk/logging-core` | Subsystem logger and redaction helpers | - | `plugin-sdk/markdown-table-runtime` | Markdown table mode helpers | - | `plugin-sdk/json-store` | Small JSON state read/write helpers | - | `plugin-sdk/file-lock` | Re-entrant file-lock helpers | - | `plugin-sdk/persistent-dedupe` | Disk-backed dedupe cache helpers | - | `plugin-sdk/acp-runtime` | ACP runtime/session and reply-dispatch helpers | - | `plugin-sdk/acp-binding-resolve-runtime` | Read-only ACP binding resolution without lifecycle startup imports | - | `plugin-sdk/agent-config-primitives` | Narrow agent runtime config-schema primitives | - | `plugin-sdk/boolean-param` | Loose boolean param reader | - | `plugin-sdk/dangerous-name-runtime` | Dangerous-name matching resolution helpers | - | `plugin-sdk/device-bootstrap` | Device bootstrap and pairing token helpers | - | `plugin-sdk/extension-shared` | Shared passive-channel, status, and ambient proxy helper primitives | - | `plugin-sdk/models-provider-runtime` | `/models` command/provider reply helpers | - | `plugin-sdk/skill-commands-runtime` | Skill command listing helpers | - | `plugin-sdk/native-command-registry` | Native command registry/build/serialize helpers | - | `plugin-sdk/agent-harness` | Experimental trusted-plugin surface for low-level agent harnesses: harness types, active-run steer/abort helpers, OpenClaw tool bridge helpers, and attempt result utilities | - | `plugin-sdk/provider-zai-endpoint` | Z.AI endpoint detection helpers | - | `plugin-sdk/infra-runtime` | System event/heartbeat helpers | - | `plugin-sdk/collection-runtime` | Small bounded cache helpers | - | `plugin-sdk/diagnostic-runtime` | Diagnostic flag and event helpers | - | `plugin-sdk/error-runtime` | Error graph, formatting, shared error classification helpers, `isApprovalNotFoundError` | - | `plugin-sdk/fetch-runtime` | Wrapped fetch, proxy, and pinned lookup helpers | - | `plugin-sdk/runtime-fetch` | Dispatcher-aware runtime fetch without proxy/guarded-fetch imports | - | `plugin-sdk/response-limit-runtime` | Bounded response-body reader without the broad media runtime surface | - | `plugin-sdk/session-binding-runtime` | Current conversation binding state without configured binding routing or pairing stores | - | `plugin-sdk/session-store-runtime` | Session-store read helpers without broad config writes/maintenance imports | - | `plugin-sdk/context-visibility-runtime` | Context visibility resolution and supplemental context filtering without broad config/security imports | - | `plugin-sdk/string-coerce-runtime` | Narrow primitive record/string coercion and normalization helpers without markdown/logging imports | - | `plugin-sdk/host-runtime` | Hostname and SCP host normalization helpers | - | `plugin-sdk/retry-runtime` | Retry config and retry runner helpers | - | `plugin-sdk/agent-runtime` | Agent dir/identity/workspace helpers | - | `plugin-sdk/directory-runtime` | Config-backed directory query/dedup | - | `plugin-sdk/keyed-async-queue` | `KeyedAsyncQueue` | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/media-runtime` | Shared media fetch/transform/store helpers plus media payload builders | - | `plugin-sdk/media-generation-runtime` | Shared media-generation failover helpers, candidate selection, and missing-model messaging | - | `plugin-sdk/media-understanding` | Media understanding provider types plus provider-facing image/audio helper exports | - | `plugin-sdk/text-runtime` | Shared text/markdown/logging helpers such as assistant-visible-text stripping, markdown render/chunking/table helpers, redaction helpers, directive-tag helpers, and safe-text utilities | - | `plugin-sdk/text-chunking` | Outbound text chunking helper | - | `plugin-sdk/speech` | Speech provider types plus provider-facing directive, registry, and validation helpers | - | `plugin-sdk/speech-core` | Shared speech provider types, registry, directive, and normalization helpers | - | `plugin-sdk/realtime-transcription` | Realtime transcription provider types, registry helpers, and shared WebSocket session helper | - | `plugin-sdk/realtime-voice` | Realtime voice provider types and registry helpers | - | `plugin-sdk/image-generation` | Image generation provider types | - | `plugin-sdk/image-generation-core` | Shared image-generation types, failover, auth, and registry helpers | - | `plugin-sdk/music-generation` | Music generation provider/request/result types | - | `plugin-sdk/music-generation-core` | Shared music-generation types, failover helpers, provider lookup, and model-ref parsing | - | `plugin-sdk/video-generation` | Video generation provider/request/result types | - | `plugin-sdk/video-generation-core` | Shared video-generation types, failover helpers, provider lookup, and model-ref parsing | - | `plugin-sdk/webhook-targets` | Webhook target registry and route-install helpers | - | `plugin-sdk/webhook-path` | Webhook path normalization helpers | - | `plugin-sdk/web-media` | Shared remote/local media loading helpers | - | `plugin-sdk/zod` | Re-exported `zod` for plugin SDK consumers | - | `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`, `shouldAckReaction` | - - - - | Subpath | Key exports | - | --- | --- | - | `plugin-sdk/memory-core` | Bundled memory-core helper surface for manager/config/file/CLI helpers | - | `plugin-sdk/memory-core-engine-runtime` | Memory index/search runtime facade | - | `plugin-sdk/memory-core-host-engine-foundation` | Memory host foundation engine exports | - | `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding contracts, registry access, local provider, and generic batch/remote helpers | - | `plugin-sdk/memory-core-host-engine-qmd` | Memory host QMD engine exports | - | `plugin-sdk/memory-core-host-engine-storage` | Memory host storage engine exports | - | `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal helpers | - | `plugin-sdk/memory-core-host-query` | Memory host query helpers | - | `plugin-sdk/memory-core-host-secret` | Memory host secret helpers | - | `plugin-sdk/memory-core-host-events` | Memory host event journal helpers | - | `plugin-sdk/memory-core-host-status` | Memory host status helpers | - | `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI runtime helpers | - | `plugin-sdk/memory-core-host-runtime-core` | Memory host core runtime helpers | - | `plugin-sdk/memory-core-host-runtime-files` | Memory host file/runtime helpers | - | `plugin-sdk/memory-host-core` | Vendor-neutral alias for memory host core runtime helpers | - | `plugin-sdk/memory-host-events` | Vendor-neutral alias for memory host event journal helpers | - | `plugin-sdk/memory-host-files` | Vendor-neutral alias for memory host file/runtime helpers | - | `plugin-sdk/memory-host-markdown` | Shared managed-markdown helpers for memory-adjacent plugins | - | `plugin-sdk/memory-host-search` | Active memory runtime facade for search-manager access | - | `plugin-sdk/memory-host-status` | Vendor-neutral alias for memory host status helpers | - | `plugin-sdk/memory-lancedb` | Bundled memory-lancedb helper surface | - - - - | Family | Current subpaths | Intended use | - | --- | --- | --- | - | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | Bundled browser plugin support helpers (`browser-support` remains the compatibility barrel) | - | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | Bundled Matrix helper/runtime surface | - | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | Bundled LINE helper/runtime surface | - | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | Bundled IRC helper surface | - | Channel-specific helpers | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | Bundled channel compatibility/helper seams | - | Auth/plugin-specific helpers | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | Bundled feature/plugin helper seams; `plugin-sdk/github-copilot-token` currently exports `DEFAULT_COPILOT_API_BASE_URL`, `deriveCopilotApiBaseUrlFromToken`, and `resolveCopilotApiToken` | - - +The generated list of 200+ subpaths lives in `scripts/lib/plugin-sdk-entrypoints.json`. ## Registration API diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md new file mode 100644 index 000000000..41963a195 --- /dev/null +++ b/docs/plugins/sdk-subpaths.md @@ -0,0 +1,273 @@ +--- +summary: "Plugin SDK subpath catalog: which imports live where, grouped by area" +read_when: + - Choosing the right plugin-sdk subpath for a plugin import + - Auditing bundled-plugin subpaths and helper surfaces +title: "Plugin SDK subpaths" +--- + +The plugin SDK is exposed as a set of narrow subpaths under `openclaw/plugin-sdk/`. +This page catalogs the commonly used subpaths grouped by purpose. The generated +full list of 200+ subpaths lives in `scripts/lib/plugin-sdk-entrypoints.json`; +reserved bundled-plugin helper subpaths appear there but are implementation +detail unless a doc page explicitly promotes them. + +For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview). + +### Plugin entry + +| Subpath | Key exports | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `plugin-sdk/plugin-entry` | `definePluginEntry` | +| `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` | +| `plugin-sdk/config-schema` | `OpenClawSchema` | +| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/channel-core` | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` | + | `plugin-sdk/config-schema` | Root `openclaw.json` Zod schema export (`OpenClawSchema`) | + | `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`, plus `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` | + | `plugin-sdk/setup` | Shared setup wizard helpers, allowlist prompts, setup status builders | + | `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` | + | `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` | + | `plugin-sdk/setup-tools` | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` | + | `plugin-sdk/account-core` | Multi-account config/action-gate helpers, default-account fallback helpers | + | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`, account-id normalization helpers | + | `plugin-sdk/account-resolution` | Account lookup + default-fallback helpers | + | `plugin-sdk/account-helpers` | Narrow account-list/account-action helpers | + | `plugin-sdk/channel-pairing` | `createChannelPairingController` | + | `plugin-sdk/channel-reply-pipeline` | `createChannelReplyPipeline` | + | `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` | + | `plugin-sdk/channel-config-schema` | Channel config schema types | + | `plugin-sdk/telegram-command-config` | Telegram custom-command normalization/validation helpers with bundled-contract fallback | + | `plugin-sdk/command-gating` | Narrow command authorization gate helpers | + | `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` | + | `plugin-sdk/channel-lifecycle` | `createAccountStatusSink`, draft stream lifecycle/finalization helpers | + | `plugin-sdk/inbound-envelope` | Shared inbound route + envelope builder helpers | + | `plugin-sdk/inbound-reply-dispatch` | Shared inbound record-and-dispatch helpers | + | `plugin-sdk/messaging-targets` | Target parsing/matching helpers | + | `plugin-sdk/outbound-media` | Shared outbound media loading helpers | + | `plugin-sdk/outbound-runtime` | Outbound identity, send delegate, and payload planning helpers | + | `plugin-sdk/poll-runtime` | Narrow poll normalization helpers | + | `plugin-sdk/thread-bindings-runtime` | Thread-binding lifecycle and adapter helpers | + | `plugin-sdk/agent-media-payload` | Legacy agent media payload builder | + | `plugin-sdk/conversation-runtime` | Conversation/thread binding, pairing, and configured-binding helpers | + | `plugin-sdk/runtime-config-snapshot` | Runtime config snapshot helper | + | `plugin-sdk/runtime-group-policy` | Runtime group-policy resolution helpers | + | `plugin-sdk/channel-status` | Shared channel status snapshot/summary helpers | + | `plugin-sdk/channel-config-primitives` | Narrow channel config-schema primitives | + | `plugin-sdk/channel-config-writes` | Channel config-write authorization helpers | + | `plugin-sdk/channel-plugin-common` | Shared channel plugin prelude exports | + | `plugin-sdk/allowlist-config-edit` | Allowlist config edit/read helpers | + | `plugin-sdk/group-access` | Shared group-access decision helpers | + | `plugin-sdk/direct-dm` | Shared direct-DM auth/guard helpers | + | `plugin-sdk/interactive-runtime` | Semantic message presentation, delivery, and legacy interactive reply helpers. See [Message Presentation](/plugins/message-presentation) | + | `plugin-sdk/channel-inbound` | Compatibility barrel for inbound debounce, mention matching, mention-policy helpers, and envelope helpers | + | `plugin-sdk/channel-mention-gating` | Narrow mention-policy helpers without the broader inbound runtime surface | + | `plugin-sdk/channel-location` | Channel location context and formatting helpers | + | `plugin-sdk/channel-logging` | Channel logging helpers for inbound drops and typing/ack failures | + | `plugin-sdk/channel-send-result` | Reply result types | + | `plugin-sdk/channel-actions` | Channel message-action helpers, plus deprecated native schema helpers kept for plugin compatibility | + | `plugin-sdk/channel-targets` | Target parsing/matching helpers | + | `plugin-sdk/channel-contract` | Channel contract types | + | `plugin-sdk/channel-feedback` | Feedback/reaction wiring | + | `plugin-sdk/channel-secret-runtime` | Narrow secret-contract helpers such as `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment`, and secret target types | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | + | `plugin-sdk/provider-setup` | Curated local/self-hosted provider setup helpers | + | `plugin-sdk/self-hosted-provider-setup` | Focused OpenAI-compatible self-hosted provider setup helpers | + | `plugin-sdk/cli-backend` | CLI backend defaults + watchdog constants | + | `plugin-sdk/provider-auth-runtime` | Runtime API-key resolution helpers for provider plugins | + | `plugin-sdk/provider-auth-api-key` | API-key onboarding/profile-write helpers such as `upsertApiKeyProfile` | + | `plugin-sdk/provider-auth-result` | Standard OAuth auth-result builder | + | `plugin-sdk/provider-auth-login` | Shared interactive login helpers for provider plugins | + | `plugin-sdk/provider-env-vars` | Provider auth env-var lookup helpers | + | `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`, `ensureApiKeyFromOptionEnvOrPrompt`, `upsertAuthProfile`, `upsertApiKeyProfile`, `writeOAuthCredentials` | + | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`, shared replay-policy builders, provider-endpoint helpers, and model-id normalization helpers such as `normalizeNativeXaiModelId` | + | `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`, `buildSingleProviderApiKeyCatalog`, `supportsNativeStreamingUsageCompat`, `applyProviderNativeStreamingUsageCompat` | + | `plugin-sdk/provider-http` | Generic provider HTTP/endpoint capability helpers, including audio transcription multipart form helpers | + | `plugin-sdk/provider-web-fetch-contract` | Narrow web-fetch config/selection contract helpers such as `enablePluginInConfig` and `WebFetchProviderPlugin` | + | `plugin-sdk/provider-web-fetch` | Web-fetch provider registration/cache helpers | + | `plugin-sdk/provider-web-search-config-contract` | Narrow web-search config/credential helpers for providers that do not need plugin-enable wiring | + | `plugin-sdk/provider-web-search-contract` | Narrow web-search config/credential contract helpers such as `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`, and scoped credential setters/getters | + | `plugin-sdk/provider-web-search` | Web-search provider registration/cache/runtime helpers | + | `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`, `buildProviderToolCompatFamilyHooks`, Gemini schema cleanup + diagnostics, and xAI compat helpers such as `resolveXaiModelCompatPatch` / `applyXaiModelCompat` | + | `plugin-sdk/provider-usage` | `fetchClaudeUsage` and similar | + | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`, stream wrapper types, and shared Anthropic/Bedrock/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot wrapper helpers | + | `plugin-sdk/provider-transport-runtime` | Native provider transport helpers such as guarded fetch, transport message transforms, and writable transport event streams | + | `plugin-sdk/provider-onboard` | Onboarding config patch helpers | + | `plugin-sdk/global-singleton` | Process-local singleton/map/cache helpers | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/command-auth` | `resolveControlCommandGate`, command registry helpers, sender-authorization helpers | + | `plugin-sdk/command-status` | Command/help message builders such as `buildCommandsMessagePaginated` and `buildHelpMessage` | + | `plugin-sdk/approval-auth-runtime` | Approver resolution and same-chat action-auth helpers | + | `plugin-sdk/approval-client-runtime` | Native exec approval profile/filter helpers | + | `plugin-sdk/approval-delivery-runtime` | Native approval capability/delivery adapters | + | `plugin-sdk/approval-gateway-runtime` | Shared approval gateway-resolution helper | + | `plugin-sdk/approval-handler-adapter-runtime` | Lightweight native approval adapter loading helpers for hot channel entrypoints | + | `plugin-sdk/approval-handler-runtime` | Broader approval handler runtime helpers; prefer the narrower adapter/gateway seams when they are enough | + | `plugin-sdk/approval-native-runtime` | Native approval target + account-binding helpers | + | `plugin-sdk/approval-reply-runtime` | Exec/plugin approval reply payload helpers | + | `plugin-sdk/command-auth-native` | Native command auth + native session-target helpers | + | `plugin-sdk/command-detection` | Shared command detection helpers | + | `plugin-sdk/command-surface` | Command-body normalization and command-surface helpers | + | `plugin-sdk/allow-from` | `formatAllowFromLowercase` | + | `plugin-sdk/channel-secret-runtime` | Narrow secret-contract collection helpers for channel/plugin secret surfaces | + | `plugin-sdk/secret-ref-runtime` | Narrow `coerceSecretRef` and SecretRef typing helpers for secret-contract/config parsing | + | `plugin-sdk/security-runtime` | Shared trust, DM gating, external-content, and secret-collection helpers | + | `plugin-sdk/ssrf-policy` | Host allowlist and private-network SSRF policy helpers | + | `plugin-sdk/ssrf-dispatcher` | Narrow pinned-dispatcher helpers without the broad infra runtime surface | + | `plugin-sdk/ssrf-runtime` | Pinned-dispatcher, SSRF-guarded fetch, and SSRF policy helpers | + | `plugin-sdk/secret-input` | Secret input parsing helpers | + | `plugin-sdk/webhook-ingress` | Webhook request/target helpers | + | `plugin-sdk/webhook-request-guards` | Request body size/timeout helpers | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/runtime` | Broad runtime/logging/backup/plugin-install helpers | + | `plugin-sdk/runtime-env` | Narrow runtime env, logger, timeout, retry, and backoff helpers | + | `plugin-sdk/channel-runtime-context` | Generic channel runtime-context registration and lookup helpers | + | `plugin-sdk/runtime-store` | `createPluginRuntimeStore` | + | `plugin-sdk/plugin-runtime` | Shared plugin command/hook/http/interactive helpers | + | `plugin-sdk/hook-runtime` | Shared webhook/internal hook pipeline helpers | + | `plugin-sdk/lazy-runtime` | Lazy runtime import/binding helpers such as `createLazyRuntimeModule`, `createLazyRuntimeMethod`, and `createLazyRuntimeSurface` | + | `plugin-sdk/process-runtime` | Process exec helpers | + | `plugin-sdk/cli-runtime` | CLI formatting, wait, and version helpers | + | `plugin-sdk/gateway-runtime` | Gateway client and channel-status patch helpers | + | `plugin-sdk/config-runtime` | Config load/write helpers and plugin-config lookup helpers | + | `plugin-sdk/telegram-command-config` | Telegram command-name/description normalization and duplicate/conflict checks, even when the bundled Telegram contract surface is unavailable | + | `plugin-sdk/text-autolink-runtime` | File-reference autolink detection without the broad text-runtime barrel | + | `plugin-sdk/approval-runtime` | Exec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers | + | `plugin-sdk/reply-runtime` | Shared inbound/reply runtime helpers, chunking, dispatch, heartbeat, reply planner | + | `plugin-sdk/reply-dispatch-runtime` | Narrow reply dispatch/finalize helpers | + | `plugin-sdk/reply-history` | Shared short-window reply-history helpers such as `buildHistoryContext`, `recordPendingHistoryEntry`, and `clearHistoryEntriesIfEnabled` | + | `plugin-sdk/reply-reference` | `createReplyReferencePlanner` | + | `plugin-sdk/reply-chunking` | Narrow text/markdown chunking helpers | + | `plugin-sdk/session-store-runtime` | Session store path + updated-at helpers | + | `plugin-sdk/state-paths` | State/OAuth dir path helpers | + | `plugin-sdk/routing` | Route/session-key/account binding helpers such as `resolveAgentRoute`, `buildAgentSessionKey`, and `resolveDefaultAgentBoundAccountId` | + | `plugin-sdk/status-helpers` | Shared channel/account status summary helpers, runtime-state defaults, and issue metadata helpers | + | `plugin-sdk/target-resolver-runtime` | Shared target resolver helpers | + | `plugin-sdk/string-normalization-runtime` | Slug/string normalization helpers | + | `plugin-sdk/request-url` | Extract string URLs from fetch/request-like inputs | + | `plugin-sdk/run-command` | Timed command runner with normalized stdout/stderr results | + | `plugin-sdk/param-readers` | Common tool/CLI param readers | + | `plugin-sdk/tool-payload` | Extract normalized payloads from tool result objects | + | `plugin-sdk/tool-send` | Extract canonical send target fields from tool args | + | `plugin-sdk/temp-path` | Shared temp-download path helpers | + | `plugin-sdk/logging-core` | Subsystem logger and redaction helpers | + | `plugin-sdk/markdown-table-runtime` | Markdown table mode helpers | + | `plugin-sdk/json-store` | Small JSON state read/write helpers | + | `plugin-sdk/file-lock` | Re-entrant file-lock helpers | + | `plugin-sdk/persistent-dedupe` | Disk-backed dedupe cache helpers | + | `plugin-sdk/acp-runtime` | ACP runtime/session and reply-dispatch helpers | + | `plugin-sdk/acp-binding-resolve-runtime` | Read-only ACP binding resolution without lifecycle startup imports | + | `plugin-sdk/agent-config-primitives` | Narrow agent runtime config-schema primitives | + | `plugin-sdk/boolean-param` | Loose boolean param reader | + | `plugin-sdk/dangerous-name-runtime` | Dangerous-name matching resolution helpers | + | `plugin-sdk/device-bootstrap` | Device bootstrap and pairing token helpers | + | `plugin-sdk/extension-shared` | Shared passive-channel, status, and ambient proxy helper primitives | + | `plugin-sdk/models-provider-runtime` | `/models` command/provider reply helpers | + | `plugin-sdk/skill-commands-runtime` | Skill command listing helpers | + | `plugin-sdk/native-command-registry` | Native command registry/build/serialize helpers | + | `plugin-sdk/agent-harness` | Experimental trusted-plugin surface for low-level agent harnesses: harness types, active-run steer/abort helpers, OpenClaw tool bridge helpers, and attempt result utilities | + | `plugin-sdk/provider-zai-endpoint` | Z.AI endpoint detection helpers | + | `plugin-sdk/infra-runtime` | System event/heartbeat helpers | + | `plugin-sdk/collection-runtime` | Small bounded cache helpers | + | `plugin-sdk/diagnostic-runtime` | Diagnostic flag and event helpers | + | `plugin-sdk/error-runtime` | Error graph, formatting, shared error classification helpers, `isApprovalNotFoundError` | + | `plugin-sdk/fetch-runtime` | Wrapped fetch, proxy, and pinned lookup helpers | + | `plugin-sdk/runtime-fetch` | Dispatcher-aware runtime fetch without proxy/guarded-fetch imports | + | `plugin-sdk/response-limit-runtime` | Bounded response-body reader without the broad media runtime surface | + | `plugin-sdk/session-binding-runtime` | Current conversation binding state without configured binding routing or pairing stores | + | `plugin-sdk/session-store-runtime` | Session-store read helpers without broad config writes/maintenance imports | + | `plugin-sdk/context-visibility-runtime` | Context visibility resolution and supplemental context filtering without broad config/security imports | + | `plugin-sdk/string-coerce-runtime` | Narrow primitive record/string coercion and normalization helpers without markdown/logging imports | + | `plugin-sdk/host-runtime` | Hostname and SCP host normalization helpers | + | `plugin-sdk/retry-runtime` | Retry config and retry runner helpers | + | `plugin-sdk/agent-runtime` | Agent dir/identity/workspace helpers | + | `plugin-sdk/directory-runtime` | Config-backed directory query/dedup | + | `plugin-sdk/keyed-async-queue` | `KeyedAsyncQueue` | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/media-runtime` | Shared media fetch/transform/store helpers plus media payload builders | + | `plugin-sdk/media-generation-runtime` | Shared media-generation failover helpers, candidate selection, and missing-model messaging | + | `plugin-sdk/media-understanding` | Media understanding provider types plus provider-facing image/audio helper exports | + | `plugin-sdk/text-runtime` | Shared text/markdown/logging helpers such as assistant-visible-text stripping, markdown render/chunking/table helpers, redaction helpers, directive-tag helpers, and safe-text utilities | + | `plugin-sdk/text-chunking` | Outbound text chunking helper | + | `plugin-sdk/speech` | Speech provider types plus provider-facing directive, registry, and validation helpers | + | `plugin-sdk/speech-core` | Shared speech provider types, registry, directive, and normalization helpers | + | `plugin-sdk/realtime-transcription` | Realtime transcription provider types, registry helpers, and shared WebSocket session helper | + | `plugin-sdk/realtime-voice` | Realtime voice provider types and registry helpers | + | `plugin-sdk/image-generation` | Image generation provider types | + | `plugin-sdk/image-generation-core` | Shared image-generation types, failover, auth, and registry helpers | + | `plugin-sdk/music-generation` | Music generation provider/request/result types | + | `plugin-sdk/music-generation-core` | Shared music-generation types, failover helpers, provider lookup, and model-ref parsing | + | `plugin-sdk/video-generation` | Video generation provider/request/result types | + | `plugin-sdk/video-generation-core` | Shared video-generation types, failover helpers, provider lookup, and model-ref parsing | + | `plugin-sdk/webhook-targets` | Webhook target registry and route-install helpers | + | `plugin-sdk/webhook-path` | Webhook path normalization helpers | + | `plugin-sdk/web-media` | Shared remote/local media loading helpers | + | `plugin-sdk/zod` | Re-exported `zod` for plugin SDK consumers | + | `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`, `shouldAckReaction` | + + + + | Subpath | Key exports | + | --- | --- | + | `plugin-sdk/memory-core` | Bundled memory-core helper surface for manager/config/file/CLI helpers | + | `plugin-sdk/memory-core-engine-runtime` | Memory index/search runtime facade | + | `plugin-sdk/memory-core-host-engine-foundation` | Memory host foundation engine exports | + | `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding contracts, registry access, local provider, and generic batch/remote helpers | + | `plugin-sdk/memory-core-host-engine-qmd` | Memory host QMD engine exports | + | `plugin-sdk/memory-core-host-engine-storage` | Memory host storage engine exports | + | `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal helpers | + | `plugin-sdk/memory-core-host-query` | Memory host query helpers | + | `plugin-sdk/memory-core-host-secret` | Memory host secret helpers | + | `plugin-sdk/memory-core-host-events` | Memory host event journal helpers | + | `plugin-sdk/memory-core-host-status` | Memory host status helpers | + | `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI runtime helpers | + | `plugin-sdk/memory-core-host-runtime-core` | Memory host core runtime helpers | + | `plugin-sdk/memory-core-host-runtime-files` | Memory host file/runtime helpers | + | `plugin-sdk/memory-host-core` | Vendor-neutral alias for memory host core runtime helpers | + | `plugin-sdk/memory-host-events` | Vendor-neutral alias for memory host event journal helpers | + | `plugin-sdk/memory-host-files` | Vendor-neutral alias for memory host file/runtime helpers | + | `plugin-sdk/memory-host-markdown` | Shared managed-markdown helpers for memory-adjacent plugins | + | `plugin-sdk/memory-host-search` | Active memory runtime facade for search-manager access | + | `plugin-sdk/memory-host-status` | Vendor-neutral alias for memory host status helpers | + | `plugin-sdk/memory-lancedb` | Bundled memory-lancedb helper surface | + + + + | Family | Current subpaths | Intended use | + | --- | --- | --- | + | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | Bundled browser plugin support helpers (`browser-support` remains the compatibility barrel) | + | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | Bundled Matrix helper/runtime surface | + | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | Bundled LINE helper/runtime surface | + | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | Bundled IRC helper surface | + | Channel-specific helpers | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | Bundled channel compatibility/helper seams | + | Auth/plugin-specific helpers | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | Bundled feature/plugin helper seams; `plugin-sdk/github-copilot-token` currently exports `DEFAULT_COPILOT_API_BASE_URL`, `deriveCopilotApiBaseUrlFromToken`, and `resolveCopilotApiToken` | + + + +## Related + +- [Plugin SDK overview](/plugins/sdk-overview) +- [Plugin SDK setup](/plugins/sdk-setup) +- [Building plugins](/plugins/building-plugins) diff --git a/docs/tools/exec-approvals-advanced.md b/docs/tools/exec-approvals-advanced.md new file mode 100644 index 000000000..be35aaed2 --- /dev/null +++ b/docs/tools/exec-approvals-advanced.md @@ -0,0 +1,342 @@ +--- +summary: "Advanced exec approvals: safe bins, interpreter binding, approval forwarding, native delivery" +read_when: + - Configuring safe bins or custom safe-bin profiles + - Forwarding approvals to Slack/Discord/Telegram or other chat channels + - Implementing a native approval client for a channel +title: "Exec approvals — advanced" +--- + +Advanced exec-approval topics: the `safeBins` fast-path, interpreter/runtime +binding, and approval-forwarding to chat channels (including native delivery). +For the core policy and approval flow, see [Exec approvals](/tools/exec-approvals). + +## Safe bins (stdin-only) + +`tools.exec.safeBins` defines a small list of **stdin-only** binaries (for +example `cut`) that can run in allowlist mode **without** explicit allowlist +entries. Safe bins reject positional file args and path-like tokens, so they +can only operate on the incoming stream. Treat this as a narrow fast-path for +stream filters, not a general trust list. + + +Do **not** add interpreter or runtime binaries (for example `python3`, `node`, +`ruby`, `bash`, `sh`, `zsh`) to `safeBins`. If a command can evaluate code, +execute subcommands, or read files by design, prefer explicit allowlist entries +and keep approval prompts enabled. Custom safe bins must define an explicit +profile in `tools.exec.safeBinProfiles.`. + + +Default safe bins: + +[//]: # "SAFE_BIN_DEFAULTS:START" + +`cut`, `uniq`, `head`, `tail`, `tr`, `wc` + +[//]: # "SAFE_BIN_DEFAULTS:END" + +`grep` and `sort` are not in the default list. If you opt in, keep explicit +allowlist entries for their non-stdin workflows. For `grep` in safe-bin mode, +provide the pattern with `-e`/`--regexp`; positional pattern form is rejected +so file operands cannot be smuggled as ambiguous positionals. + +### Argv validation and denied flags + +Validation is deterministic from argv shape only (no host filesystem existence +checks), which prevents file-existence oracle behavior from allow/deny +differences. File-oriented options are denied for default safe bins; long +options are validated fail-closed (unknown flags and ambiguous abbreviations are +rejected). + +Denied flags by safe-bin profile: + +[//]: # "SAFE_BIN_DENIED_FLAGS:START" + +- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r` +- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f` +- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o` +- `wc`: `--files0-from` + +[//]: # "SAFE_BIN_DENIED_FLAGS:END" + +Safe bins also force argv tokens to be treated as **literal text** at execution +time (no globbing and no `$VARS` expansion) for stdin-only segments, so patterns +like `*` or `$HOME/...` cannot be used to smuggle file reads. + +### Trusted binary directories + +Safe bins must resolve from trusted binary directories (system defaults plus +optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted. +Default trusted directories are intentionally minimal: `/bin`, `/usr/bin`. If +your safe-bin executable lives in package-manager/user paths (for example +`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them +explicitly to `tools.exec.safeBinTrustedDirs`. + +### Shell chaining, wrappers, and multiplexers + +Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment +satisfies the allowlist (including safe bins or skill auto-allow). Redirections +remain unsupported in allowlist mode. Command substitution (`$()` / backticks) is +rejected during allowlist parsing, including inside double quotes; use single +quotes if you need literal `$()` text. + +On macOS companion-app approvals, raw shell text containing shell control or +expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is +treated as an allowlist miss unless the shell binary itself is allowlisted. + +For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are +reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, +`NO_COLOR`, `FORCE_COLOR`). + +For `allow-always` decisions in allowlist mode, known dispatch wrappers (`env`, +`nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable path instead +of the wrapper path. Shell multiplexers (`busybox`, `toybox`) are unwrapped for +shell applets (`sh`, `ash`, etc.) the same way. If a wrapper or multiplexer +cannot be safely unwrapped, no allowlist entry is persisted automatically. + +If you allowlist interpreters like `python3` or `node`, prefer +`tools.exec.strictInlineEval=true` so inline eval still requires an explicit +approval. In strict mode, `allow-always` can still persist benign +interpreter/script invocations, but inline-eval carriers are not persisted +automatically. + +### Safe bins versus allowlist + +| Topic | `tools.exec.safeBins` | Allowlist (`exec-approvals.json`) | +| ---------------- | ------------------------------------------------------ | ------------------------------------------------------------ | +| Goal | Auto-allow narrow stdin filters | Explicitly trust specific executables | +| Match type | Executable name + safe-bin argv policy | Resolved executable path glob pattern | +| Argument scope | Restricted by safe-bin profile and literal-token rules | Path match only; arguments are otherwise your responsibility | +| Typical examples | `head`, `tail`, `tr`, `wc` | `jq`, `python3`, `node`, `ffmpeg`, custom CLIs | +| Best use | Low-risk text transforms in pipelines | Any tool with broader behavior or side effects | + +Configuration location: + +- `safeBins` comes from config (`tools.exec.safeBins` or per-agent `agents.list[].tools.exec.safeBins`). +- `safeBinTrustedDirs` comes from config (`tools.exec.safeBinTrustedDirs` or per-agent `agents.list[].tools.exec.safeBinTrustedDirs`). +- `safeBinProfiles` comes from config (`tools.exec.safeBinProfiles` or per-agent `agents.list[].tools.exec.safeBinProfiles`). Per-agent profile keys override global keys. +- allowlist entries live in host-local `~/.openclaw/exec-approvals.json` under `agents..allowlist` (or via Control UI / `openclaw approvals allowlist ...`). +- `openclaw security audit` warns with `tools.exec.safe_bins_interpreter_unprofiled` when interpreter/runtime bins appear in `safeBins` without explicit profiles. +- `openclaw doctor --fix` can scaffold missing custom `safeBinProfiles.` entries as `{}` (review and tighten afterward). Interpreter/runtime bins are not auto-scaffolded. + +Custom profile example: + +```json5 +{ + tools: { + exec: { + safeBins: ["jq", "myfilter"], + safeBinProfiles: { + myfilter: { + minPositional: 0, + maxPositional: 0, + allowedValueFlags: ["-n", "--limit"], + deniedFlags: ["-f", "--file", "-c", "--command"], + }, + }, + }, + }, +} +``` + +If you explicitly opt `jq` into `safeBins`, OpenClaw still rejects the `env` builtin in safe-bin +mode so `jq -n env` cannot dump the host process environment without an explicit allowlist path +or approval prompt. + +## Interpreter/runtime commands + +Approval-backed interpreter/runtime runs are intentionally conservative: + +- Exact argv/cwd/env context is always bound. +- Direct shell script and direct runtime file forms are best-effort bound to one concrete local + file snapshot. +- Common package-manager wrapper forms that still resolve to one direct local file (for example + `pnpm exec`, `pnpm node`, `npm exec`, `npx`) are unwrapped before binding. +- If OpenClaw cannot identify exactly one concrete local file for an interpreter/runtime command + (for example package scripts, eval forms, runtime-specific loader chains, or ambiguous multi-file + forms), approval-backed execution is denied instead of claiming semantic coverage it does not + have. +- For those workflows, prefer sandboxing, a separate host boundary, or an explicit trusted + allowlist/full workflow where the operator accepts the broader runtime semantics. + +When approvals are required, the exec tool returns immediately with an approval id. Use that id to +correlate later system events (`Exec finished` / `Exec denied`). If no decision arrives before the +timeout, the request is treated as an approval timeout and surfaced as a denial reason. + +### Followup delivery behavior + +After an approved async exec finishes, OpenClaw sends a followup `agent` turn to the same session. + +- If a valid external delivery target exists (deliverable channel plus target `to`), followup delivery uses that channel. +- In webchat-only or internal-session flows with no external target, followup delivery stays session-only (`deliver: false`). +- If a caller explicitly requests strict external delivery with no resolvable external channel, the request fails with `INVALID_REQUEST`. +- If `bestEffortDeliver` is enabled and no external channel can be resolved, delivery is downgraded to session-only instead of failing. + +## Approval forwarding to chat channels + +You can forward exec approval prompts to any chat channel (including plugin channels) and approve +them with `/approve`. This uses the normal outbound delivery pipeline. + +Config: + +```json5 +{ + approvals: { + exec: { + enabled: true, + mode: "session", // "session" | "targets" | "both" + agentFilter: ["main"], + sessionFilter: ["discord"], // substring or regex + targets: [ + { channel: "slack", to: "U12345678" }, + { channel: "telegram", to: "123456789" }, + ], + }, + }, +} +``` + +Reply in chat: + +``` +/approve allow-once +/approve allow-always +/approve deny +``` + +The `/approve` command handles both exec approvals and plugin approvals. If the ID does not match a pending exec approval, it automatically checks plugin approvals instead. + +### Plugin approval forwarding + +Plugin approval forwarding uses the same delivery pipeline as exec approvals but has its own +independent config under `approvals.plugin`. Enabling or disabling one does not affect the other. + +```json5 +{ + approvals: { + plugin: { + enabled: true, + mode: "targets", + agentFilter: ["main"], + targets: [ + { channel: "slack", to: "U12345678" }, + { channel: "telegram", to: "123456789" }, + ], + }, + }, +} +``` + +The config shape is identical to `approvals.exec`: `enabled`, `mode`, `agentFilter`, +`sessionFilter`, and `targets` work the same way. + +Channels that support shared interactive replies render the same approval buttons for both exec and +plugin approvals. Channels without shared interactive UI fall back to plain text with `/approve` +instructions. + +### Same-chat approvals on any channel + +When an exec or plugin approval request originates from a deliverable chat surface, the same chat +can now approve it with `/approve` by default. This applies to channels such as Slack, Matrix, and +Microsoft Teams in addition to the existing Web UI and terminal UI flows. + +This shared text-command path uses the normal channel auth model for that conversation. If the +originating chat can already send commands and receive replies, approval requests no longer need a +separate native delivery adapter just to stay pending. + +Discord and Telegram also support same-chat `/approve`, but those channels still use their +resolved approver list for authorization even when native approval delivery is disabled. + +For Telegram and other native approval clients that call the Gateway directly, +this fallback is intentionally bounded to "approval not found" failures. A real +exec approval denial/error does not silently retry as a plugin approval. + +### Native approval delivery + +Some channels can also act as native approval clients. Native clients add approver DMs, origin-chat +fanout, and channel-specific interactive approval UX on top of the shared same-chat `/approve` +flow. + +When native approval cards/buttons are available, that native UI is the primary +agent-facing path. The agent should not also echo a duplicate plain chat +`/approve` command unless the tool result says chat approvals are unavailable or +manual approval is the only remaining path. + +Generic model: + +- host exec policy still decides whether exec approval is required +- `approvals.exec` controls forwarding approval prompts to other chat destinations +- `channels..execApprovals` controls whether that channel acts as a native approval client + +Native approval clients auto-enable DM-first delivery when all of these are true: + +- the channel supports native approval delivery +- approvers can be resolved from explicit `execApprovals.approvers` or that + channel's documented fallback sources +- `channels..execApprovals.enabled` is unset or `"auto"` + +Set `enabled: false` to disable a native approval client explicitly. Set `enabled: true` to force +it on when approvers resolve. Public origin-chat delivery stays explicit through +`channels..execApprovals.target`. + +FAQ: [Why are there two exec approval configs for chat approvals?](/help/faq#why-are-there-two-exec-approval-configs-for-chat-approvals) + +- Discord: `channels.discord.execApprovals.*` +- Slack: `channels.slack.execApprovals.*` +- Telegram: `channels.telegram.execApprovals.*` + +These native approval clients add DM routing and optional channel fanout on top of the shared +same-chat `/approve` flow and shared approval buttons. + +Shared behavior: + +- Slack, Matrix, Microsoft Teams, and similar deliverable chats use the normal channel auth model + for same-chat `/approve` +- when a native approval client auto-enables, the default native delivery target is approver DMs +- for Discord and Telegram, only resolved approvers can approve or deny +- Discord approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom` +- Telegram approvers can be explicit (`execApprovals.approvers`) or inferred from existing owner config (`allowFrom`, plus direct-message `defaultTo` where supported) +- Slack approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom` +- Slack native buttons preserve approval id kind, so `plugin:` ids can resolve plugin approvals + without a second Slack-local fallback layer +- Matrix native DM/channel routing and reaction shortcuts handle both exec and plugin approvals; + plugin authorization still comes from `channels.matrix.dm.allowFrom` +- the requester does not need to be an approver +- the originating chat can approve directly with `/approve` when that chat already supports commands and replies +- native Discord approval buttons route by approval id kind: `plugin:` ids go + straight to plugin approvals, everything else goes to exec approvals +- native Telegram approval buttons follow the same bounded exec-to-plugin fallback as `/approve` +- when native `target` enables origin-chat delivery, approval prompts include the command text +- pending exec approvals expire after 30 minutes by default +- if no operator UI or configured approval client can accept the request, the prompt falls back to `askFallback` + +Telegram defaults to approver DMs (`target: "dm"`). You can switch to `channel` or `both` when you +want approval prompts to appear in the originating Telegram chat/topic as well. For Telegram forum +topics, OpenClaw preserves the topic for the approval prompt and the post-approval follow-up. + +See: + +- [Discord](/channels/discord) +- [Telegram](/channels/telegram) + +### macOS IPC flow + +``` +Gateway -> Node Service (WS) + | IPC (UDS + token + HMAC + TTL) + v + Mac App (UI + approvals + system.run) +``` + +Security notes: + +- Unix socket mode `0600`, token stored in `exec-approvals.json`. +- Same-UID peer check. +- Challenge/response (nonce + HMAC token + request hash) + short TTL. + +## Related + +- [Exec approvals](/tools/exec-approvals) — core policy and approval flow +- [Exec tool](/tools/exec) +- [Elevated mode](/tools/elevated) +- [Skills](/tools/skills) — skill-backed auto-allow behavior diff --git a/docs/tools/exec-approvals.md b/docs/tools/exec-approvals.md index 2a7c919d1..a36925ffa 100644 --- a/docs/tools/exec-approvals.md +++ b/docs/tools/exec-approvals.md @@ -278,137 +278,13 @@ Important trust notes: - It is intended for trusted operator environments where Gateway and node are in the same trust boundary. - If you require strict explicit trust, keep `autoAllowSkills: false` and use manual path allowlist entries only. -## Safe bins (stdin-only) +## Safe bins and approval forwarding -`tools.exec.safeBins` defines a small list of **stdin-only** binaries (for -example `cut`) that can run in allowlist mode **without** explicit allowlist -entries. Safe bins reject positional file args and path-like tokens, so they -can only operate on the incoming stream. Treat this as a narrow fast-path for -stream filters, not a general trust list. +For safe bins (the stdin-only fast-path), interpreter binding details, and how +to forward approval prompts to Slack/Discord/Telegram (or run them as native +approval clients), see [Exec approvals — advanced](/tools/exec-approvals-advanced). - -Do **not** add interpreter or runtime binaries (for example `python3`, `node`, -`ruby`, `bash`, `sh`, `zsh`) to `safeBins`. If a command can evaluate code, -execute subcommands, or read files by design, prefer explicit allowlist entries -and keep approval prompts enabled. Custom safe bins must define an explicit -profile in `tools.exec.safeBinProfiles.`. - - -Default safe bins: - -[//]: # "SAFE_BIN_DEFAULTS:START" - -`cut`, `uniq`, `head`, `tail`, `tr`, `wc` - -[//]: # "SAFE_BIN_DEFAULTS:END" - -`grep` and `sort` are not in the default list. If you opt in, keep explicit -allowlist entries for their non-stdin workflows. For `grep` in safe-bin mode, -provide the pattern with `-e`/`--regexp`; positional pattern form is rejected -so file operands cannot be smuggled as ambiguous positionals. - -### Argv validation and denied flags - -Validation is deterministic from argv shape only (no host filesystem existence -checks), which prevents file-existence oracle behavior from allow/deny -differences. File-oriented options are denied for default safe bins; long -options are validated fail-closed (unknown flags and ambiguous abbreviations are -rejected). - -Denied flags by safe-bin profile: - -[//]: # "SAFE_BIN_DENIED_FLAGS:START" - -- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r` -- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f` -- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o` -- `wc`: `--files0-from` - -[//]: # "SAFE_BIN_DENIED_FLAGS:END" - -Safe bins also force argv tokens to be treated as **literal text** at execution -time (no globbing and no `$VARS` expansion) for stdin-only segments, so patterns -like `*` or `$HOME/...` cannot be used to smuggle file reads. - -### Trusted binary directories - -Safe bins must resolve from trusted binary directories (system defaults plus -optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted. -Default trusted directories are intentionally minimal: `/bin`, `/usr/bin`. If -your safe-bin executable lives in package-manager/user paths (for example -`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them -explicitly to `tools.exec.safeBinTrustedDirs`. - -### Shell chaining, wrappers, and multiplexers - -Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment -satisfies the allowlist (including safe bins or skill auto-allow). Redirections -remain unsupported in allowlist mode. Command substitution (`$()` / backticks) is -rejected during allowlist parsing, including inside double quotes; use single -quotes if you need literal `$()` text. - -On macOS companion-app approvals, raw shell text containing shell control or -expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is -treated as an allowlist miss unless the shell binary itself is allowlisted. - -For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are -reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, -`NO_COLOR`, `FORCE_COLOR`). - -For `allow-always` decisions in allowlist mode, known dispatch wrappers (`env`, -`nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable path instead -of the wrapper path. Shell multiplexers (`busybox`, `toybox`) are unwrapped for -shell applets (`sh`, `ash`, etc.) the same way. If a wrapper or multiplexer -cannot be safely unwrapped, no allowlist entry is persisted automatically. - -If you allowlist interpreters like `python3` or `node`, prefer -`tools.exec.strictInlineEval=true` so inline eval still requires an explicit -approval. In strict mode, `allow-always` can still persist benign -interpreter/script invocations, but inline-eval carriers are not persisted -automatically. - -### Safe bins versus allowlist - -| Topic | `tools.exec.safeBins` | Allowlist (`exec-approvals.json`) | -| ---------------- | ------------------------------------------------------ | ------------------------------------------------------------ | -| Goal | Auto-allow narrow stdin filters | Explicitly trust specific executables | -| Match type | Executable name + safe-bin argv policy | Resolved executable path glob pattern | -| Argument scope | Restricted by safe-bin profile and literal-token rules | Path match only; arguments are otherwise your responsibility | -| Typical examples | `head`, `tail`, `tr`, `wc` | `jq`, `python3`, `node`, `ffmpeg`, custom CLIs | -| Best use | Low-risk text transforms in pipelines | Any tool with broader behavior or side effects | - -Configuration location: - -- `safeBins` comes from config (`tools.exec.safeBins` or per-agent `agents.list[].tools.exec.safeBins`). -- `safeBinTrustedDirs` comes from config (`tools.exec.safeBinTrustedDirs` or per-agent `agents.list[].tools.exec.safeBinTrustedDirs`). -- `safeBinProfiles` comes from config (`tools.exec.safeBinProfiles` or per-agent `agents.list[].tools.exec.safeBinProfiles`). Per-agent profile keys override global keys. -- allowlist entries live in host-local `~/.openclaw/exec-approvals.json` under `agents..allowlist` (or via Control UI / `openclaw approvals allowlist ...`). -- `openclaw security audit` warns with `tools.exec.safe_bins_interpreter_unprofiled` when interpreter/runtime bins appear in `safeBins` without explicit profiles. -- `openclaw doctor --fix` can scaffold missing custom `safeBinProfiles.` entries as `{}` (review and tighten afterward). Interpreter/runtime bins are not auto-scaffolded. - -Custom profile example: - -```json5 -{ - tools: { - exec: { - safeBins: ["jq", "myfilter"], - safeBinProfiles: { - myfilter: { - minPositional: 0, - maxPositional: 0, - allowedValueFlags: ["-n", "--limit"], - deniedFlags: ["-f", "--file", "-c", "--command"], - }, - }, - }, - }, -} -``` - -If you explicitly opt `jq` into `safeBins`, OpenClaw still rejects the `env` builtin in safe-bin -mode so `jq -n env` cannot dump the host process environment without an explicit allowlist path -or approval prompt. + ## Control UI editing @@ -444,211 +320,6 @@ That matters for async approval latency: `sessionKey` after the approval request was created, the gateway rejects the forwarded run as an approval mismatch -## Interpreter/runtime commands - -Approval-backed interpreter/runtime runs are intentionally conservative: - -- Exact argv/cwd/env context is always bound. -- Direct shell script and direct runtime file forms are best-effort bound to one concrete local - file snapshot. -- Common package-manager wrapper forms that still resolve to one direct local file (for example - `pnpm exec`, `pnpm node`, `npm exec`, `npx`) are unwrapped before binding. -- If OpenClaw cannot identify exactly one concrete local file for an interpreter/runtime command - (for example package scripts, eval forms, runtime-specific loader chains, or ambiguous multi-file - forms), approval-backed execution is denied instead of claiming semantic coverage it does not - have. -- For those workflows, prefer sandboxing, a separate host boundary, or an explicit trusted - allowlist/full workflow where the operator accepts the broader runtime semantics. - -When approvals are required, the exec tool returns immediately with an approval id. Use that id to -correlate later system events (`Exec finished` / `Exec denied`). If no decision arrives before the -timeout, the request is treated as an approval timeout and surfaced as a denial reason. - -### Followup delivery behavior - -After an approved async exec finishes, OpenClaw sends a followup `agent` turn to the same session. - -- If a valid external delivery target exists (deliverable channel plus target `to`), followup delivery uses that channel. -- In webchat-only or internal-session flows with no external target, followup delivery stays session-only (`deliver: false`). -- If a caller explicitly requests strict external delivery with no resolvable external channel, the request fails with `INVALID_REQUEST`. -- If `bestEffortDeliver` is enabled and no external channel can be resolved, delivery is downgraded to session-only instead of failing. - -The confirmation dialog includes: - -- command + args -- cwd -- agent id -- resolved executable path -- host + policy metadata - -Actions: - -- **Allow once** → run now -- **Always allow** → add to allowlist + run -- **Deny** → block - -## Approval forwarding to chat channels - -You can forward exec approval prompts to any chat channel (including plugin channels) and approve -them with `/approve`. This uses the normal outbound delivery pipeline. - -Config: - -```json5 -{ - approvals: { - exec: { - enabled: true, - mode: "session", // "session" | "targets" | "both" - agentFilter: ["main"], - sessionFilter: ["discord"], // substring or regex - targets: [ - { channel: "slack", to: "U12345678" }, - { channel: "telegram", to: "123456789" }, - ], - }, - }, -} -``` - -Reply in chat: - -``` -/approve allow-once -/approve allow-always -/approve deny -``` - -The `/approve` command handles both exec approvals and plugin approvals. If the ID does not match a pending exec approval, it automatically checks plugin approvals instead. - -### Plugin approval forwarding - -Plugin approval forwarding uses the same delivery pipeline as exec approvals but has its own -independent config under `approvals.plugin`. Enabling or disabling one does not affect the other. - -```json5 -{ - approvals: { - plugin: { - enabled: true, - mode: "targets", - agentFilter: ["main"], - targets: [ - { channel: "slack", to: "U12345678" }, - { channel: "telegram", to: "123456789" }, - ], - }, - }, -} -``` - -The config shape is identical to `approvals.exec`: `enabled`, `mode`, `agentFilter`, -`sessionFilter`, and `targets` work the same way. - -Channels that support shared interactive replies render the same approval buttons for both exec and -plugin approvals. Channels without shared interactive UI fall back to plain text with `/approve` -instructions. - -### Same-chat approvals on any channel - -When an exec or plugin approval request originates from a deliverable chat surface, the same chat -can now approve it with `/approve` by default. This applies to channels such as Slack, Matrix, and -Microsoft Teams in addition to the existing Web UI and terminal UI flows. - -This shared text-command path uses the normal channel auth model for that conversation. If the -originating chat can already send commands and receive replies, approval requests no longer need a -separate native delivery adapter just to stay pending. - -Discord and Telegram also support same-chat `/approve`, but those channels still use their -resolved approver list for authorization even when native approval delivery is disabled. - -For Telegram and other native approval clients that call the Gateway directly, -this fallback is intentionally bounded to "approval not found" failures. A real -exec approval denial/error does not silently retry as a plugin approval. - -### Native approval delivery - -Some channels can also act as native approval clients. Native clients add approver DMs, origin-chat -fanout, and channel-specific interactive approval UX on top of the shared same-chat `/approve` -flow. - -When native approval cards/buttons are available, that native UI is the primary -agent-facing path. The agent should not also echo a duplicate plain chat -`/approve` command unless the tool result says chat approvals are unavailable or -manual approval is the only remaining path. - -Generic model: - -- host exec policy still decides whether exec approval is required -- `approvals.exec` controls forwarding approval prompts to other chat destinations -- `channels..execApprovals` controls whether that channel acts as a native approval client - -Native approval clients auto-enable DM-first delivery when all of these are true: - -- the channel supports native approval delivery -- approvers can be resolved from explicit `execApprovals.approvers` or that - channel's documented fallback sources -- `channels..execApprovals.enabled` is unset or `"auto"` - -Set `enabled: false` to disable a native approval client explicitly. Set `enabled: true` to force -it on when approvers resolve. Public origin-chat delivery stays explicit through -`channels..execApprovals.target`. - -FAQ: [Why are there two exec approval configs for chat approvals?](/help/faq#why-are-there-two-exec-approval-configs-for-chat-approvals) - -- Discord: `channels.discord.execApprovals.*` -- Slack: `channels.slack.execApprovals.*` -- Telegram: `channels.telegram.execApprovals.*` - -These native approval clients add DM routing and optional channel fanout on top of the shared -same-chat `/approve` flow and shared approval buttons. - -Shared behavior: - -- Slack, Matrix, Microsoft Teams, and similar deliverable chats use the normal channel auth model - for same-chat `/approve` -- when a native approval client auto-enables, the default native delivery target is approver DMs -- for Discord and Telegram, only resolved approvers can approve or deny -- Discord approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom` -- Telegram approvers can be explicit (`execApprovals.approvers`) or inferred from existing owner config (`allowFrom`, plus direct-message `defaultTo` where supported) -- Slack approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom` -- Slack native buttons preserve approval id kind, so `plugin:` ids can resolve plugin approvals - without a second Slack-local fallback layer -- Matrix native DM/channel routing and reaction shortcuts handle both exec and plugin approvals; - plugin authorization still comes from `channels.matrix.dm.allowFrom` -- the requester does not need to be an approver -- the originating chat can approve directly with `/approve` when that chat already supports commands and replies -- native Discord approval buttons route by approval id kind: `plugin:` ids go - straight to plugin approvals, everything else goes to exec approvals -- native Telegram approval buttons follow the same bounded exec-to-plugin fallback as `/approve` -- when native `target` enables origin-chat delivery, approval prompts include the command text -- pending exec approvals expire after 30 minutes by default -- if no operator UI or configured approval client can accept the request, the prompt falls back to `askFallback` - -Telegram defaults to approver DMs (`target: "dm"`). You can switch to `channel` or `both` when you -want approval prompts to appear in the originating Telegram chat/topic as well. For Telegram forum -topics, OpenClaw preserves the topic for the approval prompt and the post-approval follow-up. - -See: - -- [Discord](/channels/discord) -- [Telegram](/channels/telegram) - -### macOS IPC flow - -``` -Gateway -> Node Service (WS) - | IPC (UDS + token + HMAC + TTL) - v - Mac App (UI + approvals + system.run) -``` - -Security notes: - -- Unix socket mode `0600`, token stored in `exec-approvals.json`. -- Same-UID peer check. -- Challenge/response (nonce + HMAC token + request hash) + short TTL. - ## System events Exec lifecycle is surfaced as system messages: @@ -680,6 +351,9 @@ stale results from a prior successful run. ## Related + + Safe bins, interpreter binding, and approval forwarding to chat. + Shell command execution tool. diff --git a/docs/tools/exec.md b/docs/tools/exec.md index 8c910568f..33a76b12e 100644 --- a/docs/tools/exec.md +++ b/docs/tools/exec.md @@ -103,7 +103,7 @@ Notes: - `tools.exec.node` (default: unset) - `tools.exec.strictInlineEval` (default: false): when true, inline interpreter eval forms such as `python -c`, `node -e`, `ruby -e`, `perl -e`, `php -r`, `lua -e`, and `osascript -e` always require explicit approval. `allow-always` can still persist benign interpreter/script invocations, but inline-eval forms still prompt each time. - `tools.exec.pathPrepend`: list of directories to prepend to `PATH` for exec runs (gateway + sandbox only). -- `tools.exec.safeBins`: stdin-only safe binaries that can run without explicit allowlist entries. For behavior details, see [Safe bins](/tools/exec-approvals#safe-bins-stdin-only). +- `tools.exec.safeBins`: stdin-only safe binaries that can run without explicit allowlist entries. For behavior details, see [Safe bins](/tools/exec-approvals-advanced#safe-bins-stdin-only). - `tools.exec.safeBinTrustedDirs`: additional explicit directories trusted for `safeBins` path checks. `PATH` entries are never auto-trusted. Built-in defaults are `/bin` and `/usr/bin`. - `tools.exec.safeBinProfiles`: optional custom argv policy per safe bin (`minPositional`, `maxPositional`, `allowedValueFlags`, `deniedFlags`). @@ -198,7 +198,7 @@ Do not treat `safeBins` as a generic allowlist, and do not add interpreter/runti `openclaw security audit` and `openclaw doctor` also warn when you explicitly add broad-behavior bins such as `jq` back into `safeBins`. If you explicitly allowlist interpreters, enable `tools.exec.strictInlineEval` so inline code-eval forms still require a fresh approval. -For full policy details and examples, see [Exec approvals](/tools/exec-approvals#safe-bins-stdin-only) and [Safe bins versus allowlist](/tools/exec-approvals#safe-bins-versus-allowlist). +For full policy details and examples, see [Exec approvals](/tools/exec-approvals-advanced#safe-bins-stdin-only) and [Safe bins versus allowlist](/tools/exec-approvals-advanced#safe-bins-versus-allowlist). ## Examples