From c9a8b6f82fbe8b755b3870b1b648232db02ec258 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 12:03:35 -0700 Subject: [PATCH 01/16] chore(fmt): format changes and broken types --- docs/.generated/config-baseline.json | 8086 ++++------------- .../server.device-pair-approve-authz.test.ts | 4 +- src/infra/device-pairing.ts | 14 + 3 files changed, 1690 insertions(+), 6414 deletions(-) diff --git a/docs/.generated/config-baseline.json b/docs/.generated/config-baseline.json index f6f854b2946..4974f3a410a 100644 --- a/docs/.generated/config-baseline.json +++ b/docs/.generated/config-baseline.json @@ -8,9 +8,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP", "help": "ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.", "hasChildren": true @@ -22,9 +20,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "ACP Allowed Agents", "help": "Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.", "hasChildren": true @@ -46,9 +42,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Backend", "help": "Default ACP runtime backend id (for example: acpx). Must match a registered ACP runtime plugin backend.", "hasChildren": false @@ -60,9 +54,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Default Agent", "help": "Fallback ACP target agent id used when ACP spawns do not specify an explicit target.", "hasChildren": false @@ -84,9 +76,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Dispatch Enabled", "help": "Independent dispatch gate for ACP session turns (default: true). Set false to keep ACP commands available while blocking ACP turn execution.", "hasChildren": false @@ -98,9 +88,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Enabled", "help": "Global ACP feature gate. Keep disabled unless ACP runtime + policy are configured.", "hasChildren": false @@ -112,10 +100,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "ACP Max Concurrent Sessions", "help": "Maximum concurrently active ACP sessions across this gateway process.", "hasChildren": false @@ -137,9 +122,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Runtime Install Command", "help": "Optional operator install/setup command shown by `/acp install` and `/acp doctor` when ACP backend wiring is missing.", "hasChildren": false @@ -151,9 +134,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Runtime TTL (minutes)", "help": "Idle runtime TTL in minutes for ACP session workers before eligible cleanup.", "hasChildren": false @@ -165,9 +146,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream", "help": "ACP streaming projection controls for chunk sizing, metadata visibility, and deduped delivery behavior.", "hasChildren": true @@ -179,9 +158,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream Coalesce Idle (ms)", "help": "Coalescer idle flush window in milliseconds for ACP streamed text before block replies are emitted.", "hasChildren": false @@ -193,9 +170,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream Delivery Mode", "help": "ACP delivery style: live streams projected output incrementally, final_only buffers all projected ACP output until terminal turn events.", "hasChildren": false @@ -207,9 +182,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream Hidden Boundary Separator", "help": "Separator inserted before next visible assistant text when hidden ACP tool lifecycle events occurred (none|space|newline|paragraph). Default: paragraph.", "hasChildren": false @@ -221,9 +194,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "ACP Stream Max Chunk Chars", "help": "Maximum chunk size for ACP streamed block projection before splitting into multiple block replies.", "hasChildren": false @@ -235,9 +206,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "ACP Stream Max Output Chars", "help": "Maximum assistant output characters projected per ACP turn before truncation notice is emitted.", "hasChildren": false @@ -249,10 +218,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "ACP Stream Max Session Update Chars", "help": "Maximum characters for projected ACP session/update lines (tool/status updates).", "hasChildren": false @@ -264,9 +230,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream Repeat Suppression", "help": "When true (default), suppress repeated ACP status/tool projection lines in a turn while keeping raw ACP events unchanged.", "hasChildren": false @@ -278,9 +242,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Stream Tag Visibility", "help": "Per-sessionUpdate visibility overrides for ACP projection (for example usage_update, available_commands_update).", "hasChildren": true @@ -302,9 +264,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agents", "help": "Agent runtime configuration root covering defaults and explicit agent entries used for routing and execution context. Keep this section explicit so model/tool behavior stays predictable across multi-agent workflows.", "hasChildren": true @@ -316,9 +276,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent Defaults", "help": "Shared default settings inherited by agents unless overridden per entry in agents.list. Use defaults to enforce consistent baseline behavior and reduce duplicated per-agent configuration.", "hasChildren": true @@ -430,9 +388,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Bootstrap Max Chars", "help": "Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).", "hasChildren": false @@ -444,9 +400,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Bootstrap Prompt Truncation Warning", "help": "Inject agent-visible warning text when bootstrap files are truncated: \"off\", \"once\" (default), or \"always\".", "hasChildren": false @@ -458,9 +412,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Bootstrap Total Max Chars", "help": "Max total characters across all injected workspace bootstrap files (default: 150000).", "hasChildren": false @@ -472,9 +424,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "CLI Backends", "help": "Optional CLI backends for text-only fallback (claude-cli, etc.).", "hasChildren": true @@ -896,9 +846,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction", "help": "Compaction tuning for when context nears token limits, including history share, reserve headroom, and pre-compaction memory flush behavior. Use this when long-running sessions need stable continuity under tight context windows.", "hasChildren": true @@ -920,9 +868,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Identifier Instructions", "help": "Custom identifier-preservation instruction text used when identifierPolicy=\"custom\". Keep this explicit and safety-focused so compaction summaries do not rewrite opaque IDs, URLs, hosts, or ports.", "hasChildren": false @@ -934,9 +880,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Compaction Identifier Policy", "help": "Identifier-preservation policy for compaction summaries: \"strict\" prepends built-in opaque-identifier retention guidance (default), \"off\" disables this prefix, and \"custom\" uses identifierInstructions. Keep \"strict\" unless you have a specific compatibility need.", "hasChildren": false @@ -948,10 +892,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Compaction Keep Recent Tokens", "help": "Minimum token budget preserved from the most recent conversation window during compaction. Use higher values to protect immediate context continuity and lower values to keep more long-tail history.", "hasChildren": false @@ -963,9 +904,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Compaction Max History Share", "help": "Maximum fraction of total context budget allowed for retained history after compaction (range 0.1-0.9). Use lower shares for more generation headroom or higher shares for deeper historical continuity.", "hasChildren": false @@ -977,9 +916,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Memory Flush", "help": "Pre-compaction memory flush settings that run an agentic memory write before heavy compaction. Keep enabled for long sessions so salient context is persisted before aggressive trimming.", "hasChildren": true @@ -991,9 +928,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Memory Flush Enabled", "help": "Enables pre-compaction memory flush before the runtime performs stronger history reduction near token limits. Keep enabled unless you intentionally disable memory side effects in constrained environments.", "hasChildren": false @@ -1001,16 +936,11 @@ { "path": "agents.defaults.compaction.memoryFlush.forceFlushTranscriptBytes", "kind": "core", - "type": [ - "integer", - "string" - ], + "type": ["integer", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Memory Flush Transcript Size Threshold", "help": "Forces pre-compaction memory flush when transcript file size reaches this threshold (bytes or strings like \"2mb\"). Use this to prevent long-session hangs even when token counters are stale; set to 0 to disable.", "hasChildren": false @@ -1022,9 +952,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Memory Flush Prompt", "help": "User-prompt template used for the pre-compaction memory flush turn when generating memory candidates. Use this only when you need custom extraction instructions beyond the default memory flush behavior.", "hasChildren": false @@ -1036,10 +964,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Compaction Memory Flush Soft Threshold", "help": "Threshold distance to compaction (in tokens) that triggers pre-compaction memory flush execution. Use earlier thresholds for safer persistence, or tighter thresholds for lower flush frequency.", "hasChildren": false @@ -1051,9 +976,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Memory Flush System Prompt", "help": "System-prompt override for the pre-compaction memory flush turn to control extraction style and safety constraints. Use carefully so custom instructions do not reduce memory quality or leak sensitive context.", "hasChildren": false @@ -1065,9 +988,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Mode", "help": "Compaction strategy mode: \"default\" uses baseline behavior, while \"safeguard\" applies stricter guardrails to preserve recent context. Keep \"default\" unless you observe aggressive history loss near limit boundaries.", "hasChildren": false @@ -1079,9 +1000,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Compaction Model Override", "help": "Optional provider/model override used only for compaction summarization. Set this when you want compaction to run on a different model than the session default, and leave it unset to keep using the primary agent model.", "hasChildren": false @@ -1093,9 +1012,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Post-Compaction Context Sections", "help": "AGENTS.md H2/H3 section names re-injected after compaction so the agent reruns critical startup guidance. Leave unset to use \"Session Startup\"/\"Red Lines\" with legacy fallback to \"Every Session\"/\"Safety\"; set to [] to disable reinjection entirely.", "hasChildren": true @@ -1115,16 +1032,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "off", - "async", - "await" - ], + "enumValues": ["off", "async", "await"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Post-Index Sync", "help": "Controls post-compaction session memory reindex mode: \"off\", \"async\", or \"await\" (default: \"async\"). Use \"await\" for strongest freshness, \"async\" for lower compaction latency, and \"off\" only when session-memory sync is handled elsewhere.", "hasChildren": false @@ -1136,9 +1047,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Quality Guard", "help": "Optional quality-audit retry settings for safeguard compaction summaries. Leave this disabled unless you explicitly want summary audits and one-shot regeneration on failed checks.", "hasChildren": true @@ -1150,9 +1059,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Quality Guard Enabled", "help": "Enables summary quality audits and regeneration retries for safeguard compaction. Default: false, so safeguard mode alone does not turn on retry behavior.", "hasChildren": false @@ -1164,9 +1071,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Compaction Quality Guard Max Retries", "help": "Maximum number of regeneration retries after a failed safeguard summary quality audit. Use small values to bound extra latency and token cost.", "hasChildren": false @@ -1178,9 +1083,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Compaction Preserve Recent Turns", "help": "Number of most recent user/assistant turns kept verbatim outside safeguard summarization (default: 3). Raise this to preserve exact recent dialogue context, or lower it to maximize compaction savings.", "hasChildren": false @@ -1192,10 +1095,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Compaction Reserve Tokens", "help": "Token headroom reserved for reply generation and tool output after compaction runs. Use higher reserves for verbose/tool-heavy sessions, and lower reserves when maximizing retained history matters more.", "hasChildren": false @@ -1207,10 +1107,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Compaction Reserve Token Floor", "help": "Minimum floor enforced for reserveTokens in Pi compaction paths (0 disables the floor guard). Use a non-zero floor to avoid over-aggressive compression under fluctuating token estimates.", "hasChildren": false @@ -1222,9 +1119,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Compaction Timeout (Seconds)", "help": "Maximum time in seconds allowed for a single compaction operation before it is aborted (default: 900). Increase this for very large sessions that need more time to summarize, or decrease it to fail faster on unresponsive models.", "hasChildren": false @@ -1446,9 +1341,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Embedded Pi", "help": "Embedded Pi runner hardening controls for how workspace-local Pi settings are trusted and applied in OpenClaw sessions.", "hasChildren": true @@ -1460,9 +1353,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Embedded Pi Project Settings Policy", "help": "How embedded Pi handles workspace-local `.pi/config/settings.json`: \"sanitize\" (default) strips shellPath/shellCommandPrefix, \"ignore\" disables project settings entirely, and \"trusted\" applies project settings as-is.", "hasChildren": false @@ -1474,9 +1365,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Envelope Elapsed", "help": "Include elapsed time in message envelopes (\"on\" or \"off\").", "hasChildren": false @@ -1488,9 +1377,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Envelope Timestamp", "help": "Include absolute timestamps in message envelopes (\"on\" or \"off\").", "hasChildren": false @@ -1502,9 +1389,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Envelope Timezone", "help": "Timezone for message envelopes (\"utc\", \"local\", \"user\", or an IANA timezone string).", "hasChildren": false @@ -1586,11 +1471,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "automation", - "storage" - ], + "tags": ["access", "automation", "storage"], "label": "Heartbeat Direct Policy", "help": "Controls whether heartbeat delivery may target direct/DM chats: \"allow\" (default) permits DM delivery and \"block\" suppresses direct-target sends.", "hasChildren": false @@ -1672,9 +1553,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Heartbeat Suppress Tool Error Warnings", "help": "Suppress tool error warning payloads during heartbeat runs.", "hasChildren": false @@ -1686,9 +1565,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, synology-chat, tlon, twitch, zalo, zalouser.", "hasChildren": false }, @@ -1719,9 +1596,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Human Delay Max (ms)", "help": "Maximum delay in ms for custom humanDelay (default: 2500).", "hasChildren": false @@ -1733,9 +1608,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Human Delay Min (ms)", "help": "Minimum delay in ms for custom humanDelay (default: 800).", "hasChildren": false @@ -1747,9 +1620,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Human Delay Mode", "help": "Delay style for block replies (\"off\", \"natural\", \"custom\").", "hasChildren": false @@ -1761,10 +1632,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance" - ], + "tags": ["media", "performance"], "label": "Image Max Dimension (px)", "help": "Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).", "hasChildren": false @@ -1772,10 +1640,7 @@ { "path": "agents.defaults.imageModel", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -1789,11 +1654,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models", - "reliability" - ], + "tags": ["media", "models", "reliability"], "label": "Image Model Fallbacks", "help": "Ordered fallback image models (provider/model).", "hasChildren": true @@ -1815,10 +1676,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models" - ], + "tags": ["media", "models"], "label": "Image Model", "help": "Optional image model (provider/model) used when the primary model lacks image input.", "hasChildren": false @@ -1850,9 +1708,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search", "help": "Vector search over MEMORY.md and memory/*.md (per-agent overrides supported).", "hasChildren": true @@ -1874,9 +1730,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Search Embedding Cache", "help": "Caches computed chunk embeddings in SQLite so reindexing and incremental updates run faster (default: true). Keep this enabled unless investigating cache correctness or minimizing disk usage.", "hasChildren": false @@ -1888,10 +1742,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Memory Search Embedding Cache Max Entries", "help": "Sets a best-effort upper bound on cached embeddings kept in SQLite for memory search. Use this when controlling disk growth matters more than peak reindex speed.", "hasChildren": false @@ -1913,9 +1764,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Chunk Overlap Tokens", "help": "Token overlap between adjacent memory chunks to preserve context continuity near split boundaries. Use modest overlap to reduce boundary misses without inflating index size too aggressively.", "hasChildren": false @@ -1927,10 +1776,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Memory Chunk Tokens", "help": "Chunk size in tokens used when splitting memory sources before embedding/indexing. Increase for broader context per chunk, or lower to improve precision on pinpoint lookups.", "hasChildren": false @@ -1942,9 +1788,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Memory Search", "help": "Master toggle for memory search indexing and retrieval behavior on this agent profile. Keep enabled for semantic recall, and disable when you want fully stateless responses.", "hasChildren": false @@ -1966,11 +1810,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "security", - "storage" - ], + "tags": ["advanced", "security", "storage"], "label": "Memory Search Session Index (Experimental)", "help": "Indexes session transcripts into memory search so responses can reference prior chat turns. Keep this off unless transcript recall is needed, because indexing cost and storage usage both increase.", "hasChildren": false @@ -1982,9 +1822,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Extra Memory Paths", "help": "Adds extra directories or .md files to the memory index beyond default memory files. Use this when key reference docs live elsewhere in your repo; when multimodal memory is enabled, matching image/audio files under these paths are also eligible for indexing.", "hasChildren": true @@ -2006,9 +1844,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "reliability" - ], + "tags": ["reliability"], "label": "Memory Search Fallback", "help": "Backup provider used when primary embeddings fail: \"openai\", \"gemini\", \"voyage\", \"mistral\", \"ollama\", \"local\", or \"none\". Set a real fallback for production reliability; use \"none\" only if you prefer explicit failures.", "hasChildren": false @@ -2040,9 +1876,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Local Embedding Model Path", "help": "Specifies the local embedding model source for local memory search, such as a GGUF file path or `hf:` URI. Use this only when provider is `local`, and verify model compatibility before large index rebuilds.", "hasChildren": false @@ -2054,9 +1888,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Memory Search Model", "help": "Embedding model override used by the selected memory provider when a non-default model is required. Set this only when you need explicit recall quality/cost tuning beyond provider defaults.", "hasChildren": false @@ -2068,9 +1900,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Multimodal", "help": "Optional multimodal memory settings for indexing image and audio files from configured extra paths. Keep this off unless your embedding model explicitly supports cross-modal embeddings, and set `memorySearch.fallback` to \"none\" while it is enabled. Matching files are uploaded to the configured remote embedding provider during indexing.", "hasChildren": true @@ -2082,9 +1912,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Memory Search Multimodal", "help": "Enables image/audio memory indexing from extraPaths. This currently requires Gemini embedding-2, keeps the default memory roots Markdown-only, disables memory-search fallback providers, and uploads matching binary content to the configured remote embedding provider.", "hasChildren": false @@ -2096,10 +1924,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Memory Search Multimodal Max File Bytes", "help": "Sets the maximum bytes allowed per multimodal file before it is skipped during memory indexing. Use this to cap upload cost and indexing latency, or raise it for short high-quality audio clips.", "hasChildren": false @@ -2111,9 +1936,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Multimodal Modalities", "help": "Selects which multimodal file types are indexed from extraPaths: \"image\", \"audio\", or \"all\". Keep this narrow to avoid indexing large binary corpora unintentionally.", "hasChildren": true @@ -2135,9 +1958,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Output Dimensionality", "help": "Gemini embedding-2 only: chooses the output vector size for memory embeddings. Use 768, 1536, or 3072 (default), and expect a full reindex when you change it because stored vector dimensions must stay consistent.", "hasChildren": false @@ -2149,9 +1970,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Provider", "help": "Selects the embedding backend used to build/query memory vectors: \"openai\", \"gemini\", \"voyage\", \"mistral\", \"ollama\", or \"local\". Keep your most reliable provider here and configure fallback for resilience.", "hasChildren": false @@ -2183,9 +2002,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Hybrid Candidate Multiplier", "help": "Expands the candidate pool before reranking (default: 4). Raise this for better recall on noisy corpora, but expect more compute and slightly slower searches.", "hasChildren": false @@ -2197,9 +2014,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Hybrid", "help": "Combines BM25 keyword matching with vector similarity for better recall on mixed exact + semantic queries. Keep enabled unless you are isolating ranking behavior for troubleshooting.", "hasChildren": false @@ -2221,9 +2036,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search MMR Re-ranking", "help": "Adds MMR reranking to diversify results and reduce near-duplicate snippets in a single answer window. Enable when recall looks repetitive; keep off for strict score ordering.", "hasChildren": false @@ -2235,9 +2048,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search MMR Lambda", "help": "Sets MMR relevance-vs-diversity balance (0 = most diverse, 1 = most relevant, default: 0.7). Lower values reduce repetition; higher values keep tightly relevant but may duplicate.", "hasChildren": false @@ -2259,9 +2070,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Temporal Decay", "help": "Applies recency decay so newer memory can outrank older memory when scores are close. Enable when timeliness matters; keep off for timeless reference knowledge.", "hasChildren": false @@ -2273,9 +2082,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Temporal Decay Half-life (Days)", "help": "Controls how fast older memory loses rank when temporal decay is enabled (half-life in days, default: 30). Lower values prioritize recent context more aggressively.", "hasChildren": false @@ -2287,9 +2094,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Text Weight", "help": "Controls how strongly BM25 keyword relevance influences hybrid ranking (0-1). Increase for exact-term matching; decrease when semantic matches should rank higher.", "hasChildren": false @@ -2301,9 +2106,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Vector Weight", "help": "Controls how strongly semantic similarity influences hybrid ranking (0-1). Increase when paraphrase matching matters more than exact terms; decrease for stricter keyword emphasis.", "hasChildren": false @@ -2315,9 +2118,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Memory Search Max Results", "help": "Maximum number of memory hits returned from search before downstream reranking and prompt injection. Raise for broader recall, or lower for tighter prompts and faster responses.", "hasChildren": false @@ -2329,9 +2130,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Min Score", "help": "Minimum relevance score threshold for including memory results in final recall output. Increase to reduce weak/noisy matches, or lower when you need more permissive retrieval.", "hasChildren": false @@ -2349,17 +2148,11 @@ { "path": "agents.defaults.memorySearch.remote.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Remote Embedding API Key", "help": "Supplies a dedicated API key for remote embedding calls used by memory indexing and query-time embeddings. Use this when memory embeddings should use different credentials than global defaults or environment variables.", "hasChildren": true @@ -2401,9 +2194,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Remote Embedding Base URL", "help": "Overrides the embedding API endpoint, such as an OpenAI-compatible proxy or custom Gemini base URL. Use this only when routing through your own gateway or vendor endpoint; keep provider defaults otherwise.", "hasChildren": false @@ -2425,9 +2216,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Remote Batch Concurrency", "help": "Limits how many embedding batch jobs run at the same time during indexing (default: 2). Increase carefully for faster bulk indexing, but watch provider rate limits and queue errors.", "hasChildren": false @@ -2439,9 +2228,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Remote Batch Embedding Enabled", "help": "Enables provider batch APIs for embedding jobs when supported (OpenAI/Gemini), improving throughput on larger index runs. Keep this enabled unless debugging provider batch failures or running very small workloads.", "hasChildren": false @@ -2453,9 +2240,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Remote Batch Poll Interval (ms)", "help": "Controls how often the system polls provider APIs for batch job status in milliseconds (default: 2000). Use longer intervals to reduce API chatter, or shorter intervals for faster completion detection.", "hasChildren": false @@ -2467,9 +2252,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Remote Batch Timeout (min)", "help": "Sets the maximum wait time for a full embedding batch operation in minutes (default: 60). Increase for very large corpora or slower providers, and lower it to fail fast in automation-heavy flows.", "hasChildren": false @@ -2481,9 +2264,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Remote Batch Wait for Completion", "help": "Waits for batch embedding jobs to fully finish before the indexing operation completes. Keep this enabled for deterministic indexing state; disable only if you accept delayed consistency.", "hasChildren": false @@ -2495,9 +2276,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Remote Embedding Headers", "help": "Adds custom HTTP headers to remote embedding requests, merged with provider defaults. Use this for proxy auth and tenant routing headers, and keep values minimal to avoid leaking sensitive metadata.", "hasChildren": true @@ -2519,9 +2298,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Search Sources", "help": "Chooses which sources are indexed: \"memory\" reads MEMORY.md + memory files, and \"sessions\" includes transcript history. Keep [\"memory\"] unless you need recall from prior chat transcripts.", "hasChildren": true @@ -2563,9 +2340,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Search Index Path", "help": "Sets where the SQLite memory index is stored on disk for each agent. Keep the default `~/.openclaw/memory/{agentId}.sqlite` unless you need custom storage placement or backup policy alignment.", "hasChildren": false @@ -2587,9 +2362,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Search Vector Index", "help": "Enables the sqlite-vec extension used for vector similarity queries in memory search (default: true). Keep this enabled for normal semantic recall; disable only for debugging or fallback-only operation.", "hasChildren": false @@ -2601,9 +2374,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Search Vector Extension Path", "help": "Overrides the auto-discovered sqlite-vec extension library path (`.dylib`, `.so`, or `.dll`). Use this when your runtime cannot find sqlite-vec automatically or you pin a known-good build.", "hasChildren": false @@ -2635,9 +2406,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Index on Search (Lazy)", "help": "Uses lazy sync by scheduling reindex on search after content changes are detected. Keep enabled for lower idle overhead, or disable if you require pre-synced indexes before any query.", "hasChildren": false @@ -2649,10 +2418,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "storage" - ], + "tags": ["automation", "storage"], "label": "Index on Session Start", "help": "Triggers a memory index sync when a session starts so early turns see fresh memory content. Keep enabled when startup freshness matters more than initial turn latency.", "hasChildren": false @@ -2674,9 +2440,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Delta Bytes", "help": "Requires at least this many newly appended bytes before session transcript changes trigger reindex (default: 100000). Increase to reduce frequent small reindexes, or lower for faster transcript freshness.", "hasChildren": false @@ -2688,9 +2452,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Delta Messages", "help": "Requires at least this many appended transcript messages before reindex is triggered (default: 50). Lower this for near-real-time transcript recall, or raise it to reduce indexing churn.", "hasChildren": false @@ -2702,9 +2464,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Force Reindex After Compaction", "help": "Forces a session memory-search reindex after compaction-triggered transcript updates (default: true). Keep enabled when compacted summaries must be immediately searchable, or disable to reduce write-time indexing pressure.", "hasChildren": false @@ -2716,9 +2476,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Watch Memory Files", "help": "Watches memory files and schedules index updates from file-change events (chokidar). Enable for near-real-time freshness; disable on very large workspaces if watch churn is too noisy.", "hasChildren": false @@ -2730,10 +2488,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "performance" - ], + "tags": ["automation", "performance"], "label": "Memory Watch Debounce (ms)", "help": "Debounce window in milliseconds for coalescing rapid file-watch events before reindex runs. Increase to reduce churn on frequently-written files, or lower for faster freshness.", "hasChildren": false @@ -2741,10 +2496,7 @@ { "path": "agents.defaults.model", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -2758,10 +2510,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "reliability" - ], + "tags": ["models", "reliability"], "label": "Model Fallbacks", "help": "Ordered fallback models (provider/model). Used when the primary model fails.", "hasChildren": true @@ -2783,9 +2532,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Primary Model", "help": "Primary model (provider/model).", "hasChildren": false @@ -2797,9 +2544,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Models", "help": "Configured model catalog (keys are full provider/model IDs).", "hasChildren": true @@ -2860,9 +2605,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "PDF Max Size (MB)", "help": "Maximum PDF file size in megabytes for the PDF tool (default: 10).", "hasChildren": false @@ -2874,9 +2617,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "PDF Max Pages", "help": "Maximum number of PDF pages to process for the PDF tool (default: 20).", "hasChildren": false @@ -2884,10 +2625,7 @@ { "path": "agents.defaults.pdfModel", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -2901,9 +2639,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "reliability" - ], + "tags": ["reliability"], "label": "PDF Model Fallbacks", "help": "Ordered fallback PDF models (provider/model).", "hasChildren": true @@ -2925,9 +2661,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "PDF Model", "help": "Optional PDF model (provider/model) for the PDF analysis tool. Defaults to imageModel, then session model.", "hasChildren": false @@ -2939,9 +2673,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Repo Root", "help": "Optional repository root shown in the system prompt runtime line (overrides auto-detect).", "hasChildren": false @@ -3033,9 +2765,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Sandbox Browser CDP Source Port Range", "help": "Optional CIDR allowlist for container-edge CDP ingress (for example 172.21.0.1/32).", "hasChildren": false @@ -3097,9 +2827,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Sandbox Browser Network", "help": "Docker network for sandbox browser containers (default: openclaw-sandbox-browser). Avoid bridge if you need stricter isolation.", "hasChildren": false @@ -3211,12 +2939,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "security", - "storage" - ], + "tags": ["access", "advanced", "security", "storage"], "label": "Sandbox Docker Allow Container Namespace Join", "help": "DANGEROUS break-glass override that allows sandbox Docker network mode container:. This joins another container namespace and weakens sandbox isolation.", "hasChildren": false @@ -3314,10 +3037,7 @@ { "path": "agents.defaults.sandbox.docker.memory", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -3327,10 +3047,7 @@ { "path": "agents.defaults.sandbox.docker.memorySwap", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -3419,11 +3136,7 @@ { "path": "agents.defaults.sandbox.docker.ulimits.*", "kind": "core", - "type": [ - "number", - "object", - "string" - ], + "type": ["number", "object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -3633,10 +3346,7 @@ { "path": "agents.defaults.subagents.model", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -3770,9 +3480,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Workspace", "help": "Default workspace path exposed to agent runtime tools for filesystem context and repo-aware behavior. Set this explicitly when running from wrappers so path resolution stays deterministic.", "hasChildren": false @@ -3784,9 +3492,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent List", "help": "Explicit list of configured agents with IDs and optional overrides for model, tools, identity, and workspace. Keep IDs stable over time so bindings, approvals, and session routing remain deterministic.", "hasChildren": true @@ -3938,11 +3644,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "automation", - "storage" - ], + "tags": ["access", "automation", "storage"], "label": "Heartbeat Direct Policy", "help": "Per-agent override for heartbeat direct/DM delivery policy; use \"block\" for agents that should only send heartbeat alerts to non-DM destinations.", "hasChildren": false @@ -4024,9 +3726,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Agent Heartbeat Suppress Tool Error Warnings", "help": "Suppress tool error warning payloads during heartbeat runs.", "hasChildren": false @@ -4038,9 +3738,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, synology-chat, tlon, twitch, zalo, zalouser.", "hasChildren": false }, @@ -4121,9 +3819,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Identity Avatar", "help": "Agent avatar (workspace-relative path, http(s) URL, or data URI).", "hasChildren": false @@ -4551,17 +4247,11 @@ { "path": "agents.list.*.memorySearch.remote.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "hasChildren": true }, { @@ -4867,10 +4557,7 @@ { "path": "agents.list.*.model", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -4943,9 +4630,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent Runtime", "help": "Optional runtime descriptor for this agent. Use embedded for default OpenClaw execution or acp for external ACP harness defaults.", "hasChildren": true @@ -4957,9 +4642,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent ACP Runtime", "help": "ACP runtime defaults for this agent when runtime.type=acp. Binding-level ACP overrides still take precedence per conversation.", "hasChildren": true @@ -4971,9 +4654,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent ACP Harness Agent", "help": "Optional ACP harness agent id to use for this OpenClaw agent (for example codex, claude).", "hasChildren": false @@ -4985,9 +4666,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent ACP Backend", "help": "Optional ACP backend override for this agent's ACP sessions (falls back to global acp.backend).", "hasChildren": false @@ -4999,9 +4678,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent ACP Working Directory", "help": "Optional default working directory for this agent's ACP sessions.", "hasChildren": false @@ -5011,15 +4688,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "persistent", - "oneshot" - ], + "enumValues": ["persistent", "oneshot"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent ACP Mode", "help": "Optional ACP session mode default for this agent (persistent or oneshot).", "hasChildren": false @@ -5031,9 +4703,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent Runtime Type", "help": "Runtime type for this agent: \"embedded\" (default OpenClaw runtime) or \"acp\" (ACP harness defaults).", "hasChildren": false @@ -5125,9 +4795,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Agent Sandbox Browser CDP Source Port Range", "help": "Per-agent override for CDP source CIDR allowlist.", "hasChildren": false @@ -5189,9 +4857,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Agent Sandbox Browser Network", "help": "Per-agent override for sandbox browser Docker network.", "hasChildren": false @@ -5303,12 +4969,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "security", - "storage" - ], + "tags": ["access", "advanced", "security", "storage"], "label": "Agent Sandbox Docker Allow Container Namespace Join", "help": "Per-agent DANGEROUS override for container namespace joins in sandbox Docker network mode.", "hasChildren": false @@ -5406,10 +5067,7 @@ { "path": "agents.list.*.sandbox.docker.memory", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -5419,10 +5077,7 @@ { "path": "agents.list.*.sandbox.docker.memorySwap", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -5511,11 +5166,7 @@ { "path": "agents.list.*.sandbox.docker.ulimits.*", "kind": "core", - "type": [ - "number", - "object", - "string" - ], + "type": ["number", "object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -5659,9 +5310,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent Skill Filter", "help": "Optional allowlist of skills for this agent (omit = all skills; empty = no skills).", "hasChildren": true @@ -5709,10 +5358,7 @@ { "path": "agents.list.*.subagents.model", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -5796,9 +5442,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Agent Tool Allowlist Additions", "help": "Per-agent additive allowlist for tools on top of global and profile policy. Keep narrow to avoid accidental privilege expansion on specialized agents.", "hasChildren": true @@ -5820,9 +5464,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Agent Tool Policy by Provider", "help": "Per-agent provider-specific tool policy overrides for channel-scoped capability control. Use this when a single agent needs tighter restrictions on one provider than others.", "hasChildren": true @@ -5960,10 +5602,7 @@ { "path": "agents.list.*.tools.elevated.allowFrom.*.*", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -6055,11 +5694,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "off", - "on-miss", - "always" - ], + "enumValues": ["off", "on-miss", "always"], "deprecated": false, "sensitive": false, "tags": [], @@ -6090,11 +5725,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "sandbox", - "gateway", - "node" - ], + "enumValues": ["sandbox", "gateway", "node"], "deprecated": false, "sensitive": false, "tags": [], @@ -6275,11 +5906,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "deny", - "allowlist", - "full" - ], + "enumValues": ["deny", "allowlist", "full"], "deprecated": false, "sensitive": false, "tags": [], @@ -6422,9 +6049,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Agent Tool Profile", "help": "Per-agent override for tool profile selection when one agent needs a different capability baseline. Use this sparingly so policy differences across agents stay intentional and reviewable.", "hasChildren": false @@ -6526,9 +6151,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approvals", "help": "Approval routing controls for forwarding exec approval requests to chat destinations outside the originating session. Keep this disabled unless operators need explicit out-of-band approval visibility.", "hasChildren": true @@ -6540,9 +6163,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Exec Approval Forwarding", "help": "Groups exec-approval forwarding behavior including enablement, routing mode, filters, and explicit targets. Configure here when approval prompts must reach operational channels instead of only the origin thread.", "hasChildren": true @@ -6554,9 +6175,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Agent Filter", "help": "Optional allowlist of agent IDs eligible for forwarded approvals, for example `[\"primary\", \"ops-agent\"]`. Use this to limit forwarding blast radius and avoid notifying channels for unrelated agents.", "hasChildren": true @@ -6578,9 +6197,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Forward Exec Approvals", "help": "Enables forwarding of exec approval requests to configured delivery destinations (default: false). Keep disabled in low-risk setups and enable only when human approval responders need channel-visible prompts.", "hasChildren": false @@ -6592,9 +6209,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Forwarding Mode", "help": "Controls where approval prompts are sent: \"session\" uses origin chat, \"targets\" uses configured targets, and \"both\" sends to both paths. Use \"session\" as baseline and expand only when operational workflow requires redundancy.", "hasChildren": false @@ -6606,9 +6221,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Approval Session Filter", "help": "Optional session-key filters matched as substring or regex-style patterns, for example `[\"discord:\", \"^agent:ops:\"]`. Use narrow patterns so only intended approval contexts are forwarded to shared destinations.", "hasChildren": true @@ -6630,9 +6243,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Forwarding Targets", "help": "Explicit delivery targets used when forwarding mode includes targets, each with channel and destination details. Keep target lists least-privilege and validate each destination before enabling broad forwarding.", "hasChildren": true @@ -6654,9 +6265,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Target Account ID", "help": "Optional account selector for multi-account channel setups when approvals must route through a specific account context. Use this only when the target channel has multiple configured identities.", "hasChildren": false @@ -6668,9 +6277,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Target Channel", "help": "Channel/provider ID used for forwarded approval delivery, such as discord, slack, or a plugin channel id. Use valid channel IDs only so approvals do not silently fail due to unknown routes.", "hasChildren": false @@ -6678,16 +6285,11 @@ { "path": "approvals.exec.targets.*.threadId", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Target Thread ID", "help": "Optional thread/topic target for channels that support threaded delivery of forwarded approvals. Use this to keep approval traffic contained in operational threads instead of main channels.", "hasChildren": false @@ -6699,9 +6301,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Approval Target Destination", "help": "Destination identifier inside the target channel (channel ID, user ID, or thread root depending on provider). Verify semantics per provider because destination format differs across channel integrations.", "hasChildren": false @@ -6713,9 +6313,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Audio", "help": "Global audio ingestion settings used before higher-level tools process speech or media content. Configure this when you need deterministic transcription behavior for voice notes and clips.", "hasChildren": true @@ -6727,9 +6325,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Audio Transcription", "help": "Command-based transcription settings for converting audio files into text before agent handling. Keep a simple, deterministic command path here so failures are easy to diagnose in logs.", "hasChildren": true @@ -6741,9 +6337,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Audio Transcription Command", "help": "Executable + args used to transcribe audio (first token must be a safe binary/path), for example `[\"whisper-cli\", \"--model\", \"small\", \"{input}\"]`. Prefer a pinned command so runtime environments behave consistently.", "hasChildren": true @@ -6765,10 +6359,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance" - ], + "tags": ["media", "performance"], "label": "Audio Transcription Timeout (sec)", "help": "Maximum time allowed for the transcription command to finish before it is aborted. Increase this for longer recordings, and keep it tight in latency-sensitive deployments.", "hasChildren": false @@ -6780,9 +6371,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Auth", "help": "Authentication profile root used for multi-profile provider credentials and cooldown-based failover ordering. Keep profiles minimal and explicit so automatic failover behavior stays auditable.", "hasChildren": true @@ -6794,10 +6383,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth" - ], + "tags": ["access", "auth"], "label": "Auth Cooldowns", "help": "Cooldown/backoff controls for temporary profile suppression after billing-related failures and retry windows. Use these to prevent rapid re-selection of profiles that are still blocked.", "hasChildren": true @@ -6809,11 +6395,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth", - "reliability" - ], + "tags": ["access", "auth", "reliability"], "label": "Billing Backoff (hours)", "help": "Base backoff (hours) when a profile fails due to billing/insufficient credits (default: 5).", "hasChildren": false @@ -6825,11 +6407,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth", - "reliability" - ], + "tags": ["access", "auth", "reliability"], "label": "Billing Backoff Overrides", "help": "Optional per-provider overrides for billing backoff (hours).", "hasChildren": true @@ -6851,11 +6429,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth", - "performance" - ], + "tags": ["access", "auth", "performance"], "label": "Billing Backoff Cap (hours)", "help": "Cap (hours) for billing backoff (default: 24).", "hasChildren": false @@ -6867,10 +6441,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth" - ], + "tags": ["access", "auth"], "label": "Failover Window (hours)", "help": "Failure window (hours) for backoff counters (default: 24).", "hasChildren": false @@ -6882,10 +6453,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth" - ], + "tags": ["access", "auth"], "label": "Auth Profile Order", "help": "Ordered auth profile IDs per provider (used for automatic failover).", "hasChildren": true @@ -6917,11 +6485,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "auth", - "storage" - ], + "tags": ["access", "auth", "storage"], "label": "Auth Profiles", "help": "Named auth profiles (provider + mode + optional email).", "hasChildren": true @@ -6973,9 +6537,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Bindings", "help": "Top-level binding rules for routing and persistent ACP conversation ownership. Use type=route for normal routing and type=acp for persistent ACP harness bindings.", "hasChildren": true @@ -6997,9 +6559,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Binding Overrides", "help": "Optional per-binding ACP overrides for bindings[].type=acp. This layer overrides agents.list[].runtime.acp defaults for the matched conversation.", "hasChildren": true @@ -7011,9 +6571,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Binding Backend", "help": "ACP backend override for this binding (falls back to agent runtime ACP backend, then global acp.backend).", "hasChildren": false @@ -7025,9 +6583,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Binding Working Directory", "help": "Working directory override for ACP sessions created from this binding.", "hasChildren": false @@ -7039,9 +6595,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Binding Label", "help": "Human-friendly label for ACP status/diagnostics in this bound conversation.", "hasChildren": false @@ -7051,15 +6605,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "persistent", - "oneshot" - ], + "enumValues": ["persistent", "oneshot"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACP Binding Mode", "help": "ACP session mode override for this binding (persistent or oneshot).", "hasChildren": false @@ -7071,9 +6620,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Agent ID", "help": "Target agent ID that receives traffic when the corresponding binding match rule is satisfied. Use valid configured agent IDs only so routing does not fail at runtime.", "hasChildren": false @@ -7095,9 +6642,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Match Rule", "help": "Match rule object for deciding when a binding applies, including channel and optional account/peer constraints. Keep rules narrow to avoid accidental agent takeover across contexts.", "hasChildren": true @@ -7109,9 +6654,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Account ID", "help": "Optional account selector for multi-account channel setups so the binding applies only to one identity. Use this when account scoping is required for the route and leave unset otherwise.", "hasChildren": false @@ -7123,9 +6666,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Channel", "help": "Channel/provider identifier this binding applies to, such as `telegram`, `discord`, or a plugin channel ID. Use the configured channel key exactly so binding evaluation works reliably.", "hasChildren": false @@ -7137,9 +6678,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Guild ID", "help": "Optional Discord-style guild/server ID constraint for binding evaluation in multi-server deployments. Use this when the same peer identifiers can appear across different guilds.", "hasChildren": false @@ -7151,9 +6690,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Peer Match", "help": "Optional peer matcher for specific conversations including peer kind and peer id. Use this when only one direct/group/channel target should be pinned to an agent.", "hasChildren": true @@ -7165,9 +6702,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Peer ID", "help": "Conversation identifier used with peer matching, such as a chat ID, channel ID, or group ID from the provider. Keep this exact to avoid silent non-matches.", "hasChildren": false @@ -7179,9 +6714,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Peer Kind", "help": "Peer conversation type: \"direct\", \"group\", \"channel\", or legacy \"dm\" (deprecated alias for direct). Prefer \"direct\" for new configs and keep kind aligned with channel semantics.", "hasChildren": false @@ -7193,9 +6726,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Roles", "help": "Optional role-based filter list used by providers that attach roles to chat context. Use this to route privileged or operational role traffic to specialized agents.", "hasChildren": true @@ -7217,9 +6748,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Team ID", "help": "Optional team/workspace ID constraint used by providers that scope chats under teams. Add this when you need bindings isolated to one workspace context.", "hasChildren": false @@ -7231,9 +6760,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Binding Type", "help": "Binding kind. Use \"route\" (or omit for legacy route entries) for normal routing, and \"acp\" for persistent ACP conversation bindings.", "hasChildren": false @@ -7245,9 +6772,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Broadcast", "help": "Broadcast routing map for sending the same outbound message to multiple peer IDs per source conversation. Keep this minimal and audited because one source can fan out to many destinations.", "hasChildren": true @@ -7259,9 +6784,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Broadcast Destination List", "help": "Per-source broadcast destination list where each key is a source peer ID and the value is an array of destination peer IDs. Keep lists intentional to avoid accidental message amplification.", "hasChildren": true @@ -7281,15 +6804,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "parallel", - "sequential" - ], + "enumValues": ["parallel", "sequential"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Broadcast Strategy", "help": "Delivery order for broadcast fan-out: \"parallel\" sends to all targets concurrently, while \"sequential\" sends one-by-one. Use \"parallel\" for speed and \"sequential\" for stricter ordering/backpressure control.", "hasChildren": false @@ -7301,9 +6819,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser", "help": "Browser runtime controls for local or remote CDP attachment, profile routing, and screenshot/snapshot behavior. Keep defaults unless your automation workflow requires custom browser transport settings.", "hasChildren": true @@ -7315,9 +6831,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Attach-only Mode", "help": "Restricts browser mode to attach-only behavior without starting local browser processes. Use this when all browser sessions are externally managed by a remote CDP provider.", "hasChildren": false @@ -7329,9 +6843,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser CDP Port Range Start", "help": "Starting local CDP port used for auto-allocated browser profile ports. Increase this when host-level port defaults conflict with other local services.", "hasChildren": false @@ -7343,9 +6855,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser CDP URL", "help": "Remote CDP websocket URL used to attach to an externally managed browser instance. Use this for centralized browser hosts and keep URL access restricted to trusted network paths.", "hasChildren": false @@ -7357,9 +6867,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Accent Color", "help": "Default accent color used for browser profile/UI cues where colored identity hints are displayed. Use consistent colors to help operators identify active browser profile context quickly.", "hasChildren": false @@ -7371,9 +6879,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Default Profile", "help": "Default browser profile name selected when callers do not explicitly choose a profile. Use a stable low-privilege profile as the default to reduce accidental cross-context state use.", "hasChildren": false @@ -7385,9 +6891,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Enabled", "help": "Enables browser capability wiring in the gateway so browser tools and CDP-driven workflows can run. Disable when browser automation is not needed to reduce surface area and startup work.", "hasChildren": false @@ -7399,9 +6903,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Evaluate Enabled", "help": "Enables browser-side evaluate helpers for runtime script evaluation capabilities where supported. Keep disabled unless your workflows require evaluate semantics beyond snapshots/navigation.", "hasChildren": false @@ -7413,9 +6915,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Executable Path", "help": "Explicit browser executable path when auto-discovery is insufficient for your host environment. Use absolute stable paths so launch behavior stays deterministic across restarts.", "hasChildren": false @@ -7447,9 +6947,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Headless Mode", "help": "Forces browser launch in headless mode when the local launcher starts browser instances. Keep headless enabled for server environments and disable only when visible UI debugging is required.", "hasChildren": false @@ -7461,9 +6959,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser No-Sandbox Mode", "help": "Disables Chromium sandbox isolation flags for environments where sandboxing fails at runtime. Keep this off whenever possible because process isolation protections are reduced.", "hasChildren": false @@ -7475,9 +6971,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profiles", "help": "Named browser profile connection map used for explicit routing to CDP ports or URLs with optional metadata. Keep profile names consistent and avoid overlapping endpoint definitions.", "hasChildren": true @@ -7499,9 +6993,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profile Attach-only Mode", "help": "Per-profile attach-only override that skips local browser launch and only attaches to an existing CDP endpoint. Useful when one profile is externally managed but others are locally launched.", "hasChildren": false @@ -7513,9 +7005,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profile CDP Port", "help": "Per-profile local CDP port used when connecting to browser instances by port instead of URL. Use unique ports per profile to avoid connection collisions.", "hasChildren": false @@ -7527,9 +7017,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profile CDP URL", "help": "Per-profile CDP websocket URL used for explicit remote browser routing by profile name. Use this when profile connections terminate on remote hosts or tunnels.", "hasChildren": false @@ -7541,9 +7029,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profile Accent Color", "help": "Per-profile accent color for visual differentiation in dashboards and browser-related UI hints. Use distinct colors for high-signal operator recognition of active profiles.", "hasChildren": false @@ -7555,9 +7041,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Browser Profile Driver", "help": "Per-profile browser driver mode: \"openclaw\" (or legacy \"clawd\") or \"extension\" depending on connection/runtime strategy. Use the driver that matches your browser control stack to avoid protocol mismatches.", "hasChildren": false @@ -7569,9 +7053,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Relay Bind Address", "help": "Bind IP address for the Chrome extension relay listener. Leave unset for loopback-only access, or set an explicit non-loopback IP such as 0.0.0.0 only when the relay must be reachable across network namespaces (for example WSL2) and the surrounding network is already trusted.", "hasChildren": false @@ -7583,9 +7065,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Remote CDP Handshake Timeout (ms)", "help": "Timeout in milliseconds for post-connect CDP handshake readiness checks against remote browser targets. Raise this for slow-start remote browsers and lower to fail fast in automation loops.", "hasChildren": false @@ -7597,9 +7077,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Remote CDP Timeout (ms)", "help": "Timeout in milliseconds for connecting to a remote CDP endpoint before failing the browser attach attempt. Increase for high-latency tunnels, or lower for faster failure detection.", "hasChildren": false @@ -7611,9 +7089,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Snapshot Defaults", "help": "Default snapshot capture configuration used when callers do not provide explicit snapshot options. Tune this for consistent capture behavior across channels and automation paths.", "hasChildren": true @@ -7625,9 +7101,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Browser Snapshot Mode", "help": "Default snapshot extraction mode controlling how page content is transformed for agent consumption. Choose the mode that balances readability, fidelity, and token footprint for your workflows.", "hasChildren": false @@ -7639,9 +7113,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Browser SSRF Policy", "help": "Server-side request forgery guardrail settings for browser/network fetch paths that could reach internal hosts. Keep restrictive defaults in production and open only explicitly approved targets.", "hasChildren": true @@ -7653,9 +7125,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Browser Allowed Hostnames", "help": "Explicit hostname allowlist exceptions for SSRF policy checks on browser/network requests. Keep this list minimal and review entries regularly to avoid stale broad access.", "hasChildren": true @@ -7677,9 +7147,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Browser Allow Private Network", "help": "Legacy alias for browser.ssrfPolicy.dangerouslyAllowPrivateNetwork. Prefer the dangerously-named key so risk intent is explicit.", "hasChildren": false @@ -7691,11 +7159,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "security" - ], + "tags": ["access", "advanced", "security"], "label": "Browser Dangerously Allow Private Network", "help": "Allows access to private-network address ranges from browser tooling. Default is enabled for trusted-network operator setups; disable to enforce strict public-only resolution checks.", "hasChildren": false @@ -7707,9 +7171,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Browser Hostname Allowlist", "help": "Legacy/alternate hostname allowlist field used by SSRF policy consumers for explicit host exceptions. Use stable exact hostnames and avoid wildcard-like broad patterns.", "hasChildren": true @@ -7731,9 +7193,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Canvas Host", "help": "Canvas host settings for serving canvas assets and local live-reload behavior used by canvas-enabled workflows. Keep disabled unless canvas-hosted assets are actively used.", "hasChildren": true @@ -7745,9 +7205,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Canvas Host Enabled", "help": "Enables the canvas host server process and routes for serving canvas files. Keep disabled when canvas workflows are inactive to reduce exposed local services.", "hasChildren": false @@ -7759,9 +7217,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "reliability" - ], + "tags": ["reliability"], "label": "Canvas Host Live Reload", "help": "Enables automatic live-reload behavior for canvas assets during development workflows. Keep disabled in production-like environments where deterministic output is preferred.", "hasChildren": false @@ -7773,9 +7229,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Canvas Host Port", "help": "TCP port used by the canvas host HTTP server when canvas hosting is enabled. Choose a non-conflicting port and align firewall/proxy policy accordingly.", "hasChildren": false @@ -7787,9 +7241,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Canvas Host Root Directory", "help": "Filesystem root directory served by canvas host for canvas content and static assets. Use a dedicated directory and avoid broad repo roots for least-privilege file exposure.", "hasChildren": false @@ -7801,9 +7253,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Channels", "help": "Channel provider configurations plus shared defaults that control access policies, heartbeat visibility, and per-surface behavior. Keep defaults centralized and override per provider only where required.", "hasChildren": true @@ -7815,10 +7265,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "BlueBubbles", "help": "iMessage via the BlueBubbles mac app + REST API.", "hasChildren": true @@ -7856,10 +7303,7 @@ { "path": "channels.bluebubbles.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -7891,10 +7335,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -7915,12 +7356,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -7949,10 +7385,7 @@ { "path": "channels.bluebubbles.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -7964,11 +7397,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -8099,11 +7528,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -8152,19 +7577,11 @@ { "path": "channels.bluebubbles.accounts.*.password", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -8381,10 +7798,7 @@ { "path": "channels.bluebubbles.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -8416,10 +7830,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -8450,19 +7861,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "BlueBubbles DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.bluebubbles.allowFrom=[\"*\"].", "hasChildren": false @@ -8490,10 +7892,7 @@ { "path": "channels.bluebubbles.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -8505,11 +7904,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -8640,11 +8035,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -8693,19 +8084,11 @@ { "path": "channels.bluebubbles.password", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -8785,10 +8168,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord", "help": "very well supported right now.", "hasChildren": true @@ -8828,14 +8208,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group-mentions", - "group-all", - "direct", - "all", - "off", - "none" - ], + "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], "deprecated": false, "sensitive": false, "tags": [], @@ -9094,10 +8467,7 @@ { "path": "channels.discord.accounts.*.allowBots", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9117,10 +8487,7 @@ { "path": "channels.discord.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9272,10 +8639,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -9294,10 +8658,7 @@ { "path": "channels.discord.accounts.*.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9307,10 +8668,7 @@ { "path": "channels.discord.accounts.*.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9370,10 +8728,7 @@ { "path": "channels.discord.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9403,10 +8758,7 @@ { "path": "channels.discord.accounts.*.dm.groupChannels.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9428,12 +8780,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -9454,12 +8801,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -9628,10 +8970,7 @@ { "path": "channels.discord.accounts.*.execApprovals.approvers.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -9683,11 +9022,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "dm", - "channel", - "both" - ], + "enumValues": ["dm", "channel", "both"], "deprecated": false, "sensitive": false, "tags": [], @@ -9698,11 +9033,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -9762,17 +9093,9 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.autoArchiveDuration", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, - "enumValues": [ - "60", - "1440", - "4320", - "10080" - ], + "enumValues": ["60", "1440", "4320", "10080"], "deprecated": false, "sensitive": false, "tags": [], @@ -9841,10 +9164,7 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.roles.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -10044,10 +9364,7 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -10069,12 +9386,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -10103,10 +9415,7 @@ { "path": "channels.discord.accounts.*.guilds.*.roles.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -10286,10 +9595,7 @@ { "path": "channels.discord.accounts.*.guilds.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -10431,11 +9737,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -10494,19 +9796,11 @@ { "path": "channels.discord.accounts.*.pluralkit.token", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -10644,12 +9938,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "online", - "dnd", - "idle", - "invisible" - ], + "enumValues": ["online", "dnd", "idle", "invisible"], "deprecated": false, "sensitive": false, "tags": [], @@ -10658,17 +9947,9 @@ { "path": "channels.discord.accounts.*.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, "tags": [], @@ -10679,11 +9960,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "partial", - "block", - "off" - ], + "enumValues": ["partial", "block", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -10762,19 +10039,11 @@ { "path": "channels.discord.accounts.*.token", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -10932,12 +10201,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "always", - "inbound", - "tagged" - ], + "enumValues": ["off", "always", "inbound", "tagged"], "deprecated": false, "sensitive": false, "tags": [], @@ -11066,20 +10330,11 @@ { "path": "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "media", - "network", - "security" - ], + "tags": ["auth", "channels", "media", "network", "security"], "hasChildren": true }, { @@ -11117,11 +10372,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "auto", - "on", - "off" - ], + "enumValues": ["auto", "on", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -11262,10 +10513,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "final", - "all" - ], + "enumValues": ["final", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -11374,20 +10622,11 @@ { "path": "channels.discord.accounts.*.voice.tts.openai.apiKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "media", - "network", - "security" - ], + "tags": ["auth", "channels", "media", "network", "security"], "hasChildren": true }, { @@ -11485,11 +10724,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "elevenlabs", - "openai", - "edge" - ], + "enumValues": ["elevenlabs", "openai", "edge"], "deprecated": false, "sensitive": false, "tags": [], @@ -11530,14 +10765,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group-mentions", - "group-all", - "direct", - "all", - "off", - "none" - ], + "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], "deprecated": false, "sensitive": false, "tags": [], @@ -11750,10 +10978,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Presence Activity", "help": "Discord presence activity text (defaults to custom status).", "hasChildren": false @@ -11765,10 +10990,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Presence Activity Type", "help": "Discord presence activity type (0=Playing,1=Streaming,2=Listening,3=Watching,4=Custom,5=Competing).", "hasChildren": false @@ -11780,10 +11002,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Presence Activity URL", "help": "Discord presence streaming URL (required for activityType=1).", "hasChildren": false @@ -11811,18 +11030,11 @@ { "path": "channels.discord.allowBots", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Discord Allow Bot Messages", "help": "Allow bot-authored messages to trigger Discord replies (default: false). Set \"mentions\" to only accept bot messages that mention the bot.", "hasChildren": false @@ -11840,10 +11052,7 @@ { "path": "channels.discord.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -11867,10 +11076,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Auto Presence Degraded Text", "help": "Optional custom status text while runtime/model availability is degraded or unknown (idle).", "hasChildren": false @@ -11882,10 +11088,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Auto Presence Enabled", "help": "Enable automatic Discord bot presence updates based on runtime/model availability signals. When enabled: healthy=>online, degraded/unknown=>idle, exhausted/unavailable=>dnd.", "hasChildren": false @@ -11897,10 +11100,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Auto Presence Exhausted Text", "help": "Optional custom status text while runtime detects exhausted/unavailable model quota (dnd). Supports {reason} template placeholder.", "hasChildren": false @@ -11912,11 +11112,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Discord Auto Presence Healthy Text", "help": "Optional custom status text while runtime is healthy (online). If omitted, falls back to static channels.discord.activity when set.", "hasChildren": false @@ -11928,11 +11124,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord Auto Presence Check Interval (ms)", "help": "How often to evaluate Discord auto-presence state in milliseconds (default: 30000).", "hasChildren": false @@ -11944,11 +11136,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord Auto Presence Min Update Interval (ms)", "help": "Minimum time between actual Discord presence update calls in milliseconds (default: 15000). Prevents status spam on noisy state changes.", "hasChildren": false @@ -12028,10 +11216,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -12050,17 +11235,11 @@ { "path": "channels.discord.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Native Commands", "help": "Override native commands for Discord (bool or \"auto\").", "hasChildren": false @@ -12068,17 +11247,11 @@ { "path": "channels.discord.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Native Skill Commands", "help": "Override native skill commands for Discord (bool or \"auto\").", "hasChildren": false @@ -12090,10 +11263,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Config Writes", "help": "Allow Discord to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -12151,10 +11321,7 @@ { "path": "channels.discord.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -12184,10 +11351,7 @@ { "path": "channels.discord.dm.groupChannels.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -12209,19 +11373,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Discord DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.discord.allowFrom=[\"*\"] (legacy: channels.discord.dm.allowFrom).", "hasChildren": false @@ -12241,19 +11396,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Discord DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.discord.allowFrom=[\"*\"].", "hasChildren": false @@ -12305,10 +11451,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Draft Chunk Break Preference", "help": "Preferred breakpoints for Discord draft chunks (paragraph | newline | sentence). Default: paragraph.", "hasChildren": false @@ -12320,11 +11463,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord Draft Chunk Max Chars", "help": "Target max size for a Discord stream preview chunk when channels.discord.streaming=\"block\" (default: 800; clamped to channels.discord.textChunkLimit).", "hasChildren": false @@ -12336,10 +11475,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Draft Chunk Min Chars", "help": "Minimum chars before emitting a Discord stream preview update when channels.discord.streaming=\"block\" (default: 200).", "hasChildren": false @@ -12371,11 +11507,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord EventQueue Listener Timeout (ms)", "help": "Canonical Discord listener timeout control in ms for gateway normalization/enqueue handlers. Default is 120000 in OpenClaw; set per account via channels.discord.accounts..eventQueue.listenerTimeout.", "hasChildren": false @@ -12387,11 +11519,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord EventQueue Max Concurrency", "help": "Optional Discord EventQueue concurrency override (max concurrent handler executions). Set per account via channels.discord.accounts..eventQueue.maxConcurrency.", "hasChildren": false @@ -12403,11 +11531,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord EventQueue Max Queue Size", "help": "Optional Discord EventQueue capacity override (max queued events before backpressure). Set per account via channels.discord.accounts..eventQueue.maxQueueSize.", "hasChildren": false @@ -12455,10 +11579,7 @@ { "path": "channels.discord.execApprovals.approvers.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -12510,11 +11631,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "dm", - "channel", - "both" - ], + "enumValues": ["dm", "channel", "both"], "deprecated": false, "sensitive": false, "tags": [], @@ -12525,11 +11642,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -12589,17 +11702,9 @@ { "path": "channels.discord.guilds.*.channels.*.autoArchiveDuration", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, - "enumValues": [ - "60", - "1440", - "4320", - "10080" - ], + "enumValues": ["60", "1440", "4320", "10080"], "deprecated": false, "sensitive": false, "tags": [], @@ -12668,10 +11773,7 @@ { "path": "channels.discord.guilds.*.channels.*.roles.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -12871,10 +11973,7 @@ { "path": "channels.discord.guilds.*.channels.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -12896,12 +11995,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -12930,10 +12024,7 @@ { "path": "channels.discord.guilds.*.roles.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -13113,10 +12204,7 @@ { "path": "channels.discord.guilds.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -13210,11 +12298,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord Inbound Worker Timeout (ms)", "help": "Optional queued Discord inbound worker timeout in ms. This is separate from Carbon listener timeouts; defaults to 1800000 and can be disabled with 0. Set per account via channels.discord.accounts..inboundWorker.runTimeoutMs.", "hasChildren": false @@ -13236,10 +12320,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Guild Members Intent", "help": "Enable the Guild Members privileged intent. Must also be enabled in the Discord Developer Portal. Default: false.", "hasChildren": false @@ -13251,10 +12332,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Presence Intent", "help": "Enable the Guild Presences privileged intent. Must also be enabled in the Discord Developer Portal. Allows tracking user activities (e.g. Spotify). Default: false.", "hasChildren": false @@ -13274,11 +12352,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -13291,11 +12365,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Discord Max Lines Per Message", "help": "Soft max line count per Discord message (default: 17).", "hasChildren": false @@ -13337,10 +12407,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord PluralKit Enabled", "help": "Resolve PluralKit proxied messages and treat system members as distinct senders.", "hasChildren": false @@ -13348,19 +12415,11 @@ { "path": "channels.discord.pluralkit.token", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Discord PluralKit Token", "help": "Optional PluralKit token for resolving private systems or members.", "hasChildren": true @@ -13402,10 +12461,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Proxy URL", "help": "Proxy URL for Discord gateway + API requests (app-id lookup and allowlist resolution). Set per account via channels.discord.accounts..proxy.", "hasChildren": false @@ -13447,11 +12503,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Discord Retry Attempts", "help": "Max retry attempts for outbound Discord API calls (default: 3).", "hasChildren": false @@ -13463,11 +12515,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Discord Retry Jitter", "help": "Jitter factor (0-1) applied to Discord retry delays.", "hasChildren": false @@ -13479,12 +12527,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance", - "reliability" - ], + "tags": ["channels", "network", "performance", "reliability"], "label": "Discord Retry Max Delay (ms)", "help": "Maximum retry delay cap in ms for Discord outbound calls.", "hasChildren": false @@ -13496,11 +12539,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Discord Retry Min Delay (ms)", "help": "Minimum retry delay in ms for Discord outbound calls.", "hasChildren": false @@ -13530,18 +12569,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "online", - "dnd", - "idle", - "invisible" - ], + "enumValues": ["online", "dnd", "idle", "invisible"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Presence Status", "help": "Discord presence status (online, dnd, idle, invisible).", "hasChildren": false @@ -13549,23 +12580,12 @@ { "path": "channels.discord.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Streaming Mode", "help": "Unified Discord stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". \"progress\" maps to \"partial\" on Discord. Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -13575,17 +12595,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "partial", - "block", - "off" - ], + "enumValues": ["partial", "block", "off"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Stream Mode (Legacy)", "help": "Legacy Discord preview mode alias (off | partial | block); auto-migrated to channels.discord.streaming.", "hasChildren": false @@ -13617,11 +12630,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Discord Thread Binding Enabled", "help": "Enable Discord thread binding features (/focus, bound-thread routing/delivery, and thread-bound subagent sessions). Overrides session.threadBindings.enabled when set.", "hasChildren": false @@ -13633,11 +12642,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Discord Thread Binding Idle Timeout (hours)", "help": "Inactivity window in hours for Discord thread-bound sessions (/focus and spawned thread sessions). Set 0 to disable idle auto-unfocus (default: 24). Overrides session.threadBindings.idleHours when set.", "hasChildren": false @@ -13649,12 +12654,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance", - "storage" - ], + "tags": ["channels", "network", "performance", "storage"], "label": "Discord Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for Discord thread-bound sessions. Set 0 to disable hard cap (default: 0). Overrides session.threadBindings.maxAgeHours when set.", "hasChildren": false @@ -13666,11 +12666,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Discord Thread-Bound ACP Spawn", "help": "Allow /acp spawn to auto-create and bind Discord threads for ACP sessions (default: false; opt-in). Set true to enable thread-bound ACP spawns for this account/channel.", "hasChildren": false @@ -13682,11 +12678,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Discord Thread-Bound Subagent Spawn", "help": "Allow subagent spawns with thread=true to auto-create and bind Discord threads (default: false; opt-in). Set true to enable thread-bound subagent spawns for this account/channel.", "hasChildren": false @@ -13694,19 +12686,11 @@ { "path": "channels.discord.token", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Discord Bot Token", "help": "Discord bot token used for gateway and REST API authentication for this provider account. Keep this secret out of committed config and rotate immediately after any leak.", "hasChildren": true @@ -13768,10 +12752,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Component Accent Color", "help": "Accent color for Discord component containers (hex). Set per account via channels.discord.accounts..ui.components.accentColor.", "hasChildren": false @@ -13793,10 +12774,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Voice Auto-Join", "help": "Voice channels to auto-join on startup (list of guildId/channelId entries).", "hasChildren": true @@ -13838,10 +12816,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Voice DAVE Encryption", "help": "Toggle DAVE end-to-end encryption for Discord voice joins (default: true in @discordjs/voice; Discord may require this).", "hasChildren": false @@ -13853,10 +12828,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Voice Decrypt Failure Tolerance", "help": "Consecutive decrypt failures before DAVE attempts session recovery (passed to @discordjs/voice; default: 24).", "hasChildren": false @@ -13868,10 +12840,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Discord Voice Enabled", "help": "Enable Discord voice channel conversations (default: true). Omit channels.discord.voice to keep voice support disabled for the account.", "hasChildren": false @@ -13883,11 +12852,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "media", - "network" - ], + "tags": ["channels", "media", "network"], "label": "Discord Voice Text-to-Speech", "help": "Optional TTS overrides for Discord voice playback (merged with messages.tts).", "hasChildren": true @@ -13897,12 +12862,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "always", - "inbound", - "tagged" - ], + "enumValues": ["off", "always", "inbound", "tagged"], "deprecated": false, "sensitive": false, "tags": [], @@ -14031,20 +12991,11 @@ { "path": "channels.discord.voice.tts.elevenlabs.apiKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "media", - "network", - "security" - ], + "tags": ["auth", "channels", "media", "network", "security"], "hasChildren": true }, { @@ -14082,11 +13033,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "auto", - "on", - "off" - ], + "enumValues": ["auto", "on", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -14227,10 +13174,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "final", - "all" - ], + "enumValues": ["final", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -14339,20 +13283,11 @@ { "path": "channels.discord.voice.tts.openai.apiKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "media", - "network", - "security" - ], + "tags": ["auth", "channels", "media", "network", "security"], "hasChildren": true }, { @@ -14450,11 +13385,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "elevenlabs", - "openai", - "edge" - ], + "enumValues": ["elevenlabs", "openai", "edge"], "deprecated": false, "sensitive": false, "tags": [], @@ -14487,10 +13418,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Feishu", "help": "飞书/Lark enterprise messaging.", "hasChildren": true @@ -14548,10 +13476,7 @@ { "path": "channels.feishu.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -14571,10 +13496,7 @@ { "path": "channels.feishu.accounts.*.appSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -14676,10 +13598,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -14700,10 +13619,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "websocket", - "webhook" - ], + "enumValues": ["websocket", "webhook"], "deprecated": false, "sensitive": false, "tags": [], @@ -14724,11 +13640,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "pairing", - "allowlist" - ], + "enumValues": ["open", "pairing", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -14779,10 +13691,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "feishu", - "lark" - ], + "enumValues": ["feishu", "lark"], "deprecated": false, "sensitive": false, "tags": [], @@ -14801,10 +13710,7 @@ { "path": "channels.feishu.accounts.*.encryptKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -14854,10 +13760,7 @@ { "path": "channels.feishu.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -14869,11 +13772,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "allowlist", - "disabled" - ], + "enumValues": ["open", "allowlist", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -14912,10 +13811,7 @@ { "path": "channels.feishu.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -14937,12 +13833,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group", - "group_sender", - "group_topic", - "group_topic_sender" - ], + "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], "deprecated": false, "sensitive": false, "tags": [], @@ -14953,10 +13844,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -15057,10 +13945,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -15079,10 +13964,7 @@ { "path": "channels.feishu.accounts.*.groupSenderAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15094,12 +13976,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group", - "group_sender", - "group_topic", - "group_topic_sender" - ], + "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], "deprecated": false, "sensitive": false, "tags": [], @@ -15130,10 +14007,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "visible", - "hidden" - ], + "enumValues": ["visible", "hidden"], "deprecated": false, "sensitive": false, "tags": [], @@ -15174,11 +14048,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "native", - "escape", - "strip" - ], + "enumValues": ["native", "escape", "strip"], "deprecated": false, "sensitive": false, "tags": [], @@ -15189,11 +14059,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "native", - "ascii", - "simple" - ], + "enumValues": ["native", "ascii", "simple"], "deprecated": false, "sensitive": false, "tags": [], @@ -15224,11 +14090,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all" - ], + "enumValues": ["off", "own", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -15239,11 +14101,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "auto", - "raw", - "card" - ], + "enumValues": ["auto", "raw", "card"], "deprecated": false, "sensitive": false, "tags": [], @@ -15254,10 +14112,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -15378,10 +14233,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -15400,10 +14252,7 @@ { "path": "channels.feishu.accounts.*.verificationToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15503,10 +14352,7 @@ { "path": "channels.feishu.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15526,10 +14372,7 @@ { "path": "channels.feishu.appSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15631,10 +14474,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -15655,10 +14495,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "websocket", - "webhook" - ], + "enumValues": ["websocket", "webhook"], "defaultValue": "websocket", "deprecated": false, "sensitive": false, @@ -15690,11 +14527,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "pairing", - "allowlist" - ], + "enumValues": ["open", "pairing", "allowlist"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -15746,10 +14579,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "feishu", - "lark" - ], + "enumValues": ["feishu", "lark"], "deprecated": false, "sensitive": false, "tags": [], @@ -15818,10 +14648,7 @@ { "path": "channels.feishu.encryptKey", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15871,10 +14698,7 @@ { "path": "channels.feishu.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15886,11 +14710,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "allowlist", - "disabled" - ], + "enumValues": ["open", "allowlist", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -15929,10 +14749,7 @@ { "path": "channels.feishu.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -15954,12 +14771,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group", - "group_sender", - "group_topic", - "group_topic_sender" - ], + "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], "deprecated": false, "sensitive": false, "tags": [], @@ -15970,10 +14782,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -16074,10 +14883,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -16096,10 +14902,7 @@ { "path": "channels.feishu.groupSenderAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -16111,12 +14914,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "group", - "group_sender", - "group_topic", - "group_topic_sender" - ], + "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], "deprecated": false, "sensitive": false, "tags": [], @@ -16147,10 +14945,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "visible", - "hidden" - ], + "enumValues": ["visible", "hidden"], "deprecated": false, "sensitive": false, "tags": [], @@ -16191,11 +14986,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "native", - "escape", - "strip" - ], + "enumValues": ["native", "escape", "strip"], "deprecated": false, "sensitive": false, "tags": [], @@ -16206,11 +14997,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "native", - "ascii", - "simple" - ], + "enumValues": ["native", "ascii", "simple"], "deprecated": false, "sensitive": false, "tags": [], @@ -16231,11 +15018,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "off", - "own", - "all" - ], + "enumValues": ["off", "own", "all"], "defaultValue": "own", "deprecated": false, "sensitive": false, @@ -16247,11 +15030,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "auto", - "raw", - "card" - ], + "enumValues": ["auto", "raw", "card"], "deprecated": false, "sensitive": false, "tags": [], @@ -16262,10 +15041,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -16388,10 +15164,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "disabled", - "enabled" - ], + "enumValues": ["disabled", "enabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -16411,10 +15184,7 @@ { "path": "channels.feishu.verificationToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -16489,10 +15259,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Google Chat", "help": "Google Workspace Chat app with HTTP webhook.", "hasChildren": true @@ -16572,10 +15339,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "app-url", - "project-number" - ], + "enumValues": ["app-url", "project-number"], "deprecated": false, "sensitive": false, "tags": [], @@ -16666,10 +15430,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -16728,10 +15489,7 @@ { "path": "channels.googlechat.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -16753,12 +15511,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -16828,10 +15581,7 @@ { "path": "channels.googlechat.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -16843,11 +15593,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -16927,10 +15673,7 @@ { "path": "channels.googlechat.accounts.*.groups.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -17020,18 +15763,11 @@ { "path": "channels.googlechat.accounts.*.serviceAccount", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "channels", - "network", - "security" - ], + "tags": ["channels", "network", "security"], "hasChildren": true }, { @@ -17090,11 +15826,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "channels", - "network", - "security" - ], + "tags": ["channels", "network", "security"], "hasChildren": true }, { @@ -17132,11 +15864,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "replace", - "status_final", - "append" - ], + "enumValues": ["replace", "status_final", "append"], "defaultValue": "replace", "deprecated": false, "sensitive": false, @@ -17158,11 +15886,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "none", - "message", - "reaction" - ], + "enumValues": ["none", "message", "reaction"], "deprecated": false, "sensitive": false, "tags": [], @@ -17243,10 +15967,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "app-url", - "project-number" - ], + "enumValues": ["app-url", "project-number"], "deprecated": false, "sensitive": false, "tags": [], @@ -17337,10 +16058,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -17409,10 +16127,7 @@ { "path": "channels.googlechat.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -17434,12 +16149,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -17509,10 +16219,7 @@ { "path": "channels.googlechat.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -17524,11 +16231,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -17608,10 +16311,7 @@ { "path": "channels.googlechat.groups.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -17701,18 +16401,11 @@ { "path": "channels.googlechat.serviceAccount", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "channels", - "network", - "security" - ], + "tags": ["channels", "network", "security"], "hasChildren": true }, { @@ -17771,11 +16464,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "channels", - "network", - "security" - ], + "tags": ["channels", "network", "security"], "hasChildren": true }, { @@ -17813,11 +16502,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "replace", - "status_final", - "append" - ], + "enumValues": ["replace", "status_final", "append"], "defaultValue": "replace", "deprecated": false, "sensitive": false, @@ -17839,11 +16524,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "none", - "message", - "reaction" - ], + "enumValues": ["none", "message", "reaction"], "deprecated": false, "sensitive": false, "tags": [], @@ -17876,10 +16557,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "iMessage", "help": "this is still a work in progress.", "hasChildren": true @@ -17917,10 +16595,7 @@ { "path": "channels.imessage.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -18022,10 +16697,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -18086,12 +16758,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -18151,10 +16818,7 @@ { "path": "channels.imessage.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -18166,11 +16830,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -18452,11 +17112,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -18565,10 +17221,7 @@ { "path": "channels.imessage.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -18670,10 +17323,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -18686,11 +17336,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "iMessage CLI Path", "help": "Filesystem path to the iMessage bridge CLI binary used for send/receive operations. Set explicitly when the binary is not on PATH in service runtime environments.", "hasChildren": false @@ -18702,10 +17348,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "iMessage Config Writes", "help": "Allow iMessage to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -18755,20 +17398,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "iMessage DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.imessage.allowFrom=[\"*\"].", "hasChildren": false @@ -18826,10 +17460,7 @@ { "path": "channels.imessage.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -18841,11 +17472,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -19127,11 +17754,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -19234,10 +17857,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "IRC", "help": "classic IRC networks with DM/channel routing and pairing controls.", "hasChildren": true @@ -19275,10 +17895,7 @@ { "path": "channels.irc.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -19360,10 +17977,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -19394,12 +18008,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -19459,10 +18068,7 @@ { "path": "channels.irc.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -19474,11 +18080,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -19518,10 +18120,7 @@ { "path": "channels.irc.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -19763,11 +18362,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -19850,12 +18445,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": false }, { @@ -19905,12 +18495,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": false }, { @@ -19996,10 +18581,7 @@ { "path": "channels.irc.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -20081,10 +18663,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -20125,20 +18704,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "IRC DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.irc.allowFrom=[\"*\"].", "hasChildren": false @@ -20196,10 +18766,7 @@ { "path": "channels.irc.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -20211,11 +18778,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -20255,10 +18818,7 @@ { "path": "channels.irc.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -20500,11 +19060,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -20577,10 +19133,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "IRC NickServ Enabled", "help": "Enable NickServ identify/register after connect (defaults to enabled when password is configured).", "hasChildren": false @@ -20592,12 +19145,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "IRC NickServ Password", "help": "NickServ password used for IDENTIFY/REGISTER (sensitive).", "hasChildren": false @@ -20609,13 +19157,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "channels", - "network", - "security", - "storage" - ], + "tags": ["auth", "channels", "network", "security", "storage"], "label": "IRC NickServ Password File", "help": "Optional file path containing NickServ password.", "hasChildren": false @@ -20627,10 +19169,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "IRC NickServ Register", "help": "If true, send NickServ REGISTER on every connect. Use once for initial registration, then disable.", "hasChildren": false @@ -20642,10 +19181,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "IRC NickServ Register Email", "help": "Email used with NickServ REGISTER (required when register=true).", "hasChildren": false @@ -20657,10 +19193,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "IRC NickServ Service", "help": "NickServ service nick (default: NickServ).", "hasChildren": false @@ -20672,12 +19205,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": false }, { @@ -20757,10 +19285,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "LINE", "help": "LINE Messaging API bot for Japan/Taiwan/Thailand markets.", "hasChildren": true @@ -20798,10 +19323,7 @@ { "path": "channels.line.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -20833,12 +19355,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "allowlist", - "pairing", - "disabled" - ], + "enumValues": ["open", "allowlist", "pairing", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -20868,10 +19385,7 @@ { "path": "channels.line.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -20883,11 +19397,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "allowlist", - "disabled" - ], + "enumValues": ["open", "allowlist", "disabled"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -20927,10 +19437,7 @@ { "path": "channels.line.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21060,10 +19567,7 @@ { "path": "channels.line.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21105,12 +19609,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "allowlist", - "pairing", - "disabled" - ], + "enumValues": ["open", "allowlist", "pairing", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -21140,10 +19639,7 @@ { "path": "channels.line.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21155,11 +19651,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "allowlist", - "disabled" - ], + "enumValues": ["open", "allowlist", "disabled"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -21199,10 +19691,7 @@ { "path": "channels.line.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21326,10 +19815,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Matrix", "help": "open protocol; configure a homeserver + access token.", "hasChildren": true @@ -21438,11 +19924,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "always", - "allowlist", - "off" - ], + "enumValues": ["always", "allowlist", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -21461,10 +19943,7 @@ { "path": "channels.matrix.autoJoinAllowlist.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21476,10 +19955,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -21528,10 +20004,7 @@ { "path": "channels.matrix.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21553,12 +20026,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -21597,10 +20065,7 @@ { "path": "channels.matrix.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21612,11 +20077,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -21795,10 +20256,7 @@ { "path": "channels.matrix.groups.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21840,11 +20298,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -21873,10 +20327,7 @@ { "path": "channels.matrix.password", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -21918,11 +20369,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "first", - "all" - ], + "enumValues": ["off", "first", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -22111,10 +20558,7 @@ { "path": "channels.matrix.rooms.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22136,11 +20580,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "inbound", - "always" - ], + "enumValues": ["off", "inbound", "always"], "deprecated": false, "sensitive": false, "tags": [], @@ -22163,10 +20603,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost", "help": "self-hosted Slack-style chat; install the plugin to enable.", "hasChildren": true @@ -22224,10 +20661,7 @@ { "path": "channels.mattermost.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22297,10 +20731,7 @@ { "path": "channels.mattermost.accounts.*.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22362,11 +20793,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "oncall", - "onmessage", - "onchar" - ], + "enumValues": ["oncall", "onmessage", "onchar"], "deprecated": false, "sensitive": false, "tags": [], @@ -22377,10 +20804,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -22419,10 +20843,7 @@ { "path": "channels.mattermost.accounts.*.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22432,10 +20853,7 @@ { "path": "channels.mattermost.accounts.*.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22467,12 +20885,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -22502,10 +20915,7 @@ { "path": "channels.mattermost.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22517,11 +20927,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -22583,11 +20989,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -22628,11 +21030,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "first", - "all" - ], + "enumValues": ["off", "first", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -22701,10 +21099,7 @@ { "path": "channels.mattermost.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22718,10 +21113,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost Base URL", "help": "Base URL for your Mattermost server (e.g., https://chat.example.com).", "hasChildren": false @@ -22779,19 +21171,11 @@ { "path": "channels.mattermost.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Mattermost Bot Token", "help": "Bot token from Mattermost System Console -> Integrations -> Bot Accounts.", "hasChildren": true @@ -22851,17 +21235,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "oncall", - "onmessage", - "onchar" - ], + "enumValues": ["oncall", "onmessage", "onchar"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost Chat Mode", "help": "Reply to channel messages on mention (\"oncall\"), on trigger chars (\">\" or \"!\") (\"onchar\"), or on every message (\"onmessage\").", "hasChildren": false @@ -22871,10 +21248,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -22913,10 +21287,7 @@ { "path": "channels.mattermost.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22926,10 +21297,7 @@ { "path": "channels.mattermost.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -22943,10 +21311,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost Config Writes", "help": "Allow Mattermost to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -22976,12 +21341,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -23011,10 +21371,7 @@ { "path": "channels.mattermost.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -23026,11 +21383,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -23092,11 +21445,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -23119,10 +21468,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost Onchar Prefixes", "help": "Trigger prefixes for onchar mode (default: [\">\", \"!\"]).", "hasChildren": true @@ -23142,11 +21488,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "first", - "all" - ], + "enumValues": ["off", "first", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -23159,10 +21501,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Mattermost Require Mention", "help": "Require @mention in channels before responding (default: true).", "hasChildren": false @@ -23194,10 +21533,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Microsoft Teams", "help": "Bot Framework; enterprise support.", "hasChildren": true @@ -23235,19 +21571,11 @@ { "path": "channels.msteams.appPassword", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -23345,10 +21673,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -23361,10 +21686,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "MS Teams Config Writes", "help": "Allow Microsoft Teams to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -23404,12 +21726,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -23481,11 +21798,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -23577,11 +21890,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -23642,10 +21951,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "thread", - "top-level" - ], + "enumValues": ["thread", "top-level"], "deprecated": false, "sensitive": false, "tags": [], @@ -23726,10 +22032,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "thread", - "top-level" - ], + "enumValues": ["thread", "top-level"], "deprecated": false, "sensitive": false, "tags": [], @@ -23900,10 +22203,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "thread", - "top-level" - ], + "enumValues": ["thread", "top-level"], "deprecated": false, "sensitive": false, "tags": [], @@ -24126,10 +22426,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Nextcloud Talk", "help": "Self-hosted chat via Nextcloud Talk webhook bots.", "hasChildren": true @@ -24177,10 +22474,7 @@ { "path": "channels.nextcloud-talk.accounts.*.apiPassword", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -24300,10 +22594,7 @@ { "path": "channels.nextcloud-talk.accounts.*.botSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -24355,10 +22646,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -24379,12 +22667,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -24456,11 +22739,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -24492,11 +22771,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -24765,10 +23040,7 @@ { "path": "channels.nextcloud-talk.apiPassword", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -24888,10 +23160,7 @@ { "path": "channels.nextcloud-talk.botSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -24943,10 +23212,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -24977,12 +23243,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -25054,11 +23315,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -25090,11 +23347,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -25347,10 +23600,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Nostr", "help": "Decentralized DMs via Nostr relays (NIP-04)", "hasChildren": true @@ -25368,10 +23618,7 @@ { "path": "channels.nostr.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -25393,12 +23640,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -25429,11 +23671,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -25576,10 +23814,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Signal", "help": "signal-cli linked device; more setup (David Reagans: \"Hop on Discord.\").", "hasChildren": true @@ -25591,10 +23826,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Signal Account", "help": "Signal account identifier (phone/number handle) used to bind this channel config to a specific Signal identity. Keep this aligned with your linked device/session state.", "hasChildren": false @@ -25672,10 +23904,7 @@ { "path": "channels.signal.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -25767,10 +23996,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -25821,12 +24047,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -25886,10 +24107,7 @@ { "path": "channels.signal.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -25901,11 +24119,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -26227,11 +24441,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -26270,10 +24480,7 @@ { "path": "channels.signal.accounts.*.reactionAllowlist.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -26285,12 +24492,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "ack", - "minimal", - "extensive" - ], + "enumValues": ["off", "ack", "minimal", "extensive"], "deprecated": false, "sensitive": false, "tags": [], @@ -26301,12 +24503,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -26405,10 +24602,7 @@ { "path": "channels.signal.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -26500,10 +24694,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -26526,10 +24717,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Signal Config Writes", "help": "Allow Signal to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -26569,20 +24757,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Signal DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.signal.allowFrom=[\"*\"].", "hasChildren": false @@ -26640,10 +24819,7 @@ { "path": "channels.signal.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -26655,11 +24831,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -26981,11 +25153,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -27024,10 +25192,7 @@ { "path": "channels.signal.reactionAllowlist.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27039,12 +25204,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "ack", - "minimal", - "extensive" - ], + "enumValues": ["off", "ack", "minimal", "extensive"], "deprecated": false, "sensitive": false, "tags": [], @@ -27055,12 +25215,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -27123,10 +25278,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack", "help": "supported (Socket Mode).", "hasChildren": true @@ -27274,10 +25426,7 @@ { "path": "channels.slack.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27287,19 +25436,11 @@ { "path": "channels.slack.accounts.*.appToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -27385,19 +25526,11 @@ { "path": "channels.slack.accounts.*.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -27433,10 +25566,7 @@ { "path": "channels.slack.accounts.*.capabilities", "kind": "channel", - "type": [ - "array", - "object" - ], + "type": ["array", "object"], "required": false, "deprecated": false, "sensitive": false, @@ -27716,10 +25846,7 @@ { "path": "channels.slack.accounts.*.channels.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27731,10 +25858,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -27753,10 +25877,7 @@ { "path": "channels.slack.accounts.*.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27766,10 +25887,7 @@ { "path": "channels.slack.accounts.*.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27829,10 +25947,7 @@ { "path": "channels.slack.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27862,10 +25977,7 @@ { "path": "channels.slack.accounts.*.dm.groupChannels.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -27887,12 +25999,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -27923,12 +26030,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -27979,11 +26081,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -28074,11 +26172,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -28099,10 +26193,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "socket", - "http" - ], + "enumValues": ["socket", "http"], "deprecated": false, "sensitive": false, "tags": [], @@ -28141,10 +26232,7 @@ { "path": "channels.slack.accounts.*.reactionAllowlist.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -28156,12 +26244,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -28240,19 +26323,11 @@ { "path": "channels.slack.accounts.*.signingSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -28338,17 +26413,9 @@ { "path": "channels.slack.accounts.*.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, "tags": [], @@ -28359,11 +26426,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "replace", - "status_final", - "append" - ], + "enumValues": ["replace", "status_final", "append"], "deprecated": false, "sensitive": false, "tags": [], @@ -28394,10 +26457,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "thread", - "channel" - ], + "enumValues": ["thread", "channel"], "deprecated": false, "sensitive": false, "tags": [], @@ -28436,19 +26496,11 @@ { "path": "channels.slack.accounts.*.userToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -28609,11 +26661,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Slack Allow Bot Messages", "help": "Allow bot-authored messages to trigger Slack replies (default: false).", "hasChildren": false @@ -28631,10 +26679,7 @@ { "path": "channels.slack.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -28644,19 +26689,11 @@ { "path": "channels.slack.appToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Slack App Token", "help": "Slack app-level token used for Socket Mode connections and event transport when enabled. Use least-privilege app scopes and store this token as a secret.", "hasChildren": true @@ -28744,19 +26781,11 @@ { "path": "channels.slack.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Slack Bot Token", "help": "Slack bot token used for standard chat actions in the configured workspace. Keep this credential scoped and rotate if workspace app permissions change.", "hasChildren": true @@ -28794,10 +26823,7 @@ { "path": "channels.slack.capabilities", "kind": "channel", - "type": [ - "array", - "object" - ], + "type": ["array", "object"], "required": false, "deprecated": false, "sensitive": false, @@ -28821,10 +26847,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Interactive Replies", "help": "Enable agent-authored Slack interactive reply directives (`[[slack_buttons: ...]]`, `[[slack_select: ...]]`). Default: false.", "hasChildren": false @@ -29082,10 +27105,7 @@ { "path": "channels.slack.channels.*.users.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -29097,10 +27117,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -29119,17 +27136,11 @@ { "path": "channels.slack.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Native Commands", "help": "Override native commands for Slack (bool or \"auto\").", "hasChildren": false @@ -29137,17 +27148,11 @@ { "path": "channels.slack.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Native Skill Commands", "help": "Override native skill commands for Slack (bool or \"auto\").", "hasChildren": false @@ -29159,10 +27164,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Config Writes", "help": "Allow Slack to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -29220,10 +27222,7 @@ { "path": "channels.slack.dm.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -29253,10 +27252,7 @@ { "path": "channels.slack.dm.groupChannels.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -29278,19 +27274,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Slack DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.slack.allowFrom=[\"*\"] (legacy: channels.slack.dm.allowFrom).", "hasChildren": false @@ -29320,19 +27307,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Slack DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.slack.allowFrom=[\"*\"].", "hasChildren": false @@ -29382,11 +27360,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -29478,11 +27452,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -29503,10 +27473,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "socket", - "http" - ], + "enumValues": ["socket", "http"], "defaultValue": "socket", "deprecated": false, "sensitive": false, @@ -29530,10 +27497,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Native Streaming", "help": "Enable native Slack text streaming (chat.startStream/chat.appendStream/chat.stopStream) when channels.slack.streaming is partial (default: true).", "hasChildren": false @@ -29551,10 +27515,7 @@ { "path": "channels.slack.reactionAllowlist.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -29566,12 +27527,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all", - "allowlist" - ], + "enumValues": ["off", "own", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -29650,19 +27606,11 @@ { "path": "channels.slack.signingSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -29748,23 +27696,12 @@ { "path": "channels.slack.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Streaming Mode", "help": "Unified Slack stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -29774,17 +27711,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "replace", - "status_final", - "append" - ], + "enumValues": ["replace", "status_final", "append"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Stream Mode (Legacy)", "help": "Legacy Slack preview mode alias (replace | status_final | append); auto-migrated to channels.slack.streaming.", "hasChildren": false @@ -29814,16 +27744,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "thread", - "channel" - ], + "enumValues": ["thread", "channel"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Thread History Scope", "help": "Scope for Slack thread history context (\"thread\" isolates per thread; \"channel\" reuses channel history).", "hasChildren": false @@ -29835,10 +27759,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Slack Thread Parent Inheritance", "help": "If true, Slack thread sessions inherit the parent channel transcript (default: false).", "hasChildren": false @@ -29850,11 +27771,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Slack Thread Initial History Limit", "help": "Maximum number of existing Slack thread messages to fetch when starting a new thread session (default: 20, set to 0 to disable).", "hasChildren": false @@ -29872,19 +27789,11 @@ { "path": "channels.slack.userToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Slack User Token", "help": "Optional Slack user token for workflows requiring user-context API access beyond bot permissions. Use sparingly and audit scopes because this token can carry broader authority.", "hasChildren": true @@ -29927,12 +27836,7 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Slack User Token Read Only", "help": "When true, treat configured Slack user token usage as read-only helper behavior where possible. Keep enabled if you only need supplemental reads without user-context writes.", "hasChildren": false @@ -29955,10 +27859,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Synology Chat", "help": "Connect your Synology NAS Chat to OpenClaw", "hasChildren": true @@ -29979,10 +27880,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram", "help": "simplest way to get started — register a bot with @BotFather and get going.", "hasChildren": true @@ -30110,10 +28008,7 @@ { "path": "channels.telegram.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30173,19 +28068,11 @@ { "path": "channels.telegram.accounts.*.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -30221,10 +28108,7 @@ { "path": "channels.telegram.accounts.*.capabilities", "kind": "channel", - "type": [ - "array", - "object" - ], + "type": ["array", "object"], "required": false, "deprecated": false, "sensitive": false, @@ -30246,13 +28130,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "dm", - "group", - "all", - "allowlist" - ], + "enumValues": ["off", "dm", "group", "all", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -30263,10 +28141,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -30285,10 +28160,7 @@ { "path": "channels.telegram.accounts.*.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30298,10 +28170,7 @@ { "path": "channels.telegram.accounts.*.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30361,10 +28230,7 @@ { "path": "channels.telegram.accounts.*.defaultTo", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30404,10 +28270,7 @@ { "path": "channels.telegram.accounts.*.direct.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30419,12 +28282,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -30673,10 +28531,7 @@ { "path": "channels.telegram.accounts.*.direct.*.topics.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30708,11 +28563,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -30773,12 +28624,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -30908,10 +28754,7 @@ { "path": "channels.telegram.accounts.*.execApprovals.approvers.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30953,11 +28796,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "dm", - "channel", - "both" - ], + "enumValues": ["dm", "channel", "both"], "deprecated": false, "sensitive": false, "tags": [], @@ -30976,10 +28815,7 @@ { "path": "channels.telegram.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -30991,11 +28827,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -31035,10 +28867,7 @@ { "path": "channels.telegram.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -31070,11 +28899,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -31313,10 +29138,7 @@ { "path": "channels.telegram.accounts.*.groups.*.topics.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -31348,11 +29170,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -31493,11 +29311,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -31548,10 +29362,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "ipv4first", - "verbatim" - ], + "enumValues": ["ipv4first", "verbatim"], "deprecated": false, "sensitive": false, "tags": [], @@ -31572,12 +29383,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "ack", - "minimal", - "extensive" - ], + "enumValues": ["off", "ack", "minimal", "extensive"], "deprecated": false, "sensitive": false, "tags": [], @@ -31588,11 +29394,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all" - ], + "enumValues": ["off", "own", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -31671,17 +29473,9 @@ { "path": "channels.telegram.accounts.*.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, "tags": [], @@ -31692,11 +29486,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "partial", - "block" - ], + "enumValues": ["off", "partial", "block"], "deprecated": false, "sensitive": false, "tags": [], @@ -31835,19 +29625,11 @@ { "path": "channels.telegram.accounts.*.webhookSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -31993,10 +29775,7 @@ { "path": "channels.telegram.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32056,19 +29835,11 @@ { "path": "channels.telegram.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "label": "Telegram Bot Token", "help": "Telegram bot token used to authenticate Bot API requests for this account/provider config. Use secret/env substitution and rotate tokens if exposure is suspected.", "hasChildren": true @@ -32106,10 +29877,7 @@ { "path": "channels.telegram.capabilities", "kind": "channel", - "type": [ - "array", - "object" - ], + "type": ["array", "object"], "required": false, "deprecated": false, "sensitive": false, @@ -32131,19 +29899,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "dm", - "group", - "all", - "allowlist" - ], + "enumValues": ["off", "dm", "group", "all", "allowlist"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Inline Buttons", "help": "Enable Telegram inline button components for supported command and interaction surfaces. Disable if your deployment needs plain-text-only compatibility behavior.", "hasChildren": false @@ -32153,10 +29912,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -32175,17 +29931,11 @@ { "path": "channels.telegram.commands.native", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Native Commands", "help": "Override native commands for Telegram (bool or \"auto\").", "hasChildren": false @@ -32193,17 +29943,11 @@ { "path": "channels.telegram.commands.nativeSkills", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Native Skill Commands", "help": "Override native skill commands for Telegram (bool or \"auto\").", "hasChildren": false @@ -32215,10 +29959,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Config Writes", "help": "Allow Telegram to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -32230,10 +29971,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Custom Commands", "help": "Additional Telegram bot menu commands (merged with native; conflicts ignored).", "hasChildren": true @@ -32281,10 +30019,7 @@ { "path": "channels.telegram.defaultTo", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32324,10 +30059,7 @@ { "path": "channels.telegram.direct.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32339,12 +30071,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -32593,10 +30320,7 @@ { "path": "channels.telegram.direct.*.topics.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32628,11 +30352,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -32693,20 +30413,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "Telegram DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.telegram.allowFrom=[\"*\"].", "hasChildren": false @@ -32798,10 +30509,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Exec Approvals", "help": "Telegram-native exec approval routing and approver authorization. Enable this only when Telegram should act as an explicit exec-approval client for the selected bot account.", "hasChildren": true @@ -32813,10 +30521,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Exec Approval Agent Filter", "help": "Optional allowlist of agent IDs eligible for Telegram exec approvals, for example `[\"main\", \"ops-agent\"]`. Use this to keep approval prompts scoped to the agents you actually operate from Telegram.", "hasChildren": true @@ -32838,10 +30543,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Exec Approval Approvers", "help": "Telegram user IDs allowed to approve exec requests for this bot account. Use numeric Telegram user IDs; prompts are only delivered to these approvers when target includes dm.", "hasChildren": true @@ -32849,10 +30551,7 @@ { "path": "channels.telegram.execApprovals.approvers.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32866,10 +30565,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Exec Approvals Enabled", "help": "Enable Telegram exec approvals for this account. When false or unset, Telegram messages/buttons cannot approve exec requests.", "hasChildren": false @@ -32881,11 +30577,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Telegram Exec Approval Session Filter", "help": "Optional session-key filters matched as substring or regex-style patterns before Telegram approval routing is used. Use narrow patterns so Telegram approvals only appear for intended sessions.", "hasChildren": true @@ -32905,17 +30597,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "dm", - "channel", - "both" - ], + "enumValues": ["dm", "channel", "both"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Exec Approval Target", "help": "Controls where Telegram approval prompts are sent: \"dm\" sends to approver DMs (default), \"channel\" sends to the originating Telegram chat/topic, and \"both\" sends to both. Channel delivery exposes the command text to the chat, so only use it in trusted groups/topics.", "hasChildren": false @@ -32933,10 +30618,7 @@ { "path": "channels.telegram.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -32948,11 +30630,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -32992,10 +30670,7 @@ { "path": "channels.telegram.groups.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -33027,11 +30702,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -33270,10 +30941,7 @@ { "path": "channels.telegram.groups.*.topics.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -33305,11 +30973,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -33450,11 +31114,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -33497,10 +31157,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram autoSelectFamily", "help": "Override Node autoSelectFamily for Telegram (true=enable, false=disable).", "hasChildren": false @@ -33510,10 +31167,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "ipv4first", - "verbatim" - ], + "enumValues": ["ipv4first", "verbatim"], "deprecated": false, "sensitive": false, "tags": [], @@ -33534,12 +31188,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "ack", - "minimal", - "extensive" - ], + "enumValues": ["off", "ack", "minimal", "extensive"], "deprecated": false, "sensitive": false, "tags": [], @@ -33550,11 +31199,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "own", - "all" - ], + "enumValues": ["off", "own", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -33597,11 +31242,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Telegram Retry Attempts", "help": "Max retry attempts for outbound Telegram API calls (default: 3).", "hasChildren": false @@ -33613,11 +31254,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Telegram Retry Jitter", "help": "Jitter factor (0-1) applied to Telegram retry delays.", "hasChildren": false @@ -33629,12 +31266,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance", - "reliability" - ], + "tags": ["channels", "network", "performance", "reliability"], "label": "Telegram Retry Max Delay (ms)", "help": "Maximum retry delay cap in ms for Telegram outbound calls.", "hasChildren": false @@ -33646,11 +31278,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "reliability" - ], + "tags": ["channels", "network", "reliability"], "label": "Telegram Retry Min Delay (ms)", "help": "Minimum retry delay in ms for Telegram outbound calls.", "hasChildren": false @@ -33658,23 +31286,12 @@ { "path": "channels.telegram.streaming", "kind": "channel", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, - "enumValues": [ - "off", - "partial", - "block", - "progress" - ], + "enumValues": ["off", "partial", "block", "progress"], "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Telegram Streaming Mode", "help": "Unified Telegram stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\" (default: \"partial\"). \"progress\" maps to \"partial\" on Telegram. Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -33684,11 +31301,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "partial", - "block" - ], + "enumValues": ["off", "partial", "block"], "deprecated": false, "sensitive": false, "tags": [], @@ -33721,11 +31334,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Telegram Thread Binding Enabled", "help": "Enable Telegram conversation binding features (/focus, /unfocus, /agents, and /session idle|max-age). Overrides session.threadBindings.enabled when set.", "hasChildren": false @@ -33737,11 +31346,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Telegram Thread Binding Idle Timeout (hours)", "help": "Inactivity window in hours for Telegram bound sessions. Set 0 to disable idle auto-unfocus (default: 24). Overrides session.threadBindings.idleHours when set.", "hasChildren": false @@ -33753,12 +31358,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance", - "storage" - ], + "tags": ["channels", "network", "performance", "storage"], "label": "Telegram Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for Telegram bound sessions. Set 0 to disable hard cap (default: 0). Overrides session.threadBindings.maxAgeHours when set.", "hasChildren": false @@ -33770,11 +31370,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Telegram Thread-Bound ACP Spawn", "help": "Allow ACP spawns with thread=true to auto-bind Telegram current conversations when supported.", "hasChildren": false @@ -33786,11 +31382,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "storage" - ], + "tags": ["channels", "network", "storage"], "label": "Telegram Thread-Bound Subagent Spawn", "help": "Allow subagent spawns with thread=true to auto-bind Telegram current conversations when supported.", "hasChildren": false @@ -33802,11 +31394,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "Telegram API Timeout (seconds)", "help": "Max seconds before Telegram API requests are aborted (default: 500 per grammY).", "hasChildren": false @@ -33864,19 +31452,11 @@ { "path": "channels.telegram.webhookSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "channels", - "network", - "security" - ], + "tags": ["auth", "channels", "network", "security"], "hasChildren": true }, { @@ -33926,10 +31506,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Tlon", "help": "Decentralized messaging on Urbit", "hasChildren": true @@ -34179,10 +31756,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "restricted", - "open" - ], + "enumValues": ["restricted", "open"], "deprecated": false, "sensitive": false, "tags": [], @@ -34365,10 +31939,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Twitch", "help": "Twitch chat integration", "hasChildren": true @@ -34428,13 +31999,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "moderator", - "owner", - "vip", - "subscriber", - "all" - ], + "enumValues": ["moderator", "owner", "vip", "subscriber", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -34503,10 +32068,7 @@ { "path": "channels.twitch.accounts.*.expiresIn", "kind": "channel", - "type": [ - "null", - "number" - ], + "type": ["null", "number"], "required": false, "deprecated": false, "sensitive": false, @@ -34578,13 +32140,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "moderator", - "owner", - "vip", - "subscriber", - "all" - ], + "enumValues": ["moderator", "owner", "vip", "subscriber", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -34653,10 +32209,7 @@ { "path": "channels.twitch.expiresIn", "kind": "channel", - "type": [ - "null", - "number" - ], + "type": ["null", "number"], "required": false, "deprecated": false, "sensitive": false, @@ -34678,11 +32231,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "bullets", - "code", - "off" - ], + "enumValues": ["bullets", "code", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -34755,10 +32304,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "WhatsApp", "help": "works with your own number; recommend a separate phone + eSIM.", "hasChildren": true @@ -34819,11 +32365,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "always", - "mentions", - "never" - ], + "enumValues": ["always", "mentions", "never"], "defaultValue": "mentions", "deprecated": false, "sensitive": false, @@ -34935,10 +32477,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -34990,12 +32529,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -35067,11 +32601,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -35343,11 +32873,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -35459,11 +32985,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "always", - "mentions", - "never" - ], + "enumValues": ["always", "mentions", "never"], "defaultValue": "mentions", "deprecated": false, "sensitive": false, @@ -35605,10 +33127,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "length", - "newline" - ], + "enumValues": ["length", "newline"], "deprecated": false, "sensitive": false, "tags": [], @@ -35621,10 +33140,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "WhatsApp Config Writes", "help": "Allow WhatsApp to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -35637,11 +33153,7 @@ "defaultValue": 0, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network", - "performance" - ], + "tags": ["channels", "network", "performance"], "label": "WhatsApp Message Debounce (ms)", "help": "Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable).", "hasChildren": false @@ -35681,20 +33193,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": [ - "access", - "channels", - "network" - ], + "tags": ["access", "channels", "network"], "label": "WhatsApp DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.whatsapp.allowFrom=[\"*\"].", "hasChildren": false @@ -35764,11 +33267,7 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -36040,11 +33539,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -36088,10 +33583,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "WhatsApp Self-Phone Mode", "help": "Same-phone setup (bot uses your personal WhatsApp number).", "hasChildren": false @@ -36123,10 +33615,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Zalo", "help": "Vietnam-focused messaging platform with Bot API.", "hasChildren": true @@ -36164,10 +33653,7 @@ { "path": "channels.zalo.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36177,10 +33663,7 @@ { "path": "channels.zalo.accounts.*.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36222,12 +33705,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -36256,10 +33734,7 @@ { "path": "channels.zalo.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36271,11 +33746,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -36296,11 +33767,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -36369,10 +33836,7 @@ { "path": "channels.zalo.accounts.*.webhookSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36432,10 +33896,7 @@ { "path": "channels.zalo.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36445,10 +33906,7 @@ { "path": "channels.zalo.botToken", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36500,12 +33958,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -36534,10 +33987,7 @@ { "path": "channels.zalo.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36549,11 +33999,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -36574,11 +34020,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -36647,10 +34089,7 @@ { "path": "channels.zalo.webhookSecret", "kind": "channel", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36704,10 +34143,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "channels", - "network" - ], + "tags": ["channels", "network"], "label": "Zalo Personal", "help": "Zalo personal account via QR code login.", "hasChildren": true @@ -36745,10 +34181,7 @@ { "path": "channels.zalouser.accounts.*.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36770,12 +34203,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -36804,10 +34232,7 @@ { "path": "channels.zalouser.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -36819,11 +34244,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -36974,11 +34395,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -37037,10 +34454,7 @@ { "path": "channels.zalouser.allowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -37072,12 +34486,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "pairing", - "allowlist", - "open", - "disabled" - ], + "enumValues": ["pairing", "allowlist", "open", "disabled"], "deprecated": false, "sensitive": false, "tags": [], @@ -37106,10 +34515,7 @@ { "path": "channels.zalouser.groupAllowFrom.*", "kind": "channel", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -37121,11 +34527,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "open", - "disabled", - "allowlist" - ], + "enumValues": ["open", "disabled", "allowlist"], "deprecated": false, "sensitive": false, "tags": [], @@ -37276,11 +34678,7 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": [ - "off", - "bullets", - "code" - ], + "enumValues": ["off", "bullets", "code"], "deprecated": false, "sensitive": false, "tags": [], @@ -37333,9 +34731,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "CLI", "help": "CLI presentation controls for local command output behavior such as banner and tagline style. Use this section to keep startup output aligned with operator preference without changing runtime behavior.", "hasChildren": true @@ -37347,9 +34743,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "CLI Banner", "help": "CLI startup banner controls for title/version line and tagline style behavior. Keep banner enabled for fast version/context checks, then tune tagline mode to your preferred noise level.", "hasChildren": true @@ -37361,9 +34755,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "CLI Banner Tagline Mode", "help": "Controls tagline style in the CLI startup banner: \"random\" (default) picks from the rotating tagline pool, \"default\" always shows the neutral default tagline, and \"off\" hides tagline text while keeping the banner version line.", "hasChildren": false @@ -37381,9 +34773,7 @@ }, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Commands", "help": "Controls chat command surfaces, owner gating, and elevated command access behavior across providers. Keep defaults unless you need stricter operator controls or broader command availability.", "hasChildren": true @@ -37395,9 +34785,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Command Elevated Access Rules", "help": "Defines elevated command allow rules by channel and sender for owner-level command surfaces. Use narrow provider-specific identities so privileged commands are not exposed to broad chat audiences.", "hasChildren": true @@ -37415,10 +34803,7 @@ { "path": "commands.allowFrom.*.*", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -37432,9 +34817,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Allow Bash Chat Command", "help": "Allow bash chat command (`!`; `/bash` alias) to run host shell commands (default: false; requires tools.elevated).", "hasChildren": false @@ -37446,9 +34829,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Bash Foreground Window (ms)", "help": "How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately).", "hasChildren": false @@ -37460,9 +34841,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Allow /config", "help": "Allow /config chat command to read/write config on disk (default: false).", "hasChildren": false @@ -37474,9 +34853,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Allow /debug", "help": "Allow /debug chat command for runtime-only overrides (default: false).", "hasChildren": false @@ -37484,16 +34861,11 @@ { "path": "commands.native", "kind": "core", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Native Commands", "help": "Registers native slash/menu commands with channels that support command registration (Discord, Slack, Telegram). Keep enabled for discoverability unless you intentionally run text-only command workflows.", "hasChildren": false @@ -37501,16 +34873,11 @@ { "path": "commands.nativeSkills", "kind": "core", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Native Skill Commands", "help": "Registers native skill commands so users can invoke skills directly from provider command menus where supported. Keep aligned with your skill policy so exposed commands match what operators expect.", "hasChildren": false @@ -37522,9 +34889,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Command Owners", "help": "Explicit owner allowlist for owner-only tools/commands. Use channel-native IDs (optionally prefixed like \"whatsapp:+15551234567\"). '*' is ignored.", "hasChildren": true @@ -37532,10 +34897,7 @@ { "path": "commands.ownerAllowFrom.*", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -37547,16 +34909,11 @@ "kind": "core", "type": "string", "required": true, - "enumValues": [ - "raw", - "hash" - ], + "enumValues": ["raw", "hash"], "defaultValue": "raw", "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Owner ID Display", "help": "Controls how owner IDs are rendered in the system prompt. Allowed values: raw, hash. Default: raw.", "hasChildren": false @@ -37568,11 +34925,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "access", - "auth", - "security" - ], + "tags": ["access", "auth", "security"], "label": "Owner ID Hash Secret", "help": "Optional secret used to HMAC hash owner IDs when ownerDisplay=hash. Prefer env substitution.", "hasChildren": false @@ -37585,9 +34938,7 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Allow Restart", "help": "Allow /restart and gateway restart tool actions (default: true).", "hasChildren": false @@ -37599,9 +34950,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Text Commands", "help": "Enables text-command parsing in chat input in addition to native command surfaces where available. Keep this enabled for compatibility across channels that do not support native command registration.", "hasChildren": false @@ -37613,9 +34962,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Use Access Groups", "help": "Enforce access-group allowlists/policies for commands.", "hasChildren": false @@ -37627,9 +34974,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Cron", "help": "Global scheduler settings for stored cron jobs, run concurrency, delivery fallback, and run-session retention. Keep defaults unless you are scaling job volume or integrating external webhook receivers.", "hasChildren": true @@ -37641,9 +34986,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Cron Enabled", "help": "Enables cron job execution for stored schedules managed by the gateway. Keep enabled for normal reminder/automation flows, and disable only to pause all cron execution without deleting jobs.", "hasChildren": false @@ -37703,10 +35046,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "announce", - "webhook" - ], + "enumValues": ["announce", "webhook"], "deprecated": false, "sensitive": false, "tags": [], @@ -37747,10 +35087,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "announce", - "webhook" - ], + "enumValues": ["announce", "webhook"], "deprecated": false, "sensitive": false, "tags": [], @@ -37773,10 +35110,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "performance" - ], + "tags": ["automation", "performance"], "label": "Cron Max Concurrent Runs", "help": "Limits how many cron jobs can execute at the same time when multiple schedules fire together. Use lower values to protect CPU/memory under heavy automation load, or raise carefully for higher throughput.", "hasChildren": false @@ -37788,10 +35122,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "reliability" - ], + "tags": ["automation", "reliability"], "label": "Cron Retry Policy", "help": "Overrides the default retry policy for one-shot jobs when they fail with transient errors (rate limit, overloaded, network, server_error). Omit to use defaults: maxAttempts 3, backoffMs [30000, 60000, 300000], retry all transient types.", "hasChildren": true @@ -37803,10 +35134,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "reliability" - ], + "tags": ["automation", "reliability"], "label": "Cron Retry Backoff (ms)", "help": "Backoff delays in ms for each retry attempt (default: [30000, 60000, 300000]). Use shorter values for faster retries.", "hasChildren": true @@ -37828,11 +35156,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "performance", - "reliability" - ], + "tags": ["automation", "performance", "reliability"], "label": "Cron Retry Max Attempts", "help": "Max retries for one-shot jobs on transient errors before permanent disable (default: 3).", "hasChildren": false @@ -37844,10 +35168,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "reliability" - ], + "tags": ["automation", "reliability"], "label": "Cron Retry Error Types", "help": "Error types to retry: rate_limit, overloaded, network, timeout, server_error. Use to restrict which errors trigger retries; omit to retry all transient types.", "hasChildren": true @@ -37857,13 +35178,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "rate_limit", - "overloaded", - "network", - "timeout", - "server_error" - ], + "enumValues": ["rate_limit", "overloaded", "network", "timeout", "server_error"], "deprecated": false, "sensitive": false, "tags": [], @@ -37876,9 +35191,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Cron Run Log Pruning", "help": "Pruning controls for per-job cron run history files under `cron/runs/.jsonl`, including size and line retention.", "hasChildren": true @@ -37890,9 +35203,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Cron Run Log Keep Lines", "help": "How many trailing run-log lines to retain when a file exceeds maxBytes (default `2000`). Increase for longer forensic history or lower for smaller disks.", "hasChildren": false @@ -37900,17 +35211,11 @@ { "path": "cron.runLog.maxBytes", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "performance" - ], + "tags": ["automation", "performance"], "label": "Cron Run Log Max Bytes", "help": "Maximum bytes per cron run-log file before pruning rewrites to the last keepLines entries (for example `2mb`, default `2000000`).", "hasChildren": false @@ -37918,17 +35223,11 @@ { "path": "cron.sessionRetention", "kind": "core", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "storage" - ], + "tags": ["automation", "storage"], "label": "Cron Session Retention", "help": "Controls how long completed cron run sessions are kept before pruning (`24h`, `7d`, `1h30m`, or `false` to disable pruning; default: `24h`). Use shorter retention to reduce storage growth on high-frequency schedules.", "hasChildren": false @@ -37940,10 +35239,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "storage" - ], + "tags": ["automation", "storage"], "label": "Cron Store Path", "help": "Path to the cron job store file used to persist scheduled jobs across restarts. Set an explicit path only when you need custom storage layout, backups, or mounted volumes.", "hasChildren": false @@ -37955,9 +35251,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Cron Legacy Webhook (Deprecated)", "help": "Deprecated legacy fallback webhook URL used only for old jobs with `notify=true`. Migrate to per-job delivery using `delivery.mode=\"webhook\"` plus `delivery.to`, and avoid relying on this global field.", "hasChildren": false @@ -37965,18 +35259,11 @@ { "path": "cron.webhookToken", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "automation", - "security" - ], + "tags": ["auth", "automation", "security"], "label": "Cron Webhook Bearer Token", "help": "Bearer token attached to cron webhook POST deliveries when webhook mode is used. Prefer secret/env substitution and rotate this token regularly if shared webhook endpoints are internet-reachable.", "hasChildren": true @@ -38018,9 +35305,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Diagnostics", "help": "Diagnostics controls for targeted tracing, telemetry export, and cache inspection during debugging. Keep baseline diagnostics minimal in production and enable deeper signals only when investigating issues.", "hasChildren": true @@ -38032,10 +35317,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace", "help": "Cache-trace logging settings for observing cache decisions and payload context in embedded runs. Enable this temporarily for debugging and disable afterward to reduce sensitive log footprint.", "hasChildren": true @@ -38047,10 +35329,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace Enabled", "help": "Log cache trace snapshots for embedded agent runs (default: false).", "hasChildren": false @@ -38062,10 +35341,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace File Path", "help": "JSONL output path for cache trace logs (default: $OPENCLAW_STATE_DIR/logs/cache-trace.jsonl).", "hasChildren": false @@ -38077,10 +35353,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace Include Messages", "help": "Include full message payloads in trace output (default: true).", "hasChildren": false @@ -38092,10 +35365,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace Include Prompt", "help": "Include prompt text in trace output (default: true).", "hasChildren": false @@ -38107,10 +35377,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Cache Trace Include System", "help": "Include system prompt in trace output (default: true).", "hasChildren": false @@ -38122,9 +35389,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Diagnostics Enabled", "help": "Master toggle for diagnostics instrumentation output in logs and telemetry wiring paths. Keep enabled for normal observability, and disable only in tightly constrained environments.", "hasChildren": false @@ -38136,9 +35401,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Diagnostics Flags", "help": "Enable targeted diagnostics logs by flag (e.g. [\"telegram.http\"]). Supports wildcards like \"telegram.*\" or \"*\".", "hasChildren": true @@ -38160,9 +35423,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry", "help": "OpenTelemetry export settings for traces, metrics, and logs emitted by gateway components. Use this when integrating with centralized observability backends and distributed tracing pipelines.", "hasChildren": true @@ -38174,9 +35435,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Enabled", "help": "Enables OpenTelemetry export pipeline for traces, metrics, and logs based on configured endpoint/protocol settings. Keep disabled unless your collector endpoint and auth are fully configured.", "hasChildren": false @@ -38188,9 +35447,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Endpoint", "help": "Collector endpoint URL used for OpenTelemetry export transport, including scheme and port. Use a reachable, trusted collector endpoint and monitor ingestion errors after rollout.", "hasChildren": false @@ -38202,10 +35459,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "performance" - ], + "tags": ["observability", "performance"], "label": "OpenTelemetry Flush Interval (ms)", "help": "Interval in milliseconds for periodic telemetry flush from buffers to the collector. Increase to reduce export chatter, or lower for faster visibility during active incident response.", "hasChildren": false @@ -38217,9 +35471,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Headers", "help": "Additional HTTP/gRPC metadata headers sent with OpenTelemetry export requests, often used for tenant auth or routing. Keep secrets in env-backed values and avoid unnecessary header sprawl.", "hasChildren": true @@ -38241,9 +35493,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Logs Enabled", "help": "Enable log signal export through OpenTelemetry in addition to local logging sinks. Use this when centralized log correlation is required across services and agents.", "hasChildren": false @@ -38255,9 +35505,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Metrics Enabled", "help": "Enable metrics signal export to the configured OpenTelemetry collector endpoint. Keep enabled for runtime health dashboards, and disable only if metric volume must be minimized.", "hasChildren": false @@ -38269,9 +35517,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Protocol", "help": "OTel transport protocol for telemetry export: \"http/protobuf\" or \"grpc\" depending on collector support. Use the protocol your observability backend expects to avoid dropped telemetry payloads.", "hasChildren": false @@ -38283,9 +35529,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Trace Sample Rate", "help": "Trace sampling rate (0-1) controlling how much trace traffic is exported to observability backends. Lower rates reduce overhead/cost, while higher rates improve debugging fidelity.", "hasChildren": false @@ -38297,9 +35541,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Service Name", "help": "Service name reported in telemetry resource attributes to identify this gateway instance in observability backends. Use stable names so dashboards and alerts remain consistent over deployments.", "hasChildren": false @@ -38311,9 +35553,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "OpenTelemetry Traces Enabled", "help": "Enable trace signal export to the configured OpenTelemetry collector endpoint. Keep enabled when latency/debug tracing is needed, and disable if you only want metrics/logs.", "hasChildren": false @@ -38325,10 +35565,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Stuck Session Warning Threshold (ms)", "help": "Age threshold in milliseconds for emitting stuck-session warnings while a session remains in processing state. Increase for long multi-tool turns to reduce false positives; decrease for faster hang detection.", "hasChildren": false @@ -38340,9 +35577,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Discovery", "help": "Service discovery settings for local mDNS advertisement and optional wide-area presence signaling. Keep discovery scoped to expected networks to avoid leaking service metadata.", "hasChildren": true @@ -38354,9 +35589,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "mDNS Discovery", "help": "mDNS discovery configuration group for local network advertisement and discovery behavior tuning. Keep minimal mode for routine LAN discovery unless extra metadata is required.", "hasChildren": true @@ -38366,16 +35599,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "off", - "minimal", - "full" - ], + "enumValues": ["off", "minimal", "full"], "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "mDNS Discovery Mode", "help": "mDNS broadcast mode (\"minimal\" default, \"full\" includes cliPath/sshPort, \"off\" disables mDNS).", "hasChildren": false @@ -38387,9 +35614,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Wide-area Discovery", "help": "Wide-area discovery configuration group for exposing discovery signals beyond local-link scopes. Enable only in deployments that intentionally aggregate gateway presence across sites.", "hasChildren": true @@ -38401,9 +35626,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Wide-area Discovery Domain", "help": "Optional unicast DNS-SD domain for wide-area discovery, such as openclaw.internal. Use this when you intentionally publish gateway discovery beyond local mDNS scopes.", "hasChildren": false @@ -38415,9 +35638,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Wide-area Discovery Enabled", "help": "Enables wide-area discovery signaling when your environment needs non-local gateway discovery. Keep disabled unless cross-network discovery is operationally required.", "hasChildren": false @@ -38429,9 +35650,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Environment", "help": "Environment import and override settings used to supply runtime variables to the gateway process. Use this section to control shell-env loading and explicit variable injection behavior.", "hasChildren": true @@ -38453,9 +35672,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Shell Environment Import", "help": "Shell environment import controls for loading variables from your login shell during startup. Keep this enabled when you depend on profile-defined secrets or PATH customizations.", "hasChildren": true @@ -38467,9 +35684,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Shell Environment Import Enabled", "help": "Enables loading environment variables from the user shell profile during startup initialization. Keep enabled for developer machines, or disable in locked-down service environments with explicit env management.", "hasChildren": false @@ -38481,9 +35696,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Shell Environment Import Timeout (ms)", "help": "Maximum time in milliseconds allowed for shell environment resolution before fallback behavior applies. Use tighter timeouts for faster startup, or increase when shell initialization is heavy.", "hasChildren": false @@ -38495,9 +35708,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Environment Variable Overrides", "help": "Explicit key/value environment variable overrides merged into runtime process environment for OpenClaw. Use this for deterministic env configuration instead of relying only on shell profile side effects.", "hasChildren": true @@ -38519,9 +35730,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gateway", "help": "Gateway runtime surface for bind mode, auth, control UI, remote transport, and operational safety controls. Keep conservative defaults unless you intentionally expose the gateway beyond trusted local interfaces.", "hasChildren": true @@ -38533,11 +35742,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network", - "reliability" - ], + "tags": ["access", "network", "reliability"], "label": "Gateway Allow x-real-ip Fallback", "help": "Enables x-real-ip fallback when x-forwarded-for is missing in proxy scenarios. Keep disabled unless your ingress stack requires this compatibility behavior.", "hasChildren": false @@ -38549,9 +35754,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Auth", "help": "Authentication policy for gateway HTTP/WebSocket access including mode, credentials, trusted-proxy behavior, and rate limiting. Keep auth enabled for every non-loopback deployment.", "hasChildren": true @@ -38563,10 +35766,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Gateway Auth Allow Tailscale Identity", "help": "Allows trusted Tailscale identity paths to satisfy gateway auth checks when configured. Use this only when your tailnet identity posture is strong and operator workflows depend on it.", "hasChildren": false @@ -38578,9 +35778,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Auth Mode", "help": "Gateway auth mode: \"none\", \"token\", \"password\", or \"trusted-proxy\" depending on your edge architecture. Use token/password for direct exposure, and trusted-proxy only behind hardened identity-aware proxies.", "hasChildren": false @@ -38588,19 +35786,11 @@ { "path": "gateway.auth.password", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "access", - "auth", - "network", - "security" - ], + "tags": ["access", "auth", "network", "security"], "label": "Gateway Password", "help": "Required for Tailscale funnel.", "hasChildren": true @@ -38642,10 +35832,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "performance" - ], + "tags": ["network", "performance"], "label": "Gateway Auth Rate Limit", "help": "Login/auth attempt throttling controls to reduce credential brute-force risk at the gateway boundary. Keep enabled in exposed environments and tune thresholds to your traffic baseline.", "hasChildren": true @@ -38693,19 +35880,11 @@ { "path": "gateway.auth.token", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "access", - "auth", - "network", - "security" - ], + "tags": ["access", "auth", "network", "security"], "label": "Gateway Token", "help": "Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.", "hasChildren": true @@ -38747,9 +35926,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Trusted Proxy Auth", "help": "Trusted-proxy auth header mapping for upstream identity providers that inject user claims. Use only with known proxy CIDRs and strict header allowlists to prevent spoofed identity headers.", "hasChildren": true @@ -38811,9 +35988,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Bind Mode", "help": "Network bind profile: \"auto\", \"lan\", \"loopback\", \"custom\", or \"tailnet\" to control interface exposure. Keep \"loopback\" or \"auto\" for safest local operation unless external clients must connect.", "hasChildren": false @@ -38825,10 +36000,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "reliability" - ], + "tags": ["network", "reliability"], "label": "Gateway Channel Health Check Interval (min)", "help": "Interval in minutes for automatic channel health probing and status updates. Use lower intervals for faster detection, or higher intervals to reduce periodic probe noise.", "hasChildren": false @@ -38840,10 +36012,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "performance" - ], + "tags": ["network", "performance"], "label": "Gateway Channel Max Restarts Per Hour", "help": "Maximum number of health-monitor-initiated channel restarts allowed within a rolling one-hour window. Once hit, further restarts are skipped until the window expires. Default: 10.", "hasChildren": false @@ -38855,9 +36024,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Channel Stale Event Threshold (min)", "help": "How many minutes a connected channel can go without receiving any event before the health monitor treats it as a stale socket and triggers a restart. Default: 30.", "hasChildren": false @@ -38869,9 +36036,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Control UI", "help": "Control UI hosting settings including enablement, pathing, and browser-origin/auth hardening behavior. Keep UI exposure minimal and pair with strong auth controls before internet-facing deployments.", "hasChildren": true @@ -38883,10 +36048,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Control UI Allowed Origins", "help": "Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com). Required for non-loopback Control UI deployments unless dangerous Host-header fallback is explicitly enabled.", "hasChildren": true @@ -38908,12 +36070,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "network", - "security" - ], + "tags": ["access", "advanced", "network", "security"], "label": "Insecure Control UI Auth Toggle", "help": "Loosens strict browser auth checks for Control UI when you must run a non-standard setup. Keep this off unless you trust your network and proxy path, because impersonation risk is higher.", "hasChildren": false @@ -38925,10 +36082,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "storage" - ], + "tags": ["network", "storage"], "label": "Control UI Base Path", "help": "Optional URL prefix where the Control UI is served (e.g. /openclaw).", "hasChildren": false @@ -38940,12 +36094,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "network", - "security" - ], + "tags": ["access", "advanced", "network", "security"], "label": "Dangerously Allow Host-Header Origin Fallback", "help": "DANGEROUS toggle that enables Host-header based origin fallback for Control UI/WebChat websocket checks. This mode is supported when your deployment intentionally relies on Host-header origin policy; explicit gateway.controlUi.allowedOrigins remains the recommended hardened default.", "hasChildren": false @@ -38957,12 +36106,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "network", - "security" - ], + "tags": ["access", "advanced", "network", "security"], "label": "Dangerously Disable Control UI Device Auth", "help": "Disables Control UI device identity checks and relies on token/password only. Use only for short-lived debugging on trusted networks, then turn it off immediately.", "hasChildren": false @@ -38974,9 +36118,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Control UI Enabled", "help": "Enables serving the gateway Control UI from the gateway HTTP process when true. Keep enabled for local administration, and disable when an external control surface replaces it.", "hasChildren": false @@ -38988,9 +36130,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Control UI Assets Root", "help": "Optional filesystem root for Control UI assets (defaults to dist/control-ui).", "hasChildren": false @@ -39002,9 +36142,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Custom Bind Host", "help": "Explicit bind host/IP used when gateway.bind is set to custom for manual interface targeting. Use a precise address and avoid wildcard binds unless external exposure is required.", "hasChildren": false @@ -39016,9 +36154,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway HTTP API", "help": "Gateway HTTP API configuration grouping endpoint toggles and transport-facing API exposure controls. Keep only required endpoints enabled to reduce attack surface.", "hasChildren": true @@ -39030,9 +36166,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway HTTP Endpoints", "help": "HTTP endpoint feature toggles under the gateway API surface for compatibility routes and optional integrations. Enable endpoints intentionally and monitor access patterns after rollout.", "hasChildren": true @@ -39054,9 +36188,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "OpenAI Chat Completions Endpoint", "help": "Enable the OpenAI-compatible `POST /v1/chat/completions` endpoint (default: false).", "hasChildren": false @@ -39068,10 +36200,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network" - ], + "tags": ["media", "network"], "label": "OpenAI Chat Completions Image Limits", "help": "Image fetch/validation controls for OpenAI-compatible `image_url` parts.", "hasChildren": true @@ -39083,11 +36212,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "media", - "network" - ], + "tags": ["access", "media", "network"], "label": "OpenAI Chat Completions Image MIME Allowlist", "help": "Allowed MIME types for `image_url` parts (case-insensitive list).", "hasChildren": true @@ -39109,11 +36234,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "media", - "network" - ], + "tags": ["access", "media", "network"], "label": "OpenAI Chat Completions Allow Image URLs", "help": "Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported).", "hasChildren": false @@ -39125,11 +36246,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network", - "performance" - ], + "tags": ["media", "network", "performance"], "label": "OpenAI Chat Completions Image Max Bytes", "help": "Max bytes per fetched/decoded `image_url` image (default: 10MB).", "hasChildren": false @@ -39141,12 +36258,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network", - "performance", - "storage" - ], + "tags": ["media", "network", "performance", "storage"], "label": "OpenAI Chat Completions Image Max Redirects", "help": "Max HTTP redirects allowed when fetching `image_url` URLs (default: 3).", "hasChildren": false @@ -39158,11 +36270,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network", - "performance" - ], + "tags": ["media", "network", "performance"], "label": "OpenAI Chat Completions Image Timeout (ms)", "help": "Timeout in milliseconds for `image_url` URL fetches (default: 10000).", "hasChildren": false @@ -39174,11 +36282,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "media", - "network" - ], + "tags": ["access", "media", "network"], "label": "OpenAI Chat Completions Image URL Allowlist", "help": "Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards.", "hasChildren": true @@ -39200,10 +36304,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "performance" - ], + "tags": ["network", "performance"], "label": "OpenAI Chat Completions Max Body Bytes", "help": "Max request body size in bytes for `/v1/chat/completions` (default: 20MB).", "hasChildren": false @@ -39215,11 +36316,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network", - "performance" - ], + "tags": ["media", "network", "performance"], "label": "OpenAI Chat Completions Max Image Parts", "help": "Max number of `image_url` parts accepted from the latest user message (default: 8).", "hasChildren": false @@ -39231,11 +36328,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "network", - "performance" - ], + "tags": ["media", "network", "performance"], "label": "OpenAI Chat Completions Max Total Image Bytes", "help": "Max cumulative decoded bytes across all `image_url` parts in one request (default: 20MB).", "hasChildren": false @@ -39517,9 +36610,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway HTTP Security Headers", "help": "Optional HTTP response security headers applied by the gateway process itself. Prefer setting these at your reverse proxy when TLS terminates there.", "hasChildren": true @@ -39527,16 +36618,11 @@ { "path": "gateway.http.securityHeaders.strictTransportSecurity", "kind": "core", - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Strict Transport Security Header", "help": "Value for the Strict-Transport-Security response header. Set only on HTTPS origins that you fully control; use false to explicitly disable.", "hasChildren": false @@ -39548,9 +36634,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Mode", "help": "Gateway operation mode: \"local\" runs channels and agent runtime on this host, while \"remote\" connects through remote transport. Keep \"local\" unless you intentionally run a split remote gateway topology.", "hasChildren": false @@ -39572,10 +36656,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Gateway Node Allowlist (Extra Commands)", "help": "Extra node.invoke commands to allow beyond the gateway defaults (array of command strings). Enabling dangerous commands here is a security-sensitive override and is flagged by `openclaw security audit`.", "hasChildren": true @@ -39607,9 +36688,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Node Browser Mode", "help": "Node browser routing (\"auto\" = pick single connected browser node, \"manual\" = require node param, \"off\" = disable).", "hasChildren": false @@ -39621,9 +36700,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Node Browser Pin", "help": "Pin browser routing to a specific node id or name (optional).", "hasChildren": false @@ -39635,10 +36712,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Gateway Node Denylist", "help": "Node command names to block even if present in node claims or default allowlist (exact command-name matching only, e.g. `system.run`; does not inspect shell text inside that command).", "hasChildren": true @@ -39660,9 +36734,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Port", "help": "TCP port used by the gateway listener for API, control UI, and channel-facing ingress paths. Use a dedicated port and avoid collisions with reverse proxies or local developer services.", "hasChildren": false @@ -39674,9 +36746,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Push Delivery", "help": "Push-delivery settings used by the gateway when it needs to wake or notify paired devices. Configure relay-backed APNs here for official iOS builds; direct APNs auth remains env-based for local/manual builds.", "hasChildren": true @@ -39688,9 +36758,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway APNs Delivery", "help": "APNs delivery settings for iOS devices paired to this gateway. Use relay settings for official/TestFlight builds that register through the external push relay.", "hasChildren": true @@ -39702,9 +36770,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway APNs Relay", "help": "External relay settings for relay-backed APNs sends. The gateway uses this relay for push.test, wake nudges, and reconnect wakes after a paired official iOS build publishes a relay-backed registration.", "hasChildren": true @@ -39716,10 +36782,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "network" - ], + "tags": ["advanced", "network"], "label": "Gateway APNs Relay Base URL", "help": "Base HTTPS URL for the external APNs relay service used by official/TestFlight iOS builds. Keep this aligned with the relay URL baked into the iOS build so registration and send traffic hit the same deployment.", "hasChildren": false @@ -39731,10 +36794,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "performance" - ], + "tags": ["network", "performance"], "label": "Gateway APNs Relay Timeout (ms)", "help": "Timeout in milliseconds for relay send requests from the gateway to the APNs relay (default: 10000). Increase for slower relays or networks, or lower to fail wake attempts faster.", "hasChildren": false @@ -39746,10 +36806,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "reliability" - ], + "tags": ["network", "reliability"], "label": "Config Reload", "help": "Live config-reload policy for how edits are applied and when full restarts are triggered. Keep hybrid behavior for safest operational updates unless debugging reload internals.", "hasChildren": true @@ -39761,11 +36818,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "performance", - "reliability" - ], + "tags": ["network", "performance", "reliability"], "label": "Config Reload Debounce (ms)", "help": "Debounce window (ms) before applying config changes.", "hasChildren": false @@ -39777,10 +36830,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "reliability" - ], + "tags": ["network", "reliability"], "label": "Config Reload Mode", "help": "Controls how config edits are applied: \"off\" ignores live edits, \"restart\" always restarts, \"hot\" applies in-process, and \"hybrid\" tries hot then restarts if required. Keep \"hybrid\" for safest routine updates.", "hasChildren": false @@ -39792,9 +36842,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Remote Gateway", "help": "Remote gateway connection settings for direct or SSH transport when this instance proxies to another runtime host. Use remote mode only when split-host operation is intentionally configured.", "hasChildren": true @@ -39802,18 +36850,11 @@ { "path": "gateway.remote.password", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "network", - "security" - ], + "tags": ["auth", "network", "security"], "label": "Remote Gateway Password", "help": "Password credential used for remote gateway authentication when password mode is enabled. Keep this secret managed externally and avoid plaintext values in committed config.", "hasChildren": true @@ -39855,9 +36896,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Remote Gateway SSH Identity", "help": "Optional SSH identity file path (passed to ssh -i).", "hasChildren": false @@ -39869,9 +36908,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Remote Gateway SSH Target", "help": "Remote gateway over SSH (tunnels the gateway port to localhost). Format: user@host or user@host:port.", "hasChildren": false @@ -39883,11 +36920,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "network", - "security" - ], + "tags": ["auth", "network", "security"], "label": "Remote Gateway TLS Fingerprint", "help": "Expected sha256 TLS fingerprint for the remote gateway (pin to avoid MITM).", "hasChildren": false @@ -39895,18 +36928,11 @@ { "path": "gateway.remote.token", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "network", - "security" - ], + "tags": ["auth", "network", "security"], "label": "Remote Gateway Token", "help": "Bearer token used to authenticate this client to a remote gateway in token-auth deployments. Store via secret/env substitution and rotate alongside remote gateway auth changes.", "hasChildren": true @@ -39948,9 +36974,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Remote Gateway Transport", "help": "Remote connection transport: \"direct\" uses configured URL connectivity, while \"ssh\" tunnels through SSH. Use SSH when you need encrypted tunnel semantics without exposing remote ports.", "hasChildren": false @@ -39962,9 +36986,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Remote Gateway URL", "help": "Remote Gateway WebSocket URL (ws:// or wss://).", "hasChildren": false @@ -39976,9 +36998,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Tailscale", "help": "Tailscale integration settings for Serve/Funnel exposure and lifecycle handling on gateway start/exit. Keep off unless your deployment intentionally relies on Tailscale ingress.", "hasChildren": true @@ -39990,9 +37010,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Tailscale Mode", "help": "Tailscale publish mode: \"off\", \"serve\", or \"funnel\" for private or public exposure paths. Use \"serve\" for tailnet-only access and \"funnel\" only when public internet reachability is required.", "hasChildren": false @@ -40004,9 +37022,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Tailscale Reset on Exit", "help": "Resets Tailscale Serve/Funnel state on gateway exit to avoid stale published routes after shutdown. Keep enabled unless another controller manages publish lifecycle outside the gateway.", "hasChildren": false @@ -40018,9 +37034,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway TLS", "help": "TLS certificate and key settings for terminating HTTPS directly in the gateway process. Use explicit certificates in production and avoid plaintext exposure on untrusted networks.", "hasChildren": true @@ -40032,9 +37046,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway TLS Auto-Generate Cert", "help": "Auto-generates a local TLS certificate/key pair when explicit files are not configured. Use only for local/dev setups and replace with real certificates for production traffic.", "hasChildren": false @@ -40046,10 +37058,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "storage" - ], + "tags": ["network", "storage"], "label": "Gateway TLS CA Path", "help": "Optional CA bundle path for client verification or custom trust-chain requirements at the gateway edge. Use this when private PKI or custom certificate chains are part of deployment.", "hasChildren": false @@ -40061,10 +37070,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "storage" - ], + "tags": ["network", "storage"], "label": "Gateway TLS Certificate Path", "help": "Filesystem path to the TLS certificate file used by the gateway when TLS is enabled. Use managed certificate paths and keep renewal automation aligned with this location.", "hasChildren": false @@ -40076,9 +37082,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway TLS Enabled", "help": "Enables TLS termination at the gateway listener so clients connect over HTTPS/WSS directly. Keep enabled for direct internet exposure or any untrusted network boundary.", "hasChildren": false @@ -40090,10 +37094,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network", - "storage" - ], + "tags": ["network", "storage"], "label": "Gateway TLS Key Path", "help": "Filesystem path to the TLS private key file used by the gateway when TLS is enabled. Keep this key file permission-restricted and rotate per your security policy.", "hasChildren": false @@ -40105,9 +37106,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Tool Exposure Policy", "help": "Gateway-level tool exposure allow/deny policy that can restrict runtime tool availability independent of agent/tool profiles. Use this for coarse emergency controls and production hardening.", "hasChildren": true @@ -40119,10 +37118,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Gateway Tool Allowlist", "help": "Explicit gateway-level tool allowlist when you want a narrow set of tools available at runtime. Use this for locked-down environments where tool scope must be tightly controlled.", "hasChildren": true @@ -40144,10 +37140,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network" - ], + "tags": ["access", "network"], "label": "Gateway Tool Denylist", "help": "Explicit gateway-level tool denylist to block risky tools even if lower-level policies allow them. Use deny rules for emergency response and defense-in-depth hardening.", "hasChildren": true @@ -40169,9 +37162,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Gateway Trusted Proxy CIDRs", "help": "CIDR/IP allowlist of upstream proxies permitted to provide forwarded client identity headers. Keep this list narrow so untrusted hops cannot impersonate users.", "hasChildren": true @@ -40193,9 +37184,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hooks", "help": "Inbound webhook automation surface for mapping external events into wake or agent actions in OpenClaw. Keep this locked down with explicit token/session/agent controls before exposing it beyond trusted networks.", "hasChildren": true @@ -40207,9 +37196,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Hooks Allowed Agent IDs", "help": "Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents.", "hasChildren": true @@ -40231,10 +37218,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Hooks Allowed Session Key Prefixes", "help": "Allowlist of accepted session-key prefixes for inbound hook requests when caller-provided keys are enabled. Use narrow prefixes to prevent arbitrary session-key injection.", "hasChildren": true @@ -40256,10 +37240,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Hooks Allow Request Session Key", "help": "Allows callers to supply a session key in hook requests when true, enabling caller-controlled routing. Keep false unless trusted integrators explicitly need custom session threading.", "hasChildren": false @@ -40271,9 +37252,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Hooks Default Session Key", "help": "Fallback session key used for hook deliveries when a request does not provide one through allowed channels. Use a stable but scoped key to avoid mixing unrelated automation conversations.", "hasChildren": false @@ -40285,9 +37264,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hooks Enabled", "help": "Enables the hooks endpoint and mapping execution pipeline for inbound webhook requests. Keep disabled unless you are actively routing external events into the gateway.", "hasChildren": false @@ -40299,9 +37276,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook", "help": "Gmail push integration settings used for Pub/Sub notifications and optional local callback serving. Keep this scoped to dedicated Gmail automation accounts where possible.", "hasChildren": true @@ -40313,9 +37288,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Account", "help": "Google account identifier used for Gmail watch/subscription operations in this hook integration. Use a dedicated automation mailbox account to isolate operational permissions.", "hasChildren": false @@ -40327,9 +37300,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Gmail Hook Allow Unsafe External Content", "help": "Allows less-sanitized external Gmail content to pass into processing when enabled. Keep disabled for safer defaults, and enable only for trusted mail streams with controlled transforms.", "hasChildren": false @@ -40341,9 +37312,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Callback URL", "help": "Public callback URL Gmail or intermediaries invoke to deliver notifications into this hook pipeline. Keep this URL protected with token validation and restricted network exposure.", "hasChildren": false @@ -40355,9 +37324,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Include Body", "help": "When true, fetch and include email body content for downstream mapping/agent processing. Keep false unless body text is required, because this increases payload size and sensitivity.", "hasChildren": false @@ -40369,9 +37336,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Label", "help": "Optional Gmail label filter limiting which labeled messages trigger hook events. Keep filters narrow to avoid flooding automations with unrelated inbox traffic.", "hasChildren": false @@ -40383,9 +37348,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Gmail Hook Max Body Bytes", "help": "Maximum Gmail payload bytes processed per event when includeBody is enabled. Keep conservative limits to reduce oversized message processing cost and risk.", "hasChildren": false @@ -40397,9 +37360,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Gmail Hook Model Override", "help": "Optional model override for Gmail-triggered runs when mailbox automations should use dedicated model behavior. Keep unset to inherit agent defaults unless mailbox tasks need specialization.", "hasChildren": false @@ -40411,10 +37372,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Gmail Hook Push Token", "help": "Shared secret token required on Gmail push hook callbacks before processing notifications. Use env substitution and rotate if callback endpoints are exposed externally.", "hasChildren": false @@ -40426,9 +37384,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Renew Interval (min)", "help": "Renewal cadence in minutes for Gmail watch subscriptions to prevent expiration. Set below provider expiration windows and monitor renew failures in logs.", "hasChildren": false @@ -40440,9 +37396,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Local Server", "help": "Local callback server settings block for directly receiving Gmail notifications without a separate ingress layer. Enable only when this process should terminate webhook traffic itself.", "hasChildren": true @@ -40454,9 +37408,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Server Bind Address", "help": "Bind address for the local Gmail callback HTTP server used when serving hooks directly. Keep loopback-only unless external ingress is intentionally required.", "hasChildren": false @@ -40468,9 +37420,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Gmail Hook Server Path", "help": "HTTP path on the local Gmail callback server where push notifications are accepted. Keep this consistent with subscription configuration to avoid dropped events.", "hasChildren": false @@ -40482,9 +37432,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Server Port", "help": "Port for the local Gmail callback HTTP server when serve mode is enabled. Use a dedicated port to avoid collisions with gateway/control interfaces.", "hasChildren": false @@ -40496,9 +37444,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Subscription", "help": "Pub/Sub subscription consumed by the gateway to receive Gmail change notifications from the configured topic. Keep subscription ownership clear so multiple consumers do not race unexpectedly.", "hasChildren": false @@ -40510,9 +37456,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Tailscale", "help": "Tailscale exposure configuration block for publishing Gmail callbacks through Serve/Funnel routes. Use private tailnet modes before enabling any public ingress path.", "hasChildren": true @@ -40524,9 +37468,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Tailscale Mode", "help": "Tailscale exposure mode for Gmail callbacks: \"off\", \"serve\", or \"funnel\". Use \"serve\" for private tailnet delivery and \"funnel\" only when public internet ingress is required.", "hasChildren": false @@ -40538,9 +37480,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Gmail Hook Tailscale Path", "help": "Path published by Tailscale Serve/Funnel for Gmail callback forwarding when enabled. Keep it aligned with Gmail webhook config so requests reach the expected handler.", "hasChildren": false @@ -40552,9 +37492,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Tailscale Target", "help": "Local service target forwarded by Tailscale Serve/Funnel (for example http://127.0.0.1:8787). Use explicit loopback targets to avoid ambiguous routing.", "hasChildren": false @@ -40566,9 +37504,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Thinking Override", "help": "Thinking effort override for Gmail-driven agent runs: \"off\", \"minimal\", \"low\", \"medium\", or \"high\". Keep modest defaults for routine inbox automations to control cost and latency.", "hasChildren": false @@ -40580,9 +37516,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gmail Hook Pub/Sub Topic", "help": "Google Pub/Sub topic name used by Gmail watch to publish change notifications for this account. Ensure the topic IAM grants Gmail publish access before enabling watches.", "hasChildren": false @@ -40594,9 +37528,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hooks", "help": "Internal hook runtime settings for bundled/custom event handlers loaded from module paths. Use this for trusted in-process automations and keep handler loading tightly scoped.", "hasChildren": true @@ -40608,9 +37540,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hooks Enabled", "help": "Enables processing for internal hook handlers and configured entries in the internal hook runtime. Keep disabled unless internal hook handlers are intentionally configured.", "hasChildren": false @@ -40622,9 +37552,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Entries", "help": "Configured internal hook entry records used to register concrete runtime handlers and metadata. Keep entries explicit and versioned so production behavior is auditable.", "hasChildren": true @@ -40685,9 +37613,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Handlers", "help": "List of internal event handlers mapping event names to modules and optional exports. Keep handler definitions explicit so event-to-code routing is auditable.", "hasChildren": true @@ -40709,9 +37635,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Event", "help": "Internal event name that triggers this handler module when emitted by the runtime. Use stable event naming conventions to avoid accidental overlap across handlers.", "hasChildren": false @@ -40723,9 +37647,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Export", "help": "Optional named export for the internal hook handler function when module default export is not used. Set this when one module ships multiple handler entrypoints.", "hasChildren": false @@ -40737,9 +37659,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Module", "help": "Safe relative module path for the internal hook handler implementation loaded at runtime. Keep module files in reviewed directories and avoid dynamic path composition.", "hasChildren": false @@ -40751,9 +37671,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Install Records", "help": "Install metadata for internal hook modules, including source and resolved artifacts for repeatable deployments. Use this as operational provenance and avoid manual drift edits.", "hasChildren": true @@ -40915,9 +37833,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Internal Hook Loader", "help": "Internal hook loader settings controlling where handler modules are discovered at startup. Use constrained load roots to reduce accidental module conflicts or shadowing.", "hasChildren": true @@ -40929,9 +37845,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Internal Hook Extra Directories", "help": "Additional directories searched for internal hook modules beyond default load paths. Keep this minimal and controlled to reduce accidental module shadowing.", "hasChildren": true @@ -40953,9 +37867,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mappings", "help": "Ordered mapping rules that match inbound hook requests and choose wake or agent actions with optional delivery routing. Use specific mappings first to avoid broad pattern rules capturing everything.", "hasChildren": true @@ -40977,9 +37889,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Action", "help": "Mapping action type: \"wake\" triggers agent wake flow, while \"agent\" sends directly to agent handling. Use \"agent\" for immediate execution and \"wake\" when heartbeat-driven processing is preferred.", "hasChildren": false @@ -40991,9 +37901,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Agent ID", "help": "Target agent ID for mapping execution when action routing should not use defaults. Use dedicated automation agents to isolate webhook behavior from interactive operator sessions.", "hasChildren": false @@ -41005,9 +37913,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Hook Mapping Allow Unsafe External Content", "help": "When true, mapping content may include less-sanitized external payload data in generated messages. Keep false by default and enable only for trusted sources with reviewed transform logic.", "hasChildren": false @@ -41019,9 +37925,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Delivery Channel", "help": "Delivery channel override for mapping outputs (for example \"last\", \"telegram\", \"discord\", \"slack\", \"signal\", \"imessage\", or \"msteams\"). Keep channel overrides explicit to avoid accidental cross-channel sends.", "hasChildren": false @@ -41033,9 +37937,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Deliver Reply", "help": "Controls whether mapping execution results are delivered back to a channel destination versus being processed silently. Disable delivery for background automations that should not post user-facing output.", "hasChildren": false @@ -41047,9 +37949,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping ID", "help": "Optional stable identifier for a hook mapping entry used for auditing, troubleshooting, and targeted updates. Use unique IDs so logs and config diffs can reference mappings unambiguously.", "hasChildren": false @@ -41061,9 +37961,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Match", "help": "Grouping object for mapping match predicates such as path and source before action routing is applied. Keep match criteria specific so unrelated webhook traffic does not trigger automations.", "hasChildren": true @@ -41075,9 +37973,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Hook Mapping Match Path", "help": "Path match condition for a hook mapping, usually compared against the inbound request path. Use this to split automation behavior by webhook endpoint path families.", "hasChildren": false @@ -41089,9 +37985,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Match Source", "help": "Source match condition for a hook mapping, typically set by trusted upstream metadata or adapter logic. Use stable source identifiers so routing remains deterministic across retries.", "hasChildren": false @@ -41103,9 +37997,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Message Template", "help": "Template for synthesizing structured mapping input into the final message content sent to the target action path. Keep templates deterministic so downstream parsing and behavior remain stable.", "hasChildren": false @@ -41117,9 +38009,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Hook Mapping Model Override", "help": "Optional model override for mapping-triggered runs when automation should use a different model than agent defaults. Use this sparingly so behavior remains predictable across mapping executions.", "hasChildren": false @@ -41131,9 +38021,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Name", "help": "Human-readable mapping display name used in diagnostics and operator-facing config UIs. Keep names concise and descriptive so routing intent is obvious during incident review.", "hasChildren": false @@ -41145,10 +38033,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "security", - "storage" - ], + "tags": ["security", "storage"], "label": "Hook Mapping Session Key", "help": "Explicit session key override for mapping-delivered messages to control thread continuity. Use stable scoped keys so repeated events correlate without leaking into unrelated conversations.", "hasChildren": false @@ -41160,9 +38045,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Text Template", "help": "Text-only fallback template used when rich payload rendering is not desired or not supported. Use this to provide a concise, consistent summary string for chat delivery surfaces.", "hasChildren": false @@ -41174,9 +38057,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Thinking Override", "help": "Optional thinking-effort override for mapping-triggered runs to tune latency versus reasoning depth. Keep low or minimal for high-volume hooks unless deeper reasoning is clearly required.", "hasChildren": false @@ -41188,9 +38069,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Hook Mapping Timeout (sec)", "help": "Maximum runtime allowed for mapping action execution before timeout handling applies. Use tighter limits for high-volume webhook sources to prevent queue pileups.", "hasChildren": false @@ -41202,9 +38081,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Delivery Destination", "help": "Destination identifier inside the selected channel when mapping replies should route to a fixed target. Verify provider-specific destination formats before enabling production mappings.", "hasChildren": false @@ -41216,9 +38093,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Transform", "help": "Transform configuration block defining module/export preprocessing before mapping action handling. Use transforms only from reviewed code paths and keep behavior deterministic for repeatable automation.", "hasChildren": true @@ -41230,9 +38105,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Transform Export", "help": "Named export to invoke from the transform module; defaults to module default export when omitted. Set this when one file hosts multiple transform handlers.", "hasChildren": false @@ -41244,9 +38117,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Transform Module", "help": "Relative transform module path loaded from hooks.transformsDir to rewrite incoming payloads before delivery. Keep modules local, reviewed, and free of path traversal patterns.", "hasChildren": false @@ -41258,9 +38129,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hook Mapping Wake Mode", "help": "Wake scheduling mode: \"now\" wakes immediately, while \"next-heartbeat\" defers until the next heartbeat cycle. Use deferred mode for lower-priority automations that can tolerate slight delay.", "hasChildren": false @@ -41272,9 +38141,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Hooks Max Body Bytes", "help": "Maximum accepted webhook payload size in bytes before the request is rejected. Keep this bounded to reduce abuse risk and protect memory usage under bursty integrations.", "hasChildren": false @@ -41286,9 +38153,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Hooks Endpoint Path", "help": "HTTP path used by the hooks endpoint (for example `/hooks`) on the gateway control server. Use a non-guessable path and combine it with token validation for defense in depth.", "hasChildren": false @@ -41300,9 +38165,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Hooks Presets", "help": "Named hook preset bundles applied at load time to seed standard mappings and behavior defaults. Keep preset usage explicit so operators can audit which automations are active.", "hasChildren": true @@ -41324,10 +38187,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Hooks Auth Token", "help": "Shared bearer token checked by hooks ingress for request authentication before mappings run. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.", "hasChildren": false @@ -41339,9 +38199,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Hooks Transforms Directory", "help": "Base directory for hook transform modules referenced by mapping transform.module paths. Use a controlled repo directory so dynamic imports remain reviewable and predictable.", "hasChildren": false @@ -41353,9 +38211,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Logging", "help": "Logging behavior controls for severity, output destinations, formatting, and sensitive-data redaction. Keep levels and redaction strict enough for production while preserving useful diagnostics.", "hasChildren": true @@ -41367,9 +38223,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Console Log Level", "help": "Console-specific log threshold: \"silent\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", or \"trace\" for terminal output control. Use this to keep local console quieter while retaining richer file logging if needed.", "hasChildren": false @@ -41381,9 +38235,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Console Log Style", "help": "Console output format style: \"pretty\", \"compact\", or \"json\" based on operator and ingestion needs. Use json for machine parsing pipelines and pretty/compact for human-first terminal workflows.", "hasChildren": false @@ -41395,10 +38247,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "storage" - ], + "tags": ["observability", "storage"], "label": "Log File Path", "help": "Optional file path for persisted log output in addition to or instead of console logging. Use a managed writable path and align retention/rotation with your operational policy.", "hasChildren": false @@ -41410,9 +38259,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Log Level", "help": "Primary log level threshold for runtime logger output: \"silent\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", or \"trace\". Keep \"info\" or \"warn\" for production, and use debug/trace only during investigation.", "hasChildren": false @@ -41434,10 +38281,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "privacy" - ], + "tags": ["observability", "privacy"], "label": "Custom Redaction Patterns", "help": "Additional custom redact regex patterns applied to log output before emission/storage. Use this to mask org-specific tokens and identifiers not covered by built-in redaction rules.", "hasChildren": true @@ -41459,10 +38303,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability", - "privacy" - ], + "tags": ["observability", "privacy"], "label": "Sensitive Data Redaction Mode", "help": "Sensitive redaction mode: \"off\" disables built-in masking, while \"tools\" redacts sensitive tool/config payload fields. Keep \"tools\" in shared logs unless you have isolated secure log sinks.", "hasChildren": false @@ -41474,9 +38315,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Media", "help": "Top-level media behavior shared across providers and tools that handle inbound files. Keep defaults unless you need stable filenames for external processing pipelines or longer-lived inbound media retention.", "hasChildren": true @@ -41488,9 +38327,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Preserve Media Filenames", "help": "When enabled, uploaded media keeps its original filename instead of a generated temp-safe name. Turn this on when downstream automations depend on stable names, and leave off to reduce accidental filename leakage.", "hasChildren": false @@ -41502,9 +38339,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Media Retention TTL (hours)", "help": "Optional retention window in hours for persisted inbound media cleanup across the full media tree. Leave unset to preserve legacy behavior, or set values like 24 (1 day) or 168 (7 days) when you want automatic cleanup.", "hasChildren": false @@ -41516,9 +38351,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory", "help": "Memory backend configuration (global).", "hasChildren": true @@ -41530,9 +38363,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Backend", "help": "Selects the global memory engine: \"builtin\" uses OpenClaw memory internals, while \"qmd\" uses the QMD sidecar pipeline. Keep \"builtin\" unless you intentionally operate QMD.", "hasChildren": false @@ -41544,9 +38375,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Memory Citations Mode", "help": "Controls citation visibility in replies: \"auto\" shows citations when useful, \"on\" always shows them, and \"off\" hides them. Keep \"auto\" for a balanced signal-to-noise default.", "hasChildren": false @@ -41568,9 +38397,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Binary", "help": "Sets the executable path for the `qmd` binary used by the QMD backend (default: resolved from PATH). Use an explicit absolute path when multiple qmd installs exist or PATH differs across environments.", "hasChildren": false @@ -41582,9 +38409,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Include Default Memory", "help": "Automatically indexes default memory files (MEMORY.md and memory/**/*.md) into QMD collections. Keep enabled unless you want indexing controlled only through explicit custom paths.", "hasChildren": false @@ -41606,10 +38431,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Max Injected Chars", "help": "Caps how much QMD text can be injected into one turn across all hits. Use lower values to control prompt bloat and latency; raise only when context is consistently truncated.", "hasChildren": false @@ -41621,10 +38443,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Max Results", "help": "Limits how many QMD hits are returned into the agent loop for each recall request (default: 6). Increase for broader recall context, or lower to keep prompts tighter and faster.", "hasChildren": false @@ -41636,10 +38455,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Max Snippet Chars", "help": "Caps per-result snippet length extracted from QMD hits in characters (default: 700). Lower this when prompts bloat quickly, and raise only if answers consistently miss key details.", "hasChildren": false @@ -41651,10 +38467,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Search Timeout (ms)", "help": "Sets per-query QMD search timeout in milliseconds (default: 4000). Increase for larger indexes or slower environments, and lower to keep request latency bounded.", "hasChildren": false @@ -41666,9 +38479,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD MCPorter", "help": "Routes QMD work through mcporter (MCP runtime) instead of spawning `qmd` for each call. Use this when cold starts are expensive on large models; keep direct process mode for simpler local setups.", "hasChildren": true @@ -41680,9 +38491,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD MCPorter Enabled", "help": "Routes QMD through an mcporter daemon instead of spawning qmd per request, reducing cold-start overhead for larger models. Keep disabled unless mcporter is installed and configured.", "hasChildren": false @@ -41694,9 +38503,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD MCPorter Server Name", "help": "Names the mcporter server target used for QMD calls (default: qmd). Change only when your mcporter setup uses a custom server name for qmd mcp keep-alive.", "hasChildren": false @@ -41708,9 +38515,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD MCPorter Start Daemon", "help": "Automatically starts the mcporter daemon when mcporter-backed QMD mode is enabled (default: true). Keep enabled unless process lifecycle is managed externally by your service supervisor.", "hasChildren": false @@ -41722,9 +38527,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Extra Paths", "help": "Adds custom directories or files to include in QMD indexing, each with an optional name and glob pattern. Use this for project-specific knowledge locations that are outside default memory paths.", "hasChildren": true @@ -41776,9 +38579,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Surface Scope", "help": "Defines which sessions/channels are eligible for QMD recall using session.sendPolicy-style rules. Keep default direct-only scope unless you intentionally want cross-chat memory sharing.", "hasChildren": true @@ -41880,9 +38681,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Search Mode", "help": "Selects the QMD retrieval path: \"query\" uses standard query flow, \"search\" uses search-oriented retrieval, and \"vsearch\" emphasizes vector retrieval. Keep default unless tuning relevance quality.", "hasChildren": false @@ -41904,9 +38703,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Session Indexing", "help": "Indexes session transcripts into QMD so recall can include prior conversation content (experimental, default: false). Enable only when transcript memory is required and you accept larger index churn.", "hasChildren": false @@ -41918,9 +38715,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Session Export Directory", "help": "Overrides where sanitized session exports are written before QMD indexing. Use this when default state storage is constrained or when exports must land on a managed volume.", "hasChildren": false @@ -41932,9 +38727,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Session Retention (days)", "help": "Defines how long exported session files are kept before automatic pruning, in days (default: unlimited). Set a finite value for storage hygiene or compliance retention policies.", "hasChildren": false @@ -41956,10 +38749,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Command Timeout (ms)", "help": "Sets timeout for QMD maintenance commands such as collection list/add in milliseconds (default: 30000). Increase when running on slower disks or remote filesystems that delay command completion.", "hasChildren": false @@ -41971,10 +38761,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Update Debounce (ms)", "help": "Sets the minimum delay between consecutive QMD refresh attempts in milliseconds (default: 15000). Increase this if frequent file changes cause update thrash or unnecessary background load.", "hasChildren": false @@ -41986,10 +38773,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Embed Interval", "help": "Sets how often QMD recomputes embeddings (duration string, default: 60m; set 0 to disable periodic embeds). Lower intervals improve freshness but increase embedding workload and cost.", "hasChildren": false @@ -42001,10 +38785,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Embed Timeout (ms)", "help": "Sets maximum runtime for each `qmd embed` cycle in milliseconds (default: 120000). Increase for heavier embedding workloads or slower hardware, and lower to fail fast under tight SLAs.", "hasChildren": false @@ -42016,10 +38797,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Update Interval", "help": "Sets how often QMD refreshes indexes from source content (duration string, default: 5m). Shorter intervals improve freshness but increase background CPU and I/O.", "hasChildren": false @@ -42031,9 +38809,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Update on Startup", "help": "Runs an initial QMD update once during gateway startup (default: true). Keep enabled so recall starts from a fresh baseline; disable only when startup speed is more important than immediate freshness.", "hasChildren": false @@ -42045,10 +38821,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "QMD Update Timeout (ms)", "help": "Sets maximum runtime for each `qmd update` cycle in milliseconds (default: 120000). Raise this for larger collections; lower it when you want quicker failure detection in automation.", "hasChildren": false @@ -42060,9 +38833,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "QMD Wait for Boot Sync", "help": "Blocks startup completion until the initial boot-time QMD sync finishes (default: false). Enable when you need fully up-to-date recall before serving traffic, and keep off for faster boot.", "hasChildren": false @@ -42074,9 +38845,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Messages", "help": "Message formatting, acknowledgment, queueing, debounce, and status reaction behavior for inbound/outbound chat flows. Use this section when channel responsiveness or message UX needs adjustment.", "hasChildren": true @@ -42088,9 +38857,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Ack Reaction Emoji", "help": "Emoji reaction used to acknowledge inbound messages (empty disables).", "hasChildren": false @@ -42100,19 +38867,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "group-mentions", - "group-all", - "direct", - "all", - "off", - "none" - ], + "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Ack Reaction Scope", "help": "When to send ack reactions (\"group-mentions\", \"group-all\", \"direct\", \"all\", \"off\", \"none\"). \"off\"/\"none\" disables ack reactions entirely.", "hasChildren": false @@ -42124,9 +38882,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Group Chat Rules", "help": "Group-message handling controls including mention triggers and history window sizing. Keep mention patterns narrow so group channels do not trigger on every message.", "hasChildren": true @@ -42138,9 +38894,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Group History Limit", "help": "Maximum number of prior group messages loaded as context per turn for group sessions. Use higher values for richer continuity, or lower values for faster and cheaper responses.", "hasChildren": false @@ -42152,9 +38906,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Group Mention Patterns", "help": "Safe case-insensitive regex patterns used to detect explicit mentions/trigger phrases in group chats. Use precise patterns to reduce false positives in high-volume channels; invalid or unsafe nested-repetition patterns are ignored.", "hasChildren": true @@ -42176,9 +38928,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Inbound Debounce", "help": "Direct inbound debounce settings used before queue/turn processing starts. Configure this for provider-specific rapid message bursts from the same sender.", "hasChildren": true @@ -42190,9 +38940,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Inbound Debounce by Channel (ms)", "help": "Per-channel inbound debounce overrides keyed by provider id in milliseconds. Use this where some providers send message fragments more aggressively than others.", "hasChildren": true @@ -42214,9 +38962,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Inbound Message Debounce (ms)", "help": "Debounce window (ms) for batching rapid inbound messages from the same sender (0 to disable).", "hasChildren": false @@ -42228,9 +38974,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Inbound Message Prefix", "help": "Prefix text prepended to inbound user messages before they are handed to the agent runtime. Use this sparingly for channel context markers and keep it stable across sessions.", "hasChildren": false @@ -42242,9 +38986,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Inbound Queue", "help": "Inbound message queue strategy used to buffer bursts before processing turns. Tune this for busy channels where sequential processing or batching behavior matters.", "hasChildren": true @@ -42256,9 +38998,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Queue Mode by Channel", "help": "Per-channel queue mode overrides keyed by provider id (for example telegram, discord, slack). Use this when one channel’s traffic pattern needs different queue behavior than global defaults.", "hasChildren": true @@ -42370,9 +39110,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Queue Capacity", "help": "Maximum number of queued inbound items retained before drop policy applies. Keep caps bounded in noisy channels so memory usage remains predictable.", "hasChildren": false @@ -42384,9 +39122,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Queue Debounce (ms)", "help": "Global queue debounce window in milliseconds before processing buffered inbound messages. Use higher values to coalesce rapid bursts, or lower values for reduced response latency.", "hasChildren": false @@ -42398,9 +39134,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Queue Debounce by Channel (ms)", "help": "Per-channel debounce overrides for queue behavior keyed by provider id. Use this to tune burst handling independently for chat surfaces with different pacing.", "hasChildren": true @@ -42422,9 +39156,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Queue Drop Strategy", "help": "Drop strategy when queue cap is exceeded: \"old\", \"new\", or \"summarize\". Use summarize when preserving intent matters, or old/new when deterministic dropping is preferred.", "hasChildren": false @@ -42436,9 +39168,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Queue Mode", "help": "Queue behavior mode: \"steer\", \"followup\", \"collect\", \"steer-backlog\", \"steer+backlog\", \"queue\", or \"interrupt\". Keep conservative modes unless you intentionally need aggressive interruption/backlog semantics.", "hasChildren": false @@ -42450,9 +39180,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Remove Ack Reaction After Reply", "help": "Removes the acknowledgment reaction after final reply delivery when enabled. Keep enabled for cleaner UX in channels where persistent ack reactions create clutter.", "hasChildren": false @@ -42464,9 +39192,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Outbound Response Prefix", "help": "Prefix text prepended to outbound assistant replies before sending to channels. Use for lightweight branding/context tags and avoid long prefixes that reduce content density.", "hasChildren": false @@ -42478,9 +39204,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Status Reactions", "help": "Lifecycle status reactions that update the emoji on the trigger message as the agent progresses (queued → thinking → tool → done/error).", "hasChildren": true @@ -42492,9 +39216,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Status Reaction Emojis", "help": "Override default status reaction emojis. Keys: thinking, compacting, tool, coding, web, done, error, stallSoft, stallHard. Must be valid Telegram reaction emojis.", "hasChildren": true @@ -42596,9 +39318,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Status Reactions", "help": "Enable lifecycle status reactions for Telegram. When enabled, the ack reaction becomes the initial 'queued' state and progresses through thinking, tool, done/error automatically. Default: false.", "hasChildren": false @@ -42610,9 +39330,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Status Reaction Timing", "help": "Override default timing. Keys: debounceMs (700), stallSoftMs (25000), stallHardMs (60000), doneHoldMs (1500), errorHoldMs (2500).", "hasChildren": true @@ -42674,9 +39392,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Suppress Tool Error Warnings", "help": "When true, suppress ⚠️ tool-error warnings from being shown to the user. The agent already sees errors in context and can retry. Default: false.", "hasChildren": false @@ -42688,9 +39404,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Message Text-to-Speech", "help": "Text-to-speech policy for reading agent replies aloud on supported voice or audio surfaces. Keep disabled unless voice playback is part of your operator/user workflow.", "hasChildren": true @@ -42700,12 +39414,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "off", - "always", - "inbound", - "tagged" - ], + "enumValues": ["off", "always", "inbound", "tagged"], "deprecated": false, "sensitive": false, "tags": [], @@ -42834,18 +39543,11 @@ { "path": "messages.tts.elevenlabs.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "media", - "security" - ], + "tags": ["auth", "media", "security"], "hasChildren": true }, { @@ -42883,11 +39585,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "auto", - "on", - "off" - ], + "enumValues": ["auto", "on", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -43028,10 +39726,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "final", - "all" - ], + "enumValues": ["final", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -43140,18 +39835,11 @@ { "path": "messages.tts.openai.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "media", - "security" - ], + "tags": ["auth", "media", "security"], "hasChildren": true }, { @@ -43249,11 +39937,7 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "elevenlabs", - "openai", - "edge" - ], + "enumValues": ["elevenlabs", "openai", "edge"], "deprecated": false, "sensitive": false, "tags": [], @@ -43286,9 +39970,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Metadata", "help": "Metadata fields automatically maintained by OpenClaw to record write/version history for this config file. Keep these values system-managed and avoid manual edits unless debugging migration history.", "hasChildren": true @@ -43300,9 +39982,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Config Last Touched At", "help": "ISO timestamp of the last config write (auto-set).", "hasChildren": false @@ -43314,9 +39994,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Config Last Touched Version", "help": "Auto-set when OpenClaw writes the config.", "hasChildren": false @@ -43328,9 +40006,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Models", "help": "Model catalog root for provider definitions, merge/replace behavior, and optional Bedrock discovery integration. Keep provider definitions explicit and validated before relying on production failover paths.", "hasChildren": true @@ -43342,9 +40018,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Bedrock Model Discovery", "help": "Automatic AWS Bedrock model discovery settings used to synthesize provider model entries from account visibility. Keep discovery scoped and refresh intervals conservative to reduce API churn.", "hasChildren": true @@ -43356,9 +40030,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Bedrock Default Context Window", "help": "Fallback context-window value applied to discovered models when provider metadata lacks explicit limits. Use realistic defaults to avoid oversized prompts that exceed true provider constraints.", "hasChildren": false @@ -43370,12 +40042,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "models", - "performance", - "security" - ], + "tags": ["auth", "models", "performance", "security"], "label": "Bedrock Default Max Tokens", "help": "Fallback max-token value applied to discovered models without explicit output token limits. Use conservative defaults to reduce truncation surprises and unexpected token spend.", "hasChildren": false @@ -43387,9 +40054,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Bedrock Discovery Enabled", "help": "Enables periodic Bedrock model discovery and catalog refresh for Bedrock-backed providers. Keep disabled unless Bedrock is actively used and IAM permissions are correctly configured.", "hasChildren": false @@ -43401,9 +40066,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Bedrock Discovery Provider Filter", "help": "Optional provider allowlist filter for Bedrock discovery so only selected providers are refreshed. Use this to limit discovery scope in multi-provider environments.", "hasChildren": true @@ -43425,10 +40088,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "performance" - ], + "tags": ["models", "performance"], "label": "Bedrock Discovery Refresh Interval (s)", "help": "Refresh cadence for Bedrock discovery polling in seconds to detect newly available models over time. Use longer intervals in production to reduce API cost and control-plane noise.", "hasChildren": false @@ -43440,9 +40100,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Bedrock Discovery Region", "help": "AWS region used for Bedrock discovery calls when discovery is enabled for your deployment. Use the region where your Bedrock models are provisioned to avoid empty discovery results.", "hasChildren": false @@ -43454,9 +40112,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Catalog Mode", "help": "Controls provider catalog behavior: \"merge\" keeps built-ins and overlays your custom providers, while \"replace\" uses only your configured providers. In \"merge\", matching provider IDs preserve non-empty agent models.json baseUrl values, while apiKey values are preserved only when the provider is not SecretRef-managed in current config/auth-profile context; SecretRef-managed providers refresh apiKey from current source markers, and matching model contextWindow/maxTokens use the higher value between explicit and implicit entries.", "hasChildren": false @@ -43468,9 +40124,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Providers", "help": "Provider map keyed by provider ID containing connection/auth settings and concrete model definitions. Use stable provider keys so references from agents and tooling remain portable across environments.", "hasChildren": true @@ -43502,9 +40156,7 @@ ], "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider API Adapter", "help": "Provider API adapter selection controlling request/response compatibility handling for model calls. Use the adapter that matches your upstream provider protocol to avoid feature mismatch.", "hasChildren": false @@ -43512,18 +40164,11 @@ { "path": "models.providers.*.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "models", - "security" - ], + "tags": ["auth", "models", "security"], "label": "Model Provider API Key", "help": "Provider credential used for API-key based authentication when the provider requires direct key auth. Use secret/env substitution and avoid storing real keys in committed config files.", "hasChildren": true @@ -43565,9 +40210,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Auth Mode", "help": "Selects provider auth style: \"api-key\" for API key auth, \"token\" for bearer token auth, \"oauth\" for OAuth credentials, and \"aws-sdk\" for AWS credential resolution. Match this to your provider requirements.", "hasChildren": false @@ -43579,9 +40222,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Authorization Header", "help": "When true, credentials are sent via the HTTP Authorization header even if alternate auth is possible. Use this only when your provider or proxy explicitly requires Authorization forwarding.", "hasChildren": false @@ -43593,9 +40234,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Base URL", "help": "Base URL for the provider endpoint used to serve model requests for that provider entry. Use HTTPS endpoints and keep URLs environment-specific through config templating where needed.", "hasChildren": false @@ -43607,9 +40246,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Headers", "help": "Static HTTP headers merged into provider requests for tenant routing, proxy auth, or custom gateway requirements. Use this sparingly and keep sensitive header values in secrets.", "hasChildren": true @@ -43617,17 +40254,11 @@ { "path": "models.providers.*.headers.*", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "models", - "security" - ], + "tags": ["models", "security"], "hasChildren": true }, { @@ -43667,9 +40298,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Inject num_ctx (OpenAI Compat)", "help": "Controls whether OpenClaw injects `options.num_ctx` for Ollama providers configured with the OpenAI-compatible adapter (`openai-completions`). Default is true. Set false only if your proxy/upstream rejects unknown `options` payload fields.", "hasChildren": false @@ -43681,9 +40310,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "models" - ], + "tags": ["models"], "label": "Model Provider Model List", "help": "Declared model list for a provider including identifiers, metadata, and optional compatibility/cost hints. Keep IDs exact to provider catalog values so selection and fallback resolve correctly.", "hasChildren": true @@ -44005,9 +40632,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Node Host", "help": "Node host controls for features exposed from this gateway node to other nodes or clients. Keep defaults unless you intentionally proxy local capabilities across your node network.", "hasChildren": true @@ -44019,9 +40644,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Node Browser Proxy", "help": "Groups browser-proxy settings for exposing local browser control through node routing. Enable only when remote node workflows need your local browser profiles.", "hasChildren": true @@ -44033,11 +40656,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "network", - "storage" - ], + "tags": ["access", "network", "storage"], "label": "Node Browser Proxy Allowed Profiles", "help": "Optional allowlist of browser profile names exposed through node proxy routing. Leave empty to expose all configured profiles, or use a tight list to enforce least-privilege profile access.", "hasChildren": true @@ -44059,9 +40678,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "network" - ], + "tags": ["network"], "label": "Node Browser Proxy Enabled", "help": "Expose the local browser control server through node proxy routing so remote clients can use this host's browser capabilities. Keep disabled unless remote automation explicitly depends on it.", "hasChildren": false @@ -44073,9 +40690,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugins", "help": "Plugin system controls for enabling extensions, constraining load scope, configuring entries, and tracking installs. Keep plugin policy explicit and least-privilege in production environments.", "hasChildren": true @@ -44087,9 +40702,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Plugin Allowlist", "help": "Optional allowlist of plugin IDs; when set, only listed plugins are eligible to load. Use this to enforce approved extension inventories in controlled environments.", "hasChildren": true @@ -44111,9 +40724,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Plugin Denylist", "help": "Optional denylist of plugin IDs that are blocked even if allowlists or paths include them. Use deny rules for emergency rollback and hard blocks on risky plugins.", "hasChildren": true @@ -44135,9 +40746,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Plugins", "help": "Enable or disable plugin/extension loading globally during startup and config reload (default: true). Keep enabled only when extension capabilities are required by your deployment.", "hasChildren": false @@ -44149,9 +40758,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Entries", "help": "Per-plugin settings keyed by plugin ID including enablement and plugin-specific runtime configuration payloads. Use this for scoped plugin tuning without changing global loader policy.", "hasChildren": true @@ -44173,9 +40780,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Config", "help": "Plugin-defined configuration payload interpreted by that plugin's own schema and validation rules. Use only documented fields from the plugin to prevent ignored or invalid settings.", "hasChildren": true @@ -44196,9 +40801,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Enabled", "help": "Per-plugin enablement override for a specific entry, applied on top of global plugin policy (restart required). Use this to stage plugin rollout gradually across environments.", "hasChildren": false @@ -44210,9 +40813,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44224,9 +40825,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44238,9 +40837,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACPX Runtime", "help": "ACP runtime backend powered by acpx with configurable command path and version policy. (plugin: acpx)", "hasChildren": true @@ -44252,9 +40849,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ACPX Runtime Config", "help": "Plugin-defined config payload for acpx.", "hasChildren": true @@ -44266,9 +40861,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "acpx Command", "help": "Optional path/command override for acpx (for example /home/user/repos/acpx/dist/cli.js). Leave unset to use plugin-local bundled acpx.", "hasChildren": false @@ -44280,9 +40873,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Working Directory", "help": "Default cwd for ACP session operations when not set per session.", "hasChildren": false @@ -44294,9 +40885,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Expected acpx Version", "help": "Exact version to enforce (for example 0.1.16) or \"any\" to skip strict version matching.", "hasChildren": false @@ -44308,9 +40897,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "MCP Servers", "help": "Named MCP server definitions to inject into ACPX-backed session bootstrap. Each entry needs a command and can include args and env.", "hasChildren": true @@ -44380,15 +40967,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "deny", - "fail" - ], + "enumValues": ["deny", "fail"], "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Non-Interactive Permission Policy", "help": "acpx policy when interactive permission prompts are unavailable.", "hasChildren": false @@ -44398,16 +40980,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "approve-all", - "approve-reads", - "deny-all" - ], + "enumValues": ["approve-all", "approve-reads", "deny-all"], "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Permission Mode", "help": "Default acpx permission policy for runtime prompts.", "hasChildren": false @@ -44419,10 +40995,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced" - ], + "tags": ["access", "advanced"], "label": "Queue Owner TTL Seconds", "help": "Idle queue-owner TTL for acpx prompt turns. Keep this short in OpenClaw to avoid delayed completion after each turn.", "hasChildren": false @@ -44434,9 +41007,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Strict Windows cmd Wrapper", "help": "Enabled by default. On Windows, reject unresolved .cmd/.bat wrappers instead of shell fallback. Disable only for compatibility with non-standard wrappers.", "hasChildren": false @@ -44448,10 +41019,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "performance" - ], + "tags": ["advanced", "performance"], "label": "Prompt Timeout Seconds", "help": "Optional acpx timeout for each runtime turn.", "hasChildren": false @@ -44463,9 +41031,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable ACPX Runtime", "hasChildren": false }, @@ -44476,9 +41042,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44490,9 +41054,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44504,9 +41066,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/bluebubbles", "help": "OpenClaw BlueBubbles channel plugin (plugin: bluebubbles)", "hasChildren": true @@ -44518,9 +41078,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/bluebubbles Config", "help": "Plugin-defined config payload for bluebubbles.", "hasChildren": false @@ -44532,9 +41090,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/bluebubbles", "hasChildren": false }, @@ -44545,9 +41101,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44559,9 +41113,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44573,9 +41125,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/copilot-proxy", "help": "OpenClaw Copilot Proxy provider plugin (plugin: copilot-proxy)", "hasChildren": true @@ -44587,9 +41137,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/copilot-proxy Config", "help": "Plugin-defined config payload for copilot-proxy.", "hasChildren": false @@ -44601,9 +41149,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/copilot-proxy", "hasChildren": false }, @@ -44614,9 +41160,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44628,9 +41172,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44642,9 +41184,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Device Pairing", "help": "Generate setup codes and approve device pairing requests. (plugin: device-pair)", "hasChildren": true @@ -44656,9 +41196,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Device Pairing Config", "help": "Plugin-defined config payload for device-pair.", "hasChildren": true @@ -44670,9 +41208,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Gateway URL", "help": "Public WebSocket URL used for /pair setup codes (ws/wss or http/https).", "hasChildren": false @@ -44684,9 +41220,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Device Pairing", "hasChildren": false }, @@ -44697,9 +41231,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44711,9 +41243,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44725,9 +41255,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "@openclaw/diagnostics-otel", "help": "OpenClaw diagnostics OpenTelemetry exporter (plugin: diagnostics-otel)", "hasChildren": true @@ -44739,9 +41267,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "@openclaw/diagnostics-otel Config", "help": "Plugin-defined config payload for diagnostics-otel.", "hasChildren": false @@ -44753,9 +41279,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "observability" - ], + "tags": ["observability"], "label": "Enable @openclaw/diagnostics-otel", "hasChildren": false }, @@ -44766,9 +41290,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44780,9 +41302,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44794,9 +41314,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Diffs", "help": "Read-only diff viewer and file renderer for agents. (plugin: diffs)", "hasChildren": true @@ -44808,9 +41326,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Diffs Config", "help": "Plugin-defined config payload for diffs.", "hasChildren": true @@ -44833,9 +41349,7 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Background Highlights", "help": "Show added/removed background highlights by default.", "hasChildren": false @@ -44845,17 +41359,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "bars", - "classic", - "none" - ], + "enumValues": ["bars", "classic", "none"], "defaultValue": "bars", "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Diff Indicator Style", "help": "Choose added/removed indicators style.", "hasChildren": false @@ -44865,16 +41373,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "png", - "pdf" - ], + "enumValues": ["png", "pdf"], "defaultValue": "png", "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Default File Format", "help": "Rendered file format for file mode (PNG or PDF).", "hasChildren": false @@ -44887,10 +41390,7 @@ "defaultValue": 960, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Default File Max Width", "help": "Maximum file render width in CSS pixels.", "hasChildren": false @@ -44900,17 +41400,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "standard", - "hq", - "print" - ], + "enumValues": ["standard", "hq", "print"], "defaultValue": "standard", "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Default File Quality", "help": "Quality preset for PNG/PDF rendering.", "hasChildren": false @@ -44923,9 +41417,7 @@ "defaultValue": 2, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Default File Scale", "help": "Device scale factor used while rendering file artifacts.", "hasChildren": false @@ -44938,9 +41430,7 @@ "defaultValue": "Fira Code", "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Font", "help": "Preferred font family name for diff content and headers.", "hasChildren": false @@ -44953,9 +41443,7 @@ "defaultValue": 15, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Font Size", "help": "Base diff font size in pixels.", "hasChildren": false @@ -44965,10 +41453,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "png", - "pdf" - ], + "enumValues": ["png", "pdf"], "deprecated": false, "sensitive": false, "tags": [], @@ -44979,10 +41464,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "png", - "pdf" - ], + "enumValues": ["png", "pdf"], "deprecated": false, "sensitive": false, "tags": [], @@ -45003,11 +41485,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "standard", - "hq", - "print" - ], + "enumValues": ["standard", "hq", "print"], "deprecated": false, "sensitive": false, "tags": [], @@ -45028,16 +41506,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "unified", - "split" - ], + "enumValues": ["unified", "split"], "defaultValue": "unified", "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Layout", "help": "Initial diff layout shown in the viewer.", "hasChildren": false @@ -45050,9 +41523,7 @@ "defaultValue": 1.6, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Line Spacing", "help": "Line-height multiplier applied to diff rows.", "hasChildren": false @@ -45062,18 +41533,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "view", - "image", - "file", - "both" - ], + "enumValues": ["view", "image", "file", "both"], "defaultValue": "both", "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Output Mode", "help": "Tool default when mode is omitted. Use view for canvas/gateway viewer, file for PNG/PDF, or both.", "hasChildren": false @@ -45086,9 +41550,7 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Show Line Numbers", "help": "Show line numbers by default.", "hasChildren": false @@ -45098,16 +41560,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "light", - "dark" - ], + "enumValues": ["light", "dark"], "defaultValue": "dark", "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Theme", "help": "Initial viewer theme.", "hasChildren": false @@ -45120,9 +41577,7 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Word Wrap", "help": "Wrap long lines by default.", "hasChildren": false @@ -45145,9 +41600,7 @@ "defaultValue": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Remote Viewer", "help": "Allow non-loopback access to diff viewer URLs when the token path is known.", "hasChildren": false @@ -45159,9 +41612,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Diffs", "hasChildren": false }, @@ -45172,9 +41623,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45186,9 +41635,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45200,9 +41647,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/discord", "help": "OpenClaw Discord channel plugin (plugin: discord)", "hasChildren": true @@ -45214,9 +41659,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/discord Config", "help": "Plugin-defined config payload for discord.", "hasChildren": false @@ -45228,9 +41671,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/discord", "hasChildren": false }, @@ -45241,9 +41682,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45255,9 +41694,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45269,9 +41706,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/feishu", "help": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng) (plugin: feishu)", "hasChildren": true @@ -45283,9 +41718,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/feishu Config", "help": "Plugin-defined config payload for feishu.", "hasChildren": false @@ -45297,9 +41730,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/feishu", "hasChildren": false }, @@ -45310,9 +41741,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45324,9 +41753,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45338,9 +41765,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/google-gemini-cli-auth", "help": "OpenClaw Gemini CLI OAuth provider plugin (plugin: google-gemini-cli-auth)", "hasChildren": true @@ -45352,9 +41777,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/google-gemini-cli-auth Config", "help": "Plugin-defined config payload for google-gemini-cli-auth.", "hasChildren": false @@ -45366,9 +41789,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/google-gemini-cli-auth", "hasChildren": false }, @@ -45379,9 +41800,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45393,9 +41812,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45407,9 +41824,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/googlechat", "help": "OpenClaw Google Chat channel plugin (plugin: googlechat)", "hasChildren": true @@ -45421,9 +41836,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/googlechat Config", "help": "Plugin-defined config payload for googlechat.", "hasChildren": false @@ -45435,9 +41848,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/googlechat", "hasChildren": false }, @@ -45448,9 +41859,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45462,9 +41871,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45476,9 +41883,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/imessage", "help": "OpenClaw iMessage channel plugin (plugin: imessage)", "hasChildren": true @@ -45490,9 +41895,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/imessage Config", "help": "Plugin-defined config payload for imessage.", "hasChildren": false @@ -45504,9 +41907,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/imessage", "hasChildren": false }, @@ -45517,9 +41918,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45531,9 +41930,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45545,9 +41942,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/irc", "help": "OpenClaw IRC channel plugin (plugin: irc)", "hasChildren": true @@ -45559,9 +41954,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/irc Config", "help": "Plugin-defined config payload for irc.", "hasChildren": false @@ -45573,9 +41966,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/irc", "hasChildren": false }, @@ -45586,9 +41977,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45600,9 +41989,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45614,9 +42001,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/line", "help": "OpenClaw LINE channel plugin (plugin: line)", "hasChildren": true @@ -45628,9 +42013,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/line Config", "help": "Plugin-defined config payload for line.", "hasChildren": false @@ -45642,9 +42025,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/line", "hasChildren": false }, @@ -45655,9 +42036,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45669,9 +42048,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45683,9 +42060,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "LLM Task", "help": "Generic JSON-only LLM tool for structured tasks callable from workflows. (plugin: llm-task)", "hasChildren": true @@ -45697,9 +42072,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "LLM Task Config", "help": "Plugin-defined config payload for llm-task.", "hasChildren": true @@ -45781,9 +42154,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable LLM Task", "hasChildren": false }, @@ -45794,9 +42165,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45808,9 +42177,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45822,9 +42189,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Lobster", "help": "Typed workflow tool with resumable approvals. (plugin: lobster)", "hasChildren": true @@ -45836,9 +42201,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Lobster Config", "help": "Plugin-defined config payload for lobster.", "hasChildren": false @@ -45850,9 +42213,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Lobster", "hasChildren": false }, @@ -45863,9 +42224,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45877,9 +42236,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45891,9 +42248,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/matrix", "help": "OpenClaw Matrix channel plugin (plugin: matrix)", "hasChildren": true @@ -45905,9 +42260,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/matrix Config", "help": "Plugin-defined config payload for matrix.", "hasChildren": false @@ -45919,9 +42272,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/matrix", "hasChildren": false }, @@ -45932,9 +42283,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45946,9 +42295,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45960,9 +42307,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/mattermost", "help": "OpenClaw Mattermost channel plugin (plugin: mattermost)", "hasChildren": true @@ -45974,9 +42319,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/mattermost Config", "help": "Plugin-defined config payload for mattermost.", "hasChildren": false @@ -45988,9 +42331,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/mattermost", "hasChildren": false }, @@ -46001,9 +42342,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46015,9 +42354,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46029,9 +42366,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/memory-core", "help": "OpenClaw core memory search plugin (plugin: memory-core)", "hasChildren": true @@ -46043,9 +42378,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/memory-core Config", "help": "Plugin-defined config payload for memory-core.", "hasChildren": false @@ -46057,9 +42390,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/memory-core", "hasChildren": false }, @@ -46070,9 +42401,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46084,9 +42413,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46098,9 +42425,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "@openclaw/memory-lancedb", "help": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture (plugin: memory-lancedb)", "hasChildren": true @@ -46112,9 +42437,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "@openclaw/memory-lancedb Config", "help": "Plugin-defined config payload for memory-lancedb.", "hasChildren": true @@ -46126,9 +42449,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Auto-Capture", "help": "Automatically capture important information from conversations", "hasChildren": false @@ -46140,9 +42461,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Auto-Recall", "help": "Automatically inject relevant memories into context", "hasChildren": false @@ -46154,11 +42473,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "performance", - "storage" - ], + "tags": ["advanced", "performance", "storage"], "label": "Capture Max Chars", "help": "Maximum message length eligible for auto-capture", "hasChildren": false @@ -46170,10 +42485,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Database Path", "hasChildren": false }, @@ -46194,11 +42506,7 @@ "required": true, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "storage" - ], + "tags": ["auth", "security", "storage"], "label": "OpenAI API Key", "help": "API key for OpenAI embeddings (or use ${OPENAI_API_KEY})", "hasChildren": false @@ -46210,10 +42518,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Base URL", "help": "Base URL for compatible providers (e.g. http://localhost:11434/v1)", "hasChildren": false @@ -46225,10 +42530,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Dimensions", "help": "Vector dimensions for custom models (required for non-standard models)", "hasChildren": false @@ -46240,10 +42542,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "storage" - ], + "tags": ["models", "storage"], "label": "Embedding Model", "help": "OpenAI embedding model to use", "hasChildren": false @@ -46255,9 +42554,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Enable @openclaw/memory-lancedb", "hasChildren": false }, @@ -46268,9 +42565,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46282,9 +42577,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46296,9 +42589,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "@openclaw/minimax-portal-auth", "help": "OpenClaw MiniMax Portal OAuth provider plugin (plugin: minimax-portal-auth)", "hasChildren": true @@ -46310,9 +42601,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "@openclaw/minimax-portal-auth Config", "help": "Plugin-defined config payload for minimax-portal-auth.", "hasChildren": false @@ -46324,9 +42613,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Enable @openclaw/minimax-portal-auth", "hasChildren": false }, @@ -46337,9 +42624,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46351,9 +42636,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46365,9 +42648,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/msteams", "help": "OpenClaw Microsoft Teams channel plugin (plugin: msteams)", "hasChildren": true @@ -46379,9 +42660,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/msteams Config", "help": "Plugin-defined config payload for msteams.", "hasChildren": false @@ -46393,9 +42672,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/msteams", "hasChildren": false }, @@ -46406,9 +42683,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46420,9 +42695,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46434,9 +42707,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/nextcloud-talk", "help": "OpenClaw Nextcloud Talk channel plugin (plugin: nextcloud-talk)", "hasChildren": true @@ -46448,9 +42719,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/nextcloud-talk Config", "help": "Plugin-defined config payload for nextcloud-talk.", "hasChildren": false @@ -46462,9 +42731,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/nextcloud-talk", "hasChildren": false }, @@ -46475,9 +42742,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46489,9 +42754,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46503,9 +42766,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/nostr", "help": "OpenClaw Nostr channel plugin for NIP-04 encrypted DMs (plugin: nostr)", "hasChildren": true @@ -46517,9 +42778,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/nostr Config", "help": "Plugin-defined config payload for nostr.", "hasChildren": false @@ -46531,9 +42790,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/nostr", "hasChildren": false }, @@ -46544,9 +42801,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46558,9 +42813,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46572,9 +42825,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/ollama-provider", "help": "OpenClaw Ollama provider plugin (plugin: ollama)", "hasChildren": true @@ -46586,9 +42837,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/ollama-provider Config", "help": "Plugin-defined config payload for ollama.", "hasChildren": false @@ -46600,9 +42849,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/ollama-provider", "hasChildren": false }, @@ -46613,9 +42860,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46627,9 +42872,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46641,9 +42884,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "OpenProse", "help": "OpenProse VM skill pack with a /prose slash command. (plugin: open-prose)", "hasChildren": true @@ -46655,9 +42896,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "OpenProse Config", "help": "Plugin-defined config payload for open-prose.", "hasChildren": false @@ -46669,9 +42908,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable OpenProse", "hasChildren": false }, @@ -46682,9 +42919,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46696,9 +42931,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46710,9 +42943,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Phone Control", "help": "Arm/disarm high-risk phone node commands (camera/screen/writes) with an optional auto-expiry. (plugin: phone-control)", "hasChildren": true @@ -46724,9 +42955,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Phone Control Config", "help": "Plugin-defined config payload for phone-control.", "hasChildren": false @@ -46738,9 +42967,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Phone Control", "hasChildren": false }, @@ -46751,9 +42978,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46765,9 +42990,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46779,9 +43002,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "qwen-portal-auth", "help": "Plugin entry for qwen-portal-auth.", "hasChildren": true @@ -46793,9 +43014,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "qwen-portal-auth Config", "help": "Plugin-defined config payload for qwen-portal-auth.", "hasChildren": false @@ -46807,9 +43026,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable qwen-portal-auth", "hasChildren": false }, @@ -46820,9 +43037,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46834,9 +43049,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46848,9 +43061,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/sglang-provider", "help": "OpenClaw SGLang provider plugin (plugin: sglang)", "hasChildren": true @@ -46862,9 +43073,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/sglang-provider Config", "help": "Plugin-defined config payload for sglang.", "hasChildren": false @@ -46876,9 +43085,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/sglang-provider", "hasChildren": false }, @@ -46889,9 +43096,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46903,9 +43108,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46917,9 +43120,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/signal", "help": "OpenClaw Signal channel plugin (plugin: signal)", "hasChildren": true @@ -46931,9 +43132,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/signal Config", "help": "Plugin-defined config payload for signal.", "hasChildren": false @@ -46945,9 +43144,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/signal", "hasChildren": false }, @@ -46958,9 +43155,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -46972,9 +43167,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -46986,9 +43179,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/slack", "help": "OpenClaw Slack channel plugin (plugin: slack)", "hasChildren": true @@ -47000,9 +43191,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/slack Config", "help": "Plugin-defined config payload for slack.", "hasChildren": false @@ -47014,9 +43203,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/slack", "hasChildren": false }, @@ -47027,9 +43214,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47041,9 +43226,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47055,9 +43238,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/synology-chat", "help": "Synology Chat channel plugin for OpenClaw (plugin: synology-chat)", "hasChildren": true @@ -47069,9 +43250,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/synology-chat Config", "help": "Plugin-defined config payload for synology-chat.", "hasChildren": false @@ -47083,9 +43262,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/synology-chat", "hasChildren": false }, @@ -47096,9 +43273,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47110,9 +43285,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47124,9 +43297,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Talk Voice", "help": "Manage Talk voice selection (list/set). (plugin: talk-voice)", "hasChildren": true @@ -47138,9 +43309,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Talk Voice Config", "help": "Plugin-defined config payload for talk-voice.", "hasChildren": false @@ -47152,9 +43321,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Talk Voice", "hasChildren": false }, @@ -47165,9 +43332,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47179,9 +43344,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47193,9 +43356,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/telegram", "help": "OpenClaw Telegram channel plugin (plugin: telegram)", "hasChildren": true @@ -47207,9 +43368,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/telegram Config", "help": "Plugin-defined config payload for telegram.", "hasChildren": false @@ -47221,9 +43380,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/telegram", "hasChildren": false }, @@ -47234,9 +43391,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47248,9 +43403,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47262,9 +43415,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Thread Ownership", "help": "Prevents multiple agents from responding in the same Slack thread. Uses HTTP calls to the slack-forwarder ownership API. (plugin: thread-ownership)", "hasChildren": true @@ -47276,9 +43427,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Thread Ownership Config", "help": "Plugin-defined config payload for thread-ownership.", "hasChildren": true @@ -47290,9 +43439,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "A/B Test Channels", "help": "Slack channel IDs where thread ownership is enforced", "hasChildren": true @@ -47314,9 +43461,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Forwarder URL", "help": "Base URL of the slack-forwarder ownership API (default: http://slack-forwarder:8750)", "hasChildren": false @@ -47328,9 +43473,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Enable Thread Ownership", "hasChildren": false }, @@ -47341,9 +43484,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47355,9 +43496,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47369,9 +43508,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/tlon", "help": "OpenClaw Tlon/Urbit channel plugin (plugin: tlon)", "hasChildren": true @@ -47383,9 +43520,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/tlon Config", "help": "Plugin-defined config payload for tlon.", "hasChildren": false @@ -47397,9 +43532,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/tlon", "hasChildren": false }, @@ -47410,9 +43543,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47424,9 +43555,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47438,9 +43567,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/twitch", "help": "OpenClaw Twitch channel plugin (plugin: twitch)", "hasChildren": true @@ -47452,9 +43579,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/twitch Config", "help": "Plugin-defined config payload for twitch.", "hasChildren": false @@ -47466,9 +43591,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/twitch", "hasChildren": false }, @@ -47479,9 +43602,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47493,9 +43614,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47507,9 +43626,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/vllm-provider", "help": "OpenClaw vLLM provider plugin (plugin: vllm)", "hasChildren": true @@ -47521,9 +43638,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/vllm-provider Config", "help": "Plugin-defined config payload for vllm.", "hasChildren": false @@ -47535,9 +43650,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/vllm-provider", "hasChildren": false }, @@ -47548,9 +43661,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -47562,9 +43673,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -47576,9 +43685,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/voice-call", "help": "OpenClaw voice-call plugin (plugin: voice-call)", "hasChildren": true @@ -47590,9 +43697,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/voice-call Config", "help": "Plugin-defined config payload for voice-call.", "hasChildren": true @@ -47604,9 +43709,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Inbound Allowlist", "hasChildren": true }, @@ -47637,9 +43740,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "From Number", "hasChildren": false }, @@ -47650,9 +43751,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Inbound Greeting", "hasChildren": false }, @@ -47661,17 +43760,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "disabled", - "allowlist", - "pairing", - "open" - ], + "enumValues": ["disabled", "allowlist", "pairing", "open"], "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Inbound Policy", "hasChildren": false }, @@ -47710,15 +43802,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "notify", - "conversation" - ], + "enumValues": ["notify", "conversation"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default Call Mode", "hasChildren": false }, @@ -47729,9 +43816,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Notify Hangup Delay (sec)", "hasChildren": false }, @@ -47770,17 +43855,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "telnyx", - "twilio", - "plivo", - "mock" - ], + "enumValues": ["telnyx", "twilio", "plivo", "mock"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Provider", "help": "Use twilio, telnyx, or mock for dev/no-network.", "hasChildren": false @@ -47792,9 +43870,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Public Webhook URL", "hasChildren": false }, @@ -47805,9 +43881,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Response Model", "hasChildren": false }, @@ -47818,9 +43892,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Response System Prompt", "hasChildren": false }, @@ -47831,10 +43903,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "performance" - ], + "tags": ["advanced", "performance"], "label": "Response Timeout (ms)", "hasChildren": false }, @@ -47865,9 +43934,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Webhook Bind", "hasChildren": false }, @@ -47878,9 +43945,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Webhook Path", "hasChildren": false }, @@ -47891,9 +43956,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Webhook Port", "hasChildren": false }, @@ -47914,9 +43977,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Skip Signature Verification", "hasChildren": false }, @@ -47937,10 +43998,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Call Log Store Path", "hasChildren": false }, @@ -47961,9 +44019,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable Streaming", "hasChildren": false }, @@ -48004,11 +44060,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "advanced", - "auth", - "security" - ], + "tags": ["advanced", "auth", "security"], "label": "OpenAI Realtime API Key", "hasChildren": false }, @@ -48039,10 +44091,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Media Stream Path", "hasChildren": false }, @@ -48053,10 +44102,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], + "tags": ["advanced", "media"], "label": "Realtime STT Model", "hasChildren": false }, @@ -48065,9 +44111,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "openai-realtime" - ], + "enumValues": ["openai-realtime"], "deprecated": false, "sensitive": false, "tags": [], @@ -48108,9 +44152,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "openai" - ], + "enumValues": ["openai"], "deprecated": false, "sensitive": false, "tags": [], @@ -48131,16 +44173,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "off", - "serve", - "funnel" - ], + "enumValues": ["off", "serve", "funnel"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Tailscale Mode", "hasChildren": false }, @@ -48151,10 +44187,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "storage" - ], + "tags": ["advanced", "storage"], "label": "Tailscale Path", "hasChildren": false }, @@ -48175,10 +44208,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Telnyx API Key", "hasChildren": false }, @@ -48189,9 +44219,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Telnyx Connection ID", "hasChildren": false }, @@ -48202,9 +44230,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "security" - ], + "tags": ["security"], "label": "Telnyx Public Key", "hasChildren": false }, @@ -48215,9 +44241,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Default To Number", "hasChildren": false }, @@ -48246,12 +44270,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "off", - "always", - "inbound", - "tagged" - ], + "enumValues": ["off", "always", "inbound", "tagged"], "deprecated": false, "sensitive": false, "tags": [], @@ -48384,12 +44403,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "advanced", - "auth", - "media", - "security" - ], + "tags": ["advanced", "auth", "media", "security"], "label": "ElevenLabs API Key", "hasChildren": false }, @@ -48398,11 +44412,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "auto", - "on", - "off" - ], + "enumValues": ["auto", "on", "off"], "deprecated": false, "sensitive": false, "tags": [], @@ -48415,10 +44425,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], + "tags": ["advanced", "media"], "label": "ElevenLabs Base URL", "hasChildren": false }, @@ -48439,11 +44446,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], + "tags": ["advanced", "media", "models"], "label": "ElevenLabs Model ID", "hasChildren": false }, @@ -48464,10 +44467,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], + "tags": ["advanced", "media"], "label": "ElevenLabs Voice ID", "hasChildren": false }, @@ -48556,10 +44556,7 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "final", - "all" - ], + "enumValues": ["final", "all"], "deprecated": false, "sensitive": false, "tags": [], @@ -48672,12 +44669,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "advanced", - "auth", - "media", - "security" - ], + "tags": ["advanced", "auth", "media", "security"], "label": "OpenAI API Key", "hasChildren": false }, @@ -48708,11 +44700,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], + "tags": ["advanced", "media", "models"], "label": "OpenAI TTS Model", "hasChildren": false }, @@ -48733,10 +44721,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], + "tags": ["advanced", "media"], "label": "OpenAI TTS Voice", "hasChildren": false }, @@ -48755,17 +44740,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "openai", - "elevenlabs", - "edge" - ], + "enumValues": ["openai", "elevenlabs", "edge"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], + "tags": ["advanced", "media"], "label": "TTS Provider Override", "help": "Deep-merges with messages.tts (Edge is ignored for calls).", "hasChildren": false @@ -48807,10 +44785,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced" - ], + "tags": ["access", "advanced"], "label": "Allow ngrok Free Tier (Loopback Bypass)", "hasChildren": false }, @@ -48821,11 +44796,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "advanced", - "auth", - "security" - ], + "tags": ["advanced", "auth", "security"], "label": "ngrok Auth Token", "hasChildren": false }, @@ -48836,9 +44807,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "ngrok Domain", "hasChildren": false }, @@ -48847,17 +44816,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": [ - "none", - "ngrok", - "tailscale-serve", - "tailscale-funnel" - ], + "enumValues": ["none", "ngrok", "tailscale-serve", "tailscale-funnel"], "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Tunnel Provider", "hasChildren": false }, @@ -48878,9 +44840,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Twilio Account SID", "hasChildren": false }, @@ -48891,10 +44851,7 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "label": "Twilio Auth Token", "hasChildren": false }, @@ -48965,9 +44922,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/voice-call", "hasChildren": false }, @@ -48978,9 +44933,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -48992,9 +44945,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -49006,9 +44957,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/whatsapp", "help": "OpenClaw WhatsApp channel plugin (plugin: whatsapp)", "hasChildren": true @@ -49020,9 +44969,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/whatsapp Config", "help": "Plugin-defined config payload for whatsapp.", "hasChildren": false @@ -49034,9 +44981,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/whatsapp", "hasChildren": false }, @@ -49047,9 +44992,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -49061,9 +45004,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -49075,9 +45016,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/zalo", "help": "OpenClaw Zalo channel plugin (plugin: zalo)", "hasChildren": true @@ -49089,9 +45028,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/zalo Config", "help": "Plugin-defined config payload for zalo.", "hasChildren": false @@ -49103,9 +45040,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/zalo", "hasChildren": false }, @@ -49116,9 +45051,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -49130,9 +45063,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -49144,9 +45075,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/zalouser", "help": "OpenClaw Zalo Personal Account plugin via native zca-js integration (plugin: zalouser)", "hasChildren": true @@ -49158,9 +45087,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "@openclaw/zalouser Config", "help": "Plugin-defined config payload for zalouser.", "hasChildren": false @@ -49172,9 +45099,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Enable @openclaw/zalouser", "hasChildren": false }, @@ -49185,9 +45110,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -49199,9 +45122,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access" - ], + "tags": ["access"], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -49213,9 +45134,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Install Records", "help": "CLI-managed install metadata (used by `openclaw plugins update` to locate install sources).", "hasChildren": true @@ -49237,9 +45156,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Install Time", "help": "ISO timestamp of last install/update.", "hasChildren": false @@ -49251,9 +45168,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Plugin Install Path", "help": "Resolved install directory (usually ~/.openclaw/extensions/).", "hasChildren": false @@ -49265,9 +45180,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolved Integrity", "help": "Resolved npm dist integrity hash for the fetched artifact (if reported by npm).", "hasChildren": false @@ -49279,9 +45192,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolution Time", "help": "ISO timestamp when npm package metadata was last resolved for this install record.", "hasChildren": false @@ -49293,9 +45204,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolved Package Name", "help": "Resolved npm package name from the fetched artifact.", "hasChildren": false @@ -49307,9 +45216,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolved Package Spec", "help": "Resolved exact npm spec (@) from the fetched artifact.", "hasChildren": false @@ -49321,9 +45228,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolved Package Version", "help": "Resolved npm package version from the fetched artifact (useful for non-pinned specs).", "hasChildren": false @@ -49335,9 +45240,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Resolved Shasum", "help": "Resolved npm dist shasum for the fetched artifact (if reported by npm).", "hasChildren": false @@ -49349,9 +45252,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Install Source", "help": "Install source (\"npm\", \"archive\", or \"path\").", "hasChildren": false @@ -49363,9 +45264,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Plugin Install Source Path", "help": "Original archive/path used for install (if any).", "hasChildren": false @@ -49377,9 +45276,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Install Spec", "help": "Original npm spec used for install (if source is npm).", "hasChildren": false @@ -49391,9 +45288,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Install Version", "help": "Version recorded at install time (if available).", "hasChildren": false @@ -49405,9 +45300,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Loader", "help": "Plugin loader configuration group for specifying filesystem paths where plugins are discovered. Keep load paths explicit and reviewed to avoid accidental untrusted extension loading.", "hasChildren": true @@ -49419,9 +45312,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Plugin Load Paths", "help": "Additional plugin files or directories scanned by the loader beyond built-in defaults. Use dedicated extension directories and avoid broad paths with unrelated executable content.", "hasChildren": true @@ -49443,9 +45334,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Plugin Slots", "help": "Selects which plugins own exclusive runtime slots such as memory so only one plugin provides that capability. Use explicit slot ownership to avoid overlapping providers with conflicting behavior.", "hasChildren": true @@ -49457,9 +45346,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Context Engine Plugin", "help": "Selects the active context engine plugin by id so one plugin provides context orchestration behavior.", "hasChildren": false @@ -49471,9 +45358,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Memory Plugin", "help": "Select the active memory plugin by id, or \"none\" to disable memory plugins.", "hasChildren": false @@ -49805,9 +45690,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session", "help": "Global session routing, reset, delivery policy, and maintenance controls for conversation history behavior. Keep defaults unless you need stricter isolation, retention, or delivery constraints.", "hasChildren": true @@ -49819,9 +45702,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Agent-to-Agent", "help": "Groups controls for inter-agent session exchanges, including loop prevention limits on reply chaining. Keep defaults unless you run advanced agent-to-agent automation with strict turn caps.", "hasChildren": true @@ -49833,10 +45714,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Agent-to-Agent Ping-Pong Turns", "help": "Max reply-back turns between requester and target agents during agent-to-agent exchanges (0-5). Use lower values to hard-limit chatter loops and preserve predictable run completion.", "hasChildren": false @@ -49848,9 +45726,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "DM Session Scope", "help": "DM session scoping: \"main\" keeps continuity, while \"per-peer\", \"per-channel-peer\", and \"per-account-channel-peer\" increase isolation. Use isolated modes for shared inboxes or multi-account deployments.", "hasChildren": false @@ -49862,9 +45738,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Identity Links", "help": "Maps canonical identities to provider-prefixed peer IDs so equivalent users resolve to one DM thread (example: telegram:123456). Use this when the same human appears across multiple channels or accounts.", "hasChildren": true @@ -49896,9 +45770,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Idle Minutes", "help": "Applies a legacy idle reset window in minutes for session reuse behavior across inactivity gaps. Use this only for compatibility and prefer structured reset policies under session.reset/session.resetByType.", "hasChildren": false @@ -49910,9 +45782,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Main Key", "help": "Overrides the canonical main session key used for continuity when dmScope or routing logic points to \"main\". Use a stable value only if you intentionally need custom session anchoring.", "hasChildren": false @@ -49924,9 +45794,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Maintenance", "help": "Automatic session-store maintenance controls for pruning age, entry caps, and file rotation behavior. Start in warn mode to observe impact, then enforce once thresholds are tuned.", "hasChildren": true @@ -49934,16 +45802,11 @@ { "path": "session.maintenance.highWaterBytes", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Disk High-water Target", "help": "Target size after disk-budget cleanup (high-water mark). Defaults to 80% of maxDiskBytes; set explicitly for tighter reclaim behavior on constrained disks.", "hasChildren": false @@ -49951,17 +45814,11 @@ { "path": "session.maintenance.maxDiskBytes", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Session Max Disk Budget", "help": "Optional per-agent sessions-directory disk budget (for example `500mb`). Use this to cap session storage per agent; when exceeded, warn mode reports pressure and enforce mode performs oldest-first cleanup.", "hasChildren": false @@ -49973,10 +45830,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Session Max Entries", "help": "Caps total session entry count retained in the store to prevent unbounded growth over time. Use lower limits for constrained environments, or higher limits when longer history is required.", "hasChildren": false @@ -49986,15 +45840,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "enforce", - "warn" - ], + "enumValues": ["enforce", "warn"], "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Maintenance Mode", "help": "Determines whether maintenance policies are only reported (\"warn\") or actively applied (\"enforce\"). Keep \"warn\" during rollout and switch to \"enforce\" after validating safe thresholds.", "hasChildren": false @@ -50002,16 +45851,11 @@ { "path": "session.maintenance.pruneAfter", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Prune After", "help": "Removes entries older than this duration (for example `30d` or `12h`) during maintenance passes. Use this as the primary age-retention control and align it with data retention policy.", "hasChildren": false @@ -50023,9 +45867,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Prune Days (Deprecated)", "help": "Deprecated age-retention field kept for compatibility with legacy configs using day counts. Use session.maintenance.pruneAfter instead so duration syntax and behavior are consistent.", "hasChildren": false @@ -50033,17 +45875,11 @@ { "path": "session.maintenance.resetArchiveRetention", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset Archive Retention", "help": "Retention for reset transcript archives (`*.reset.`). Accepts a duration (for example `30d`), or `false` to disable cleanup. Defaults to pruneAfter so reset artifacts do not grow forever.", "hasChildren": false @@ -50051,16 +45887,11 @@ { "path": "session.maintenance.rotateBytes", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Rotate Size", "help": "Rotates the session store when file size exceeds a threshold such as `10mb` or `1gb`. Use this to bound single-file growth and keep backup/restore operations manageable.", "hasChildren": false @@ -50072,12 +45903,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "auth", - "performance", - "security", - "storage" - ], + "tags": ["auth", "performance", "security", "storage"], "label": "Session Parent Fork Max Tokens", "help": "Maximum parent-session token count allowed for thread/session inheritance forking. If the parent exceeds this, OpenClaw starts a fresh thread session instead of forking; set 0 to disable this protection.", "hasChildren": false @@ -50089,9 +45915,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset Policy", "help": "Defines the default reset policy object used when no type-specific or channel-specific override applies. Set this first, then layer resetByType or resetByChannel only where behavior must differ.", "hasChildren": true @@ -50103,9 +45927,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Daily Reset Hour", "help": "Sets local-hour boundary (0-23) for daily reset mode so sessions roll over at predictable times. Use with mode=daily and align to operator timezone expectations for human-readable behavior.", "hasChildren": false @@ -50117,9 +45939,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset Idle Minutes", "help": "Sets inactivity window before reset for idle mode and can also act as secondary guard with daily mode. Use larger values to preserve continuity or smaller values for fresher short-lived threads.", "hasChildren": false @@ -50131,9 +45951,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset Mode", "help": "Selects reset strategy: \"daily\" resets at a configured hour and \"idle\" resets after inactivity windows. Keep one clear mode per policy to avoid surprising context turnover patterns.", "hasChildren": false @@ -50145,9 +45963,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset by Channel", "help": "Provides channel-specific reset overrides keyed by provider/channel id for fine-grained behavior control. Use this only when one channel needs exceptional reset behavior beyond type-level policies.", "hasChildren": true @@ -50199,9 +46015,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset by Chat Type", "help": "Overrides reset behavior by chat type (direct, group, thread) when defaults are not sufficient. Use this when group/thread traffic needs different reset cadence than direct messages.", "hasChildren": true @@ -50213,9 +46027,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset (Direct)", "help": "Defines reset policy for direct chats and supersedes the base session.reset configuration for that type. Use this as the canonical direct-message override instead of the legacy dm alias.", "hasChildren": true @@ -50257,9 +46069,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset (DM Deprecated Alias)", "help": "Deprecated alias for direct reset behavior kept for backward compatibility with older configs. Use session.resetByType.direct instead so future tooling and validation remain consistent.", "hasChildren": true @@ -50301,9 +46111,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset (Group)", "help": "Defines reset policy for group chat sessions where continuity and noise patterns differ from DMs. Use shorter idle windows for busy groups if context drift becomes a problem.", "hasChildren": true @@ -50345,9 +46153,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset (Thread)", "help": "Defines reset policy for thread-scoped sessions, including focused channel thread workflows. Use this when thread sessions should expire faster or slower than other chat types.", "hasChildren": true @@ -50389,9 +46195,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Reset Triggers", "help": "Lists message triggers that force a session reset when matched in inbound content. Use sparingly for explicit reset phrases so context is not dropped unexpectedly during normal conversation.", "hasChildren": true @@ -50413,9 +46217,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Scope", "help": "Sets base session grouping strategy: \"per-sender\" isolates by sender and \"global\" shares one session per channel context. Keep \"per-sender\" for safer multi-user behavior unless deliberate shared context is required.", "hasChildren": false @@ -50427,10 +46229,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Policy", "help": "Controls cross-session send permissions using allow/deny rules evaluated against channel, chatType, and key prefixes. Use this to fence where session tools can deliver messages in complex environments.", "hasChildren": true @@ -50442,10 +46241,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Policy Default Action", "help": "Sets fallback action when no sendPolicy rule matches: \"allow\" or \"deny\". Keep \"allow\" for simpler setups, or choose \"deny\" when you require explicit allow rules for every destination.", "hasChildren": false @@ -50457,10 +46253,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Policy Rules", "help": "Ordered allow/deny rules evaluated before the default action, for example `{ action: \"deny\", match: { channel: \"discord\" } }`. Put most specific rules first so broad rules do not shadow exceptions.", "hasChildren": true @@ -50482,10 +46275,7 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Action", "help": "Defines rule decision as \"allow\" or \"deny\" when the corresponding match criteria are satisfied. Use deny-first ordering when enforcing strict boundaries with explicit allow exceptions.", "hasChildren": false @@ -50497,10 +46287,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Match", "help": "Defines optional rule match conditions that can combine channel, chatType, and key-prefix constraints. Keep matches narrow so policy intent stays readable and debugging remains straightforward.", "hasChildren": true @@ -50512,10 +46299,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Channel", "help": "Matches rule application to a specific channel/provider id (for example discord, telegram, slack). Use this when one channel should permit or deny delivery independently of others.", "hasChildren": false @@ -50527,10 +46311,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Chat Type", "help": "Matches rule application to chat type (direct, group, thread) so behavior varies by conversation form. Use this when DM and group destinations require different safety boundaries.", "hasChildren": false @@ -50542,10 +46323,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Key Prefix", "help": "Matches a normalized session-key prefix after internal key normalization steps in policy consumers. Use this for general prefix controls, and prefer rawKeyPrefix when exact full-key matching is required.", "hasChildren": false @@ -50557,10 +46335,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "storage" - ], + "tags": ["access", "storage"], "label": "Session Send Rule Raw Key Prefix", "help": "Matches the raw, unnormalized session-key prefix for exact full-key policy targeting. Use this when normalized keyPrefix is too broad and you need agent-prefixed or transport-specific precision.", "hasChildren": false @@ -50572,9 +46347,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Store Path", "help": "Sets the session storage file path used to persist session records across restarts. Use an explicit path only when you need custom disk layout, backup routing, or mounted-volume storage.", "hasChildren": false @@ -50586,9 +46359,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Thread Bindings", "help": "Shared defaults for thread-bound session routing behavior across providers that support thread focus workflows. Configure global defaults here and override per channel only when behavior differs.", "hasChildren": true @@ -50600,9 +46371,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Thread Binding Enabled", "help": "Global master switch for thread-bound session routing features and focused thread delivery behavior. Keep enabled for modern thread workflows unless you need to disable thread binding globally.", "hasChildren": false @@ -50614,9 +46383,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Thread Binding Idle Timeout (hours)", "help": "Default inactivity window in hours for thread-bound sessions across providers/channels (0 disables idle auto-unfocus). Default: 24.", "hasChildren": false @@ -50628,10 +46395,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for thread-bound sessions across providers/channels (0 disables hard cap). Default: 0.", "hasChildren": false @@ -50643,10 +46407,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage" - ], + "tags": ["performance", "storage"], "label": "Session Typing Interval (seconds)", "help": "Controls interval for repeated typing indicators while replies are being prepared in typing-capable channels. Increase to reduce chatty updates or decrease for more active typing feedback.", "hasChildren": false @@ -50658,9 +46419,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage" - ], + "tags": ["storage"], "label": "Session Typing Mode", "help": "Controls typing behavior timing: \"never\", \"instant\", \"thinking\", or \"message\" based emission points. Keep conservative modes in high-volume channels to avoid unnecessary typing noise.", "hasChildren": false @@ -50672,9 +46431,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Skills", "hasChildren": true }, @@ -50721,17 +46478,11 @@ { "path": "skills.entries.*.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security" - ], + "tags": ["auth", "security"], "hasChildren": true }, { @@ -50940,9 +46691,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Watch Skills", "help": "Enable filesystem watching for skill-definition changes so updates can be applied without full process restart. Keep enabled in development workflows and disable in immutable production images.", "hasChildren": false @@ -50954,10 +46703,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation", - "performance" - ], + "tags": ["automation", "performance"], "label": "Skills Watch Debounce (ms)", "help": "Debounce window in milliseconds for coalescing rapid skill file changes before reload logic runs. Increase to reduce reload churn on frequent writes, or lower for faster edit feedback.", "hasChildren": false @@ -50969,9 +46715,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Talk", "help": "Talk-mode voice synthesis settings for voice identity, model selection, output format, and interruption behavior. Use this section to tune human-facing voice UX while controlling latency and cost.", "hasChildren": true @@ -50979,18 +46723,11 @@ { "path": "talk.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "media", - "security" - ], + "tags": ["auth", "media", "security"], "label": "Talk API Key", "help": "Use this legacy ElevenLabs API key for Talk mode only during migration, and keep secrets in env-backed storage. Prefer talk.providers.elevenlabs.apiKey (fallback: ELEVENLABS_API_KEY).", "hasChildren": true @@ -51032,9 +46769,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Interrupt on Speech", "help": "If true (default), stop assistant speech when the user starts speaking in Talk mode. Keep enabled for conversational turn-taking.", "hasChildren": false @@ -51046,10 +46781,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models" - ], + "tags": ["media", "models"], "label": "Talk Model ID", "help": "Legacy ElevenLabs model ID for Talk mode (default: eleven_v3). Prefer talk.providers.elevenlabs.modelId.", "hasChildren": false @@ -51061,9 +46793,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Output Format", "help": "Use this legacy ElevenLabs output format for Talk mode (for example pcm_44100 or mp3_44100_128) only during migration. Prefer talk.providers.elevenlabs.outputFormat.", "hasChildren": false @@ -51075,9 +46805,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Active Provider", "help": "Active Talk provider id (for example \"elevenlabs\").", "hasChildren": false @@ -51089,9 +46817,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Provider Settings", "help": "Provider-specific Talk settings keyed by provider id. During migration, prefer this over legacy talk.* keys.", "hasChildren": true @@ -51118,18 +46844,11 @@ { "path": "talk.providers.*.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "media", - "security" - ], + "tags": ["auth", "media", "security"], "label": "Talk Provider API Key", "help": "Provider API key for Talk mode.", "hasChildren": true @@ -51171,10 +46890,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models" - ], + "tags": ["media", "models"], "label": "Talk Provider Model ID", "help": "Provider default model ID for Talk mode.", "hasChildren": false @@ -51186,9 +46902,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Provider Output Format", "help": "Provider default output format for Talk mode.", "hasChildren": false @@ -51200,9 +46914,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Provider Voice Aliases", "help": "Optional provider voice alias map for Talk directives.", "hasChildren": true @@ -51224,9 +46936,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Provider Voice ID", "help": "Provider default voice ID for Talk mode.", "hasChildren": false @@ -51238,10 +46948,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance" - ], + "tags": ["media", "performance"], "label": "Talk Silence Timeout (ms)", "help": "Milliseconds of user silence before Talk mode finalizes and sends the current transcript. Leave unset to keep the platform default pause window (700 ms on macOS and Android, 900 ms on iOS).", "hasChildren": false @@ -51253,9 +46960,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Voice Aliases", "help": "Use this legacy ElevenLabs voice alias map (for example {\"Clawd\":\"EXAVITQu4vr4xnSDxMaL\"}) only during migration. Prefer talk.providers.elevenlabs.voiceAliases.", "hasChildren": true @@ -51277,9 +46982,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media" - ], + "tags": ["media"], "label": "Talk Voice ID", "help": "Legacy ElevenLabs default voice ID for Talk mode. Prefer talk.providers.elevenlabs.voiceId.", "hasChildren": false @@ -51291,9 +46994,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Tools", "help": "Global tool access policy and capability configuration across web, exec, media, messaging, and elevated surfaces. Use this section to constrain risky capabilities before broad rollout.", "hasChildren": true @@ -51305,9 +47006,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Agent-to-Agent Tool Access", "help": "Policy for allowing agent-to-agent tool calls and constraining which target agents can be reached. Keep disabled or tightly scoped unless cross-agent orchestration is intentionally enabled.", "hasChildren": true @@ -51319,10 +47018,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Agent-to-Agent Target Allowlist", "help": "Allowlist of target agent IDs permitted for agent_to_agent calls when orchestration is enabled. Use explicit allowlists to avoid uncontrolled cross-agent call graphs.", "hasChildren": true @@ -51344,9 +47040,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Agent-to-Agent Tool", "help": "Enables the agent_to_agent tool surface so one agent can invoke another agent at runtime. Keep off in simple deployments and enable only when orchestration value outweighs complexity.", "hasChildren": false @@ -51358,10 +47052,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Tool Allowlist", "help": "Absolute tool allowlist that replaces profile-derived defaults for strict environments. Use this only when you intentionally run a tightly curated subset of tool capabilities.", "hasChildren": true @@ -51383,10 +47074,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Tool Allowlist Additions", "help": "Extra tool allowlist entries merged on top of the selected tool profile and default policy. Keep this list small and explicit so audits can quickly identify intentional policy exceptions.", "hasChildren": true @@ -51408,9 +47096,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool Policy by Provider", "help": "Per-provider tool allow/deny overrides keyed by channel/provider ID to tailor capabilities by surface. Use this when one provider needs stricter controls than global tool policy.", "hasChildren": true @@ -51502,10 +47188,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Tool Denylist", "help": "Global tool denylist that blocks listed tools even when profile or provider rules would allow them. Use deny rules for emergency lockouts and long-term defense-in-depth.", "hasChildren": true @@ -51527,9 +47210,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Elevated Tool Access", "help": "Elevated tool access controls for privileged command surfaces that should only be reachable from trusted senders. Keep disabled unless operator workflows explicitly require elevated actions.", "hasChildren": true @@ -51541,10 +47222,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Elevated Tool Allow Rules", "help": "Sender allow rules for elevated tools, usually keyed by channel/provider identity formats. Use narrow, explicit identities so elevated commands cannot be triggered by unintended users.", "hasChildren": true @@ -51562,10 +47240,7 @@ { "path": "tools.elevated.allowFrom.*.*", "kind": "core", - "type": [ - "number", - "string" - ], + "type": ["number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -51579,9 +47254,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Elevated Tool Access", "help": "Enables elevated tool execution path when sender and policy checks pass. Keep disabled in public/shared channels and enable only for trusted owner-operated contexts.", "hasChildren": false @@ -51593,9 +47266,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Tool", "help": "Exec-tool policy grouping for shell execution host, security mode, approval behavior, and runtime bindings. Keep conservative defaults in production and tighten elevated execution paths.", "hasChildren": true @@ -51617,10 +47288,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "apply_patch Model Allowlist", "help": "Optional allowlist of model ids (e.g. \"gpt-5.2\" or \"openai/gpt-5.2\").", "hasChildren": true @@ -51642,9 +47310,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable apply_patch", "help": "Experimental. Enables apply_patch for OpenAI models when allowed by tool policy.", "hasChildren": false @@ -51656,12 +47322,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "advanced", - "security", - "tools" - ], + "tags": ["access", "advanced", "security", "tools"], "label": "apply_patch Workspace-Only", "help": "Restrict apply_patch paths to the workspace directory (default: true). Set false to allow writing outside the workspace (dangerous).", "hasChildren": false @@ -51671,16 +47332,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "off", - "on-miss", - "always" - ], + "enumValues": ["off", "on-miss", "always"], "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Ask", "help": "Approval strategy for when exec commands require human confirmation before running. Use stricter ask behavior in shared channels and lower-friction settings in private operator contexts.", "hasChildren": false @@ -51710,16 +47365,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "sandbox", - "gateway", - "node" - ], + "enumValues": ["sandbox", "gateway", "node"], "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Host", "help": "Selects execution host strategy for shell commands, typically controlling local vs delegated execution environment. Use the safest host mode that still satisfies your automation requirements.", "hasChildren": false @@ -51731,9 +47380,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Node Binding", "help": "Node binding configuration for exec tooling when command execution is delegated through connected nodes. Use explicit node binding only when multi-node routing is required.", "hasChildren": false @@ -51745,9 +47392,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Notify On Exit", "help": "When true (default), backgrounded exec sessions on exit and node exec lifecycle events enqueue a system event and request a heartbeat.", "hasChildren": false @@ -51759,9 +47404,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Notify On Empty Success", "help": "When true, successful backgrounded exec exits with empty output still enqueue a completion system event (default: false).", "hasChildren": false @@ -51773,10 +47416,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Exec PATH Prepend", "help": "Directories to prepend to PATH for exec runs (gateway/sandbox).", "hasChildren": true @@ -51798,10 +47438,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Exec Safe Bin Profiles", "help": "Optional per-binary safe-bin profiles (positional limits + allowed/denied flags).", "hasChildren": true @@ -51883,9 +47520,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Safe Bins", "help": "Allow stdin-only safe binaries to run without explicit allowlist entries.", "hasChildren": true @@ -51907,10 +47542,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Exec Safe Bin Trusted Dirs", "help": "Additional explicit directories trusted for safe-bin path checks (PATH entries are never auto-trusted).", "hasChildren": true @@ -51930,16 +47562,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "deny", - "allowlist", - "full" - ], + "enumValues": ["deny", "allowlist", "full"], "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Exec Security", "help": "Execution security posture selector controlling sandbox/approval expectations for command execution. Keep strict security mode for untrusted prompts and relax only for trusted operator workflows.", "hasChildren": false @@ -51971,9 +47597,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Workspace-only FS tools", "help": "Restrict filesystem tools (read/write/edit/apply_patch) to the workspace directory (default: false).", "hasChildren": false @@ -51995,9 +47619,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Link Understanding", "help": "Enable automatic link understanding pre-processing so URLs can be summarized before agent reasoning. Keep enabled for richer context, and disable when strict minimal processing is required.", "hasChildren": false @@ -52009,10 +47631,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Link Understanding Max Links", "help": "Maximum number of links expanded per turn during link understanding. Use lower values to control latency/cost in chatty threads and higher values when multi-link context is critical.", "hasChildren": false @@ -52024,10 +47643,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "tools" - ], + "tags": ["models", "tools"], "label": "Link Understanding Models", "help": "Preferred model list for link understanding tasks, evaluated in order as fallbacks when supported. Use lightweight models first for routine summarization and heavier models only when needed.", "hasChildren": true @@ -52099,9 +47715,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Link Understanding Scope", "help": "Controls when link understanding runs relative to conversation context and message type. Keep scope conservative to avoid unnecessary fetches on messages where links are not actionable.", "hasChildren": true @@ -52203,10 +47817,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Link Understanding Timeout (sec)", "help": "Per-link understanding timeout budget in seconds before unresolved links are skipped. Keep this bounded to avoid long stalls when external sites are slow or unreachable.", "hasChildren": false @@ -52228,9 +47839,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Critical Threshold", "help": "Critical threshold for repetitive patterns when detector is enabled (default: 20).", "hasChildren": false @@ -52252,9 +47861,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Generic Repeat Detection", "help": "Enable generic repeated same-tool/same-params loop detection (default: true).", "hasChildren": false @@ -52266,9 +47873,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Poll No-Progress Detection", "help": "Enable known poll tool no-progress loop detection (default: true).", "hasChildren": false @@ -52280,9 +47885,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Ping-Pong Detection", "help": "Enable ping-pong loop detection (default: true).", "hasChildren": false @@ -52294,9 +47897,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Detection", "help": "Enable repetitive tool-call loop detection and backoff safety checks (default: false).", "hasChildren": false @@ -52308,10 +47909,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "reliability", - "tools" - ], + "tags": ["reliability", "tools"], "label": "Tool-loop Global Circuit Breaker Threshold", "help": "Global no-progress breaker threshold (default: 30).", "hasChildren": false @@ -52323,9 +47921,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop History Size", "help": "Tool history window size for loop detection (default: 30).", "hasChildren": false @@ -52337,9 +47933,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Tool-loop Warning Threshold", "help": "Warning threshold for repetitive patterns when detector is enabled (default: 10).", "hasChildren": false @@ -52371,10 +47965,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Audio Understanding Attachment Policy", "help": "Attachment policy for audio inputs indicating which uploaded files are eligible for audio processing. Keep restrictive defaults in mixed-content channels to avoid unintended audio workloads.", "hasChildren": true @@ -52466,10 +48057,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Transcript Echo Format", "help": "Format string for the echoed transcript message. Use `{transcript}` as a placeholder for the transcribed text. Default: '📝 \"{transcript}\"'.", "hasChildren": false @@ -52481,10 +48069,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Echo Transcript to Chat", "help": "Echo the audio transcript back to the originating chat before agent processing. When enabled, users immediately see what was heard from their voice note, helping them verify transcription accuracy before the agent acts on it. Default: false.", "hasChildren": false @@ -52496,10 +48081,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Enable Audio Understanding", "help": "Enable audio understanding so voice notes or audio clips can be transcribed/summarized for agent context. Disable when audio ingestion is outside policy or unnecessary for your workflows.", "hasChildren": false @@ -52531,10 +48113,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Audio Understanding Language", "help": "Preferred language hint for audio understanding/transcription when provider support is available. Set this to improve recognition accuracy for known primary languages.", "hasChildren": false @@ -52546,11 +48125,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Audio Understanding Max Bytes", "help": "Maximum accepted audio payload size in bytes before processing is rejected or clipped by policy. Set this based on expected recording length and upstream provider limits.", "hasChildren": false @@ -52562,11 +48137,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Audio Understanding Max Chars", "help": "Maximum characters retained from audio understanding output to prevent oversized transcript injection. Increase for long-form dictation, or lower to keep conversational turns compact.", "hasChildren": false @@ -52578,11 +48149,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models", - "tools" - ], + "tags": ["media", "models", "tools"], "label": "Audio Understanding Models", "help": "Ordered model preferences specifically for audio understanding, used before shared media model fallback. Choose models optimized for transcription quality in your primary language/domain.", "hasChildren": true @@ -52820,11 +48387,7 @@ { "path": "tools.media.audio.models.*.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -52858,10 +48421,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Audio Understanding Prompt", "help": "Instruction template guiding audio understanding output style, such as concise summary versus near-verbatim transcript. Keep wording consistent so downstream automations can rely on output format.", "hasChildren": false @@ -52889,11 +48449,7 @@ { "path": "tools.media.audio.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -52907,10 +48463,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Audio Understanding Scope", "help": "Scope selector for when audio understanding runs across inbound messages and attachments. Keep focused scopes in high-volume channels to reduce cost and avoid accidental transcription.", "hasChildren": true @@ -53012,11 +48565,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Audio Understanding Timeout (sec)", "help": "Timeout in seconds for audio understanding execution before the operation is cancelled. Use longer timeouts for long recordings and tighter ones for interactive chat responsiveness.", "hasChildren": false @@ -53028,11 +48577,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Media Understanding Concurrency", "help": "Maximum number of concurrent media understanding operations per turn across image, audio, and video tasks. Lower this in resource-constrained deployments to prevent CPU/network saturation.", "hasChildren": false @@ -53054,10 +48599,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Image Understanding Attachment Policy", "help": "Attachment handling policy for image inputs, including which message attachments qualify for image analysis. Use restrictive settings in untrusted channels to reduce unexpected processing.", "hasChildren": true @@ -53169,10 +48711,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Enable Image Understanding", "help": "Enable image understanding so attached or referenced images can be interpreted into textual context. Disable if you need text-only operation or want to avoid image-processing cost.", "hasChildren": false @@ -53214,11 +48753,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Image Understanding Max Bytes", "help": "Maximum accepted image payload size in bytes before the item is skipped or truncated by policy. Keep limits realistic for your provider caps and infrastructure bandwidth.", "hasChildren": false @@ -53230,11 +48765,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Image Understanding Max Chars", "help": "Maximum characters returned from image understanding output after model response normalization. Use tighter limits to reduce prompt bloat and larger limits for detail-heavy OCR tasks.", "hasChildren": false @@ -53246,11 +48777,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models", - "tools" - ], + "tags": ["media", "models", "tools"], "label": "Image Understanding Models", "help": "Ordered model preferences specifically for image understanding when you want to override shared media models. Put the most reliable multimodal model first to reduce fallback attempts.", "hasChildren": true @@ -53488,11 +49015,7 @@ { "path": "tools.media.image.models.*.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -53526,10 +49049,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Image Understanding Prompt", "help": "Instruction template used for image understanding requests to shape extraction style and detail level. Keep prompts deterministic so outputs stay consistent across turns and channels.", "hasChildren": false @@ -53557,11 +49077,7 @@ { "path": "tools.media.image.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -53575,10 +49091,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Image Understanding Scope", "help": "Scope selector for when image understanding is attempted (for example only explicit requests versus broader auto-detection). Keep narrow scope in busy channels to control token and API spend.", "hasChildren": true @@ -53680,11 +49193,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Image Understanding Timeout (sec)", "help": "Timeout in seconds for each image understanding request before it is aborted. Increase for high-resolution analysis and lower it for latency-sensitive operator workflows.", "hasChildren": false @@ -53696,11 +49205,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models", - "tools" - ], + "tags": ["media", "models", "tools"], "label": "Media Understanding Shared Models", "help": "Shared fallback model list used by media understanding tools when modality-specific model lists are not set. Keep this aligned with available multimodal providers to avoid runtime fallback churn.", "hasChildren": true @@ -53938,11 +49443,7 @@ { "path": "tools.media.models.*.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -53986,10 +49487,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Video Understanding Attachment Policy", "help": "Attachment eligibility policy for video analysis, defining which message files can trigger video processing. Keep this explicit in shared channels to prevent accidental large media workloads.", "hasChildren": true @@ -54101,10 +49599,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Enable Video Understanding", "help": "Enable video understanding so clips can be summarized into text for downstream reasoning and responses. Disable when processing video is out of policy or too expensive for your deployment.", "hasChildren": false @@ -54146,11 +49641,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Video Understanding Max Bytes", "help": "Maximum accepted video payload size in bytes before policy rejection or trimming occurs. Tune this to provider and infrastructure limits to avoid repeated timeout/failure loops.", "hasChildren": false @@ -54162,11 +49653,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Video Understanding Max Chars", "help": "Maximum characters retained from video understanding output to control prompt growth. Raise for dense scene descriptions and lower when concise summaries are preferred.", "hasChildren": false @@ -54178,11 +49665,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "models", - "tools" - ], + "tags": ["media", "models", "tools"], "label": "Video Understanding Models", "help": "Ordered model preferences specifically for video understanding before shared media fallback applies. Prioritize models with strong multimodal video support to minimize degraded summaries.", "hasChildren": true @@ -54420,11 +49903,7 @@ { "path": "tools.media.video.models.*.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -54458,10 +49937,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Video Understanding Prompt", "help": "Instruction template for video understanding describing desired summary granularity and focus areas. Keep this stable so output quality remains predictable across model/provider fallbacks.", "hasChildren": false @@ -54489,11 +49965,7 @@ { "path": "tools.media.video.providerOptions.*.*", "kind": "core", - "type": [ - "boolean", - "number", - "string" - ], + "type": ["boolean", "number", "string"], "required": false, "deprecated": false, "sensitive": false, @@ -54507,10 +49979,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "tools" - ], + "tags": ["media", "tools"], "label": "Video Understanding Scope", "help": "Scope selector controlling when video understanding is attempted across incoming events. Narrow scope in noisy channels, and broaden only where video interpretation is core to workflow.", "hasChildren": true @@ -54612,11 +50081,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "media", - "performance", - "tools" - ], + "tags": ["media", "performance", "tools"], "label": "Video Understanding Timeout (sec)", "help": "Timeout in seconds for each video understanding request before cancellation. Use conservative values in interactive channels and longer values for offline or batch-heavy processing.", "hasChildren": false @@ -54638,10 +50103,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Allow Cross-Context Messaging", "help": "Legacy override: allow cross-context sends across all providers.", "hasChildren": false @@ -54663,9 +50125,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Message Broadcast", "help": "Enable broadcast action (default: true).", "hasChildren": false @@ -54687,10 +50147,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Allow Cross-Context (Across Providers)", "help": "Allow sends across different providers (default: false).", "hasChildren": false @@ -54702,10 +50159,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "access", - "tools" - ], + "tags": ["access", "tools"], "label": "Allow Cross-Context (Same Provider)", "help": "Allow sends to other channels within the same provider (default: true).", "hasChildren": false @@ -54727,9 +50181,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Cross-Context Marker", "help": "Add a visible origin marker when sending cross-context (default: true).", "hasChildren": false @@ -54741,9 +50193,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Cross-Context Marker Prefix", "help": "Text prefix for cross-context markers (supports \"{channel}\").", "hasChildren": false @@ -54755,9 +50205,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Cross-Context Marker Suffix", "help": "Text suffix for cross-context markers (supports \"{channel}\").", "hasChildren": false @@ -54769,10 +50217,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Tool Profile", "help": "Global tool profile name used to select a predefined tool policy baseline before applying allow/deny overrides. Use this for consistent environment posture across agents and keep profile names stable.", "hasChildren": false @@ -54784,10 +50229,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Sandbox Tool Policy", "help": "Tool policy wrapper for sandboxed agent executions so sandbox runs can have distinct capability boundaries. Use this to enforce stronger safety in sandbox contexts.", "hasChildren": true @@ -54799,10 +50241,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Sandbox Tool Allow/Deny Policy", "help": "Allow/deny tool policy applied when agents run in sandboxed execution environments. Keep policies minimal so sandbox tasks cannot escalate into unnecessary external actions.", "hasChildren": true @@ -54952,18 +50391,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": [ - "self", - "tree", - "agent", - "all" - ], + "enumValues": ["self", "tree", "agent", "all"], "deprecated": false, "sensitive": false, - "tags": [ - "storage", - "tools" - ], + "tags": ["storage", "tools"], "label": "Session Tools Visibility", "help": "Controls which sessions can be targeted by sessions_list/sessions_history/sessions_send. (\"tree\" default = current session + spawned subagent sessions; \"self\" = only current; \"agent\" = any session in the current agent id; \"all\" = any session; cross-agent still requires tools.agentToAgent).", "hasChildren": false @@ -54975,9 +50406,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Subagent Tool Policy", "help": "Tool policy wrapper for spawned subagents to restrict or expand tool availability compared to parent defaults. Use this to keep delegated agent capabilities scoped to task intent.", "hasChildren": true @@ -54989,9 +50418,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Subagent Tool Allow/Deny Policy", "help": "Allow/deny tool policy applied to spawned subagent runtimes for per-subagent hardening. Keep this narrower than parent scope when subagents run semi-autonomous workflows.", "hasChildren": true @@ -55063,9 +50490,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Web Tools", "help": "Web-tool policy grouping for search/fetch providers, limits, and fallback behavior tuning. Keep enabled settings aligned with API key availability and outbound networking policy.", "hasChildren": true @@ -55087,11 +50512,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage", - "tools" - ], + "tags": ["performance", "storage", "tools"], "label": "Web Fetch Cache TTL (min)", "help": "Cache TTL in minutes for web_fetch results.", "hasChildren": false @@ -55103,9 +50524,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Web Fetch Tool", "help": "Enable the web_fetch tool (lightweight HTTP fetch).", "hasChildren": false @@ -55123,18 +50542,11 @@ { "path": "tools.web.fetch.firecrawl.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Firecrawl API Key", "help": "Firecrawl API key (fallback: FIRECRAWL_API_KEY env var).", "hasChildren": true @@ -55176,9 +50588,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Firecrawl Base URL", "help": "Firecrawl base URL (e.g. https://api.firecrawl.dev or custom endpoint).", "hasChildren": false @@ -55190,9 +50600,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Firecrawl Fallback", "help": "Enable Firecrawl fallback for web_fetch (if configured).", "hasChildren": false @@ -55204,10 +50612,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Firecrawl Cache Max Age (ms)", "help": "Firecrawl maxAge (ms) for cached results when supported by the API.", "hasChildren": false @@ -55219,9 +50624,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Firecrawl Main Content Only", "help": "When true, Firecrawl returns only the main content (default: true).", "hasChildren": false @@ -55233,10 +50636,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Firecrawl Timeout (sec)", "help": "Timeout in seconds for Firecrawl requests.", "hasChildren": false @@ -55248,10 +50648,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Web Fetch Max Chars", "help": "Max characters returned by web_fetch (truncated).", "hasChildren": false @@ -55263,10 +50660,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Web Fetch Hard Max Chars", "help": "Hard cap for web_fetch maxChars (applies to config and tool calls).", "hasChildren": false @@ -55278,11 +50672,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage", - "tools" - ], + "tags": ["performance", "storage", "tools"], "label": "Web Fetch Max Redirects", "help": "Maximum redirects allowed for web_fetch (default: 3).", "hasChildren": false @@ -55294,9 +50684,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Web Fetch Readability Extraction", "help": "Use Readability to extract main content from HTML (fallbacks to basic HTML cleanup).", "hasChildren": false @@ -55308,10 +50696,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Web Fetch Timeout (sec)", "help": "Timeout in seconds for web_fetch requests.", "hasChildren": false @@ -55323,9 +50708,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Web Fetch User-Agent", "help": "Override User-Agent header for web_fetch requests.", "hasChildren": false @@ -55343,18 +50726,11 @@ { "path": "tools.web.search.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Brave Search API Key", "help": "Brave Search API key (fallback: BRAVE_API_KEY env var).", "hasChildren": true @@ -55406,9 +50782,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Brave Search Mode", "help": "Brave Search mode: \"web\" (URL results) or \"llm-context\" (pre-extracted page content for LLM grounding).", "hasChildren": false @@ -55420,11 +50794,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "storage", - "tools" - ], + "tags": ["performance", "storage", "tools"], "label": "Web Search Cache TTL (min)", "help": "Cache TTL in minutes for web_search results.", "hasChildren": false @@ -55436,9 +50806,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Enable Web Search Tool", "help": "Enable the web_search tool (requires a provider API key).", "hasChildren": false @@ -55456,18 +50824,11 @@ { "path": "tools.web.search.gemini.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Gemini Search API Key", "help": "Gemini API key for Google Search grounding (fallback: GEMINI_API_KEY env var).", "hasChildren": true @@ -55509,10 +50870,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "tools" - ], + "tags": ["models", "tools"], "label": "Gemini Search Model", "help": "Gemini model override (default: \"gemini-2.5-flash\").", "hasChildren": false @@ -55530,18 +50888,11 @@ { "path": "tools.web.search.grok.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Grok Search API Key", "help": "Grok (xAI) API key (fallback: XAI_API_KEY env var).", "hasChildren": true @@ -55593,10 +50944,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "tools" - ], + "tags": ["models", "tools"], "label": "Grok Search Model", "help": "Grok model override (default: \"grok-4-1-fast\").", "hasChildren": false @@ -55614,18 +50962,11 @@ { "path": "tools.web.search.kimi.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Kimi Search API Key", "help": "Moonshot/Kimi API key (fallback: KIMI_API_KEY or MOONSHOT_API_KEY env var).", "hasChildren": true @@ -55667,9 +51008,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Kimi Search Base URL", "help": "Kimi base URL override (default: \"https://api.moonshot.ai/v1\").", "hasChildren": false @@ -55681,10 +51020,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "tools" - ], + "tags": ["models", "tools"], "label": "Kimi Search Model", "help": "Kimi model override (default: \"moonshot-v1-128k\").", "hasChildren": false @@ -55696,10 +51032,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Web Search Max Results", "help": "Number of results to return (1-10).", "hasChildren": false @@ -55717,18 +51050,11 @@ { "path": "tools.web.search.perplexity.apiKey", "kind": "core", - "type": [ - "object", - "string" - ], + "type": ["object", "string"], "required": false, "deprecated": false, "sensitive": true, - "tags": [ - "auth", - "security", - "tools" - ], + "tags": ["auth", "security", "tools"], "label": "Perplexity API Key", "help": "Perplexity or OpenRouter API key (fallback: PERPLEXITY_API_KEY or OPENROUTER_API_KEY env var). Direct Perplexity keys default to the Search API; OpenRouter keys use Sonar chat completions.", "hasChildren": true @@ -55770,9 +51096,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Perplexity Base URL", "help": "Optional Perplexity/OpenRouter chat-completions base URL override. Setting this opts Perplexity into the legacy Sonar/OpenRouter compatibility path.", "hasChildren": false @@ -55784,10 +51108,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "models", - "tools" - ], + "tags": ["models", "tools"], "label": "Perplexity Model", "help": "Optional Sonar/OpenRouter model override (default: \"perplexity/sonar-pro\"). Setting this opts Perplexity into the legacy chat-completions compatibility path.", "hasChildren": false @@ -55799,9 +51120,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "tools" - ], + "tags": ["tools"], "label": "Web Search Provider", "help": "Search provider (\"brave\", \"gemini\", \"grok\", \"kimi\", or \"perplexity\"). Auto-detected from available API keys if omitted.", "hasChildren": false @@ -55813,10 +51132,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance", - "tools" - ], + "tags": ["performance", "tools"], "label": "Web Search Timeout (sec)", "help": "Timeout in seconds for web_search requests.", "hasChildren": false @@ -55828,9 +51144,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "UI", "help": "UI presentation settings for accenting and assistant identity shown in control surfaces. Use this for branding and readability customization without changing runtime behavior.", "hasChildren": true @@ -55842,9 +51156,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Assistant Appearance", "help": "Assistant display identity settings for name and avatar shown in UI surfaces. Keep these values aligned with your operator-facing persona and support expectations.", "hasChildren": true @@ -55856,9 +51168,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Assistant Avatar", "help": "Assistant avatar image source used in UI surfaces (URL, path, or data URI depending on runtime support). Use trusted assets and consistent branding dimensions for clean rendering.", "hasChildren": false @@ -55870,9 +51180,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Assistant Name", "help": "Display name shown for the assistant in UI views, chat chrome, and status contexts. Keep this stable so operators can reliably identify which assistant persona is active.", "hasChildren": false @@ -55884,9 +51192,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Accent Color", "help": "Primary accent/seam color used by UI surfaces for emphasis, badges, and visual identity cues. Use high-contrast values that remain readable across light/dark themes.", "hasChildren": false @@ -55898,9 +51204,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Updates", "help": "Update-channel and startup-check behavior for keeping OpenClaw runtime versions current. Use conservative channels in production and more experimental channels only in controlled environments.", "hasChildren": true @@ -55922,9 +51226,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Auto Update Beta Check Interval (hours)", "help": "How often beta-channel checks run in hours (default: 1).", "hasChildren": false @@ -55936,9 +51238,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Auto Update Enabled", "help": "Enable background auto-update for package installs (default: false).", "hasChildren": false @@ -55950,9 +51250,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Auto Update Stable Delay (hours)", "help": "Minimum delay before stable-channel auto-apply starts (default: 6).", "hasChildren": false @@ -55964,9 +51262,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Auto Update Stable Jitter (hours)", "help": "Extra stable-channel rollout spread window in hours (default: 12).", "hasChildren": false @@ -55978,9 +51274,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Update Channel", "help": "Update channel for git + npm installs (\"stable\", \"beta\", or \"dev\").", "hasChildren": false @@ -55992,9 +51286,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Update Check on Start", "help": "Check for npm updates when the gateway starts (default: true).", "hasChildren": false @@ -56006,9 +51298,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Channel", "help": "Web channel runtime settings for heartbeat and reconnect behavior when operating web-based chat surfaces. Use reconnect values tuned to your network reliability profile and expected uptime needs.", "hasChildren": true @@ -56020,9 +51310,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Channel Enabled", "help": "Enables the web channel runtime and related websocket lifecycle behavior. Keep disabled when web chat is unused to reduce active connection management overhead.", "hasChildren": false @@ -56034,9 +51322,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "automation" - ], + "tags": ["automation"], "label": "Web Channel Heartbeat Interval (sec)", "help": "Heartbeat interval in seconds for web channel connectivity and liveness maintenance. Use shorter intervals for faster detection, or longer intervals to reduce keepalive chatter.", "hasChildren": false @@ -56048,9 +51334,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Channel Reconnect Policy", "help": "Reconnect backoff policy for web channel reconnect attempts after transport failure. Keep bounded retries and jitter tuned to avoid thundering-herd reconnect behavior.", "hasChildren": true @@ -56062,9 +51346,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Reconnect Backoff Factor", "help": "Exponential backoff multiplier used between reconnect attempts in web channel retry loops. Keep factor above 1 and tune with jitter for stable large-fleet reconnect behavior.", "hasChildren": false @@ -56076,9 +51358,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Reconnect Initial Delay (ms)", "help": "Initial reconnect delay in milliseconds before the first retry after disconnection. Use modest delays to recover quickly without immediate retry storms.", "hasChildren": false @@ -56090,9 +51370,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Web Reconnect Jitter", "help": "Randomization factor (0-1) applied to reconnect delays to desynchronize clients after outage events. Keep non-zero jitter in multi-client deployments to reduce synchronized spikes.", "hasChildren": false @@ -56104,9 +51382,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Web Reconnect Max Attempts", "help": "Maximum reconnect attempts before giving up for the current failure sequence (0 means no retries). Use finite caps for controlled failure handling in automation-sensitive environments.", "hasChildren": false @@ -56118,9 +51394,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "performance" - ], + "tags": ["performance"], "label": "Web Reconnect Max Delay (ms)", "help": "Maximum reconnect backoff cap in milliseconds to bound retry delay growth over repeated failures. Use a reasonable cap so recovery remains timely after prolonged outages.", "hasChildren": false @@ -56132,9 +51406,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Setup Wizard State", "help": "Setup wizard state tracking fields that record the most recent guided onboarding run details. Keep these fields for observability and troubleshooting of setup flows across upgrades.", "hasChildren": true @@ -56146,9 +51418,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Wizard Last Run Timestamp", "help": "ISO timestamp for when the setup wizard most recently completed on this host. Use this to confirm onboarding recency during support and operational audits.", "hasChildren": false @@ -56160,9 +51430,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Wizard Last Run Command", "help": "Command invocation recorded for the latest wizard run to preserve execution context. Use this to reproduce onboarding steps when verifying setup regressions.", "hasChildren": false @@ -56174,9 +51442,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Wizard Last Run Commit", "help": "Source commit identifier recorded for the last wizard execution in development builds. Use this to correlate onboarding behavior with exact source state during debugging.", "hasChildren": false @@ -56188,9 +51454,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Wizard Last Run Mode", "help": "Wizard execution mode recorded as \"local\" or \"remote\" for the most recent onboarding flow. Use this to understand whether setup targeted direct local runtime or remote gateway topology.", "hasChildren": false @@ -56202,9 +51466,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced" - ], + "tags": ["advanced"], "label": "Wizard Last Run Version", "help": "OpenClaw version recorded at the time of the most recent wizard run on this config. Use this when diagnosing behavior differences across version-to-version onboarding changes.", "hasChildren": false diff --git a/src/gateway/server.device-pair-approve-authz.test.ts b/src/gateway/server.device-pair-approve-authz.test.ts index 20c1d6d5959..9ed5ce0950d 100644 --- a/src/gateway/server.device-pair-approve-authz.test.ts +++ b/src/gateway/server.device-pair-approve-authz.test.ts @@ -63,11 +63,11 @@ async function issuePairingScopedOperator(name: string): Promise<{ role: "operator", scopes: ["operator.pairing"], }); - expect(rotated?.token).toBeTruthy(); + expect(rotated.ok ? rotated.entry.token : "").toBeTruthy(); return { identityPath: loaded.identityPath, deviceId: loaded.identity.deviceId, - token: String(rotated?.token ?? ""), + token: rotated.ok ? rotated.entry.token : "", }; } diff --git a/src/infra/device-pairing.ts b/src/infra/device-pairing.ts index b452e951bc8..e6cf9259a66 100644 --- a/src/infra/device-pairing.ts +++ b/src/infra/device-pairing.ts @@ -85,6 +85,11 @@ export type ApproveDevicePairingResult = | { status: "forbidden"; missingScope: string } | null; +type ApprovedDevicePairingResult = Extract< + NonNullable, + { status: "approved" } +>; + type DevicePairingStateFile = { pendingById: Record; pairedByDeviceId: Record; @@ -343,6 +348,15 @@ export async function requestDevicePairing( }); } +export async function approveDevicePairing( + requestId: string, + baseDir?: string, +): Promise; +export async function approveDevicePairing( + requestId: string, + options: { callerScopes?: readonly string[] }, + baseDir?: string, +): Promise; export async function approveDevicePairing( requestId: string, optionsOrBaseDir?: { callerScopes?: readonly string[] } | string, From dd2eb290384535f99af91f83816ac2b70e2cc575 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 12:11:55 -0700 Subject: [PATCH 02/16] Commands: split static onboard auth choice help (#47545) * Commands: split static onboard auth choice help * Tests: cover static onboard auth choice help * Changelog: note static onboard auth choice help --- CHANGELOG.md | 1 + src/cli/program/register.onboard.test.ts | 4 +- src/cli/program/register.onboard.ts | 4 +- src/commands/auth-choice-options.static.ts | 332 +++++++++++++++++++++ src/commands/auth-choice-options.test.ts | 21 ++ src/commands/auth-choice-options.ts | 331 +------------------- 6 files changed, 366 insertions(+), 327 deletions(-) create mode 100644 src/commands/auth-choice-options.static.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 65bee8da1aa..052510b8628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,6 +97,7 @@ Docs: https://docs.openclaw.ai - macOS/exec approvals: respect per-agent exec approval settings in the gateway prompter, including allowlist fallback when the native prompt cannot be shown, so gateway-triggered `system.run` requests follow configured policy instead of always prompting or denying unexpectedly. (#13707) Thanks @sliekens. - Telegram/media downloads: thread the same direct or proxy transport policy into SSRF-guarded file fetches so inbound attachments keep working when Telegram falls back between env-proxy and direct networking. (#44639) Thanks @obviyus. - Telegram/inbound media IPv4 fallback: retry SSRF-guarded Telegram file downloads once with the same IPv4 fallback policy as Bot API calls so fresh installs on IPv6-broken hosts no longer fail to download inbound images. +- Commands/onboarding: split static auth-choice help from the plugin-backed onboarding catalog so `openclaw onboard` registration no longer pulls provider-wizard imports just to describe `--auth-choice`. (#47545) Thanks @vincentkoc. - Windows/gateway install: bound `schtasks` calls and fall back to the Startup-folder login item when task creation hangs, so native `openclaw gateway install` fails fast instead of wedging forever on broken Scheduled Task setups. - Windows/gateway stop: resolve Startup-folder fallback listeners from the installed `gateway.cmd` port, so `openclaw gateway stop` now actually kills fallback-launched gateway processes before restart. - Windows/gateway status: reuse the installed service command environment when reading runtime status, so startup-fallback gateways keep reporting the configured port and running state in `gateway status --json` instead of falling back to `gateway port unknown`. diff --git a/src/cli/program/register.onboard.test.ts b/src/cli/program/register.onboard.test.ts index 53bc1dbc7a5..086296c8895 100644 --- a/src/cli/program/register.onboard.test.ts +++ b/src/cli/program/register.onboard.test.ts @@ -9,8 +9,8 @@ const runtime = { exit: vi.fn(), }; -vi.mock("../../commands/auth-choice-options.js", () => ({ - formatAuthChoiceChoicesForCli: () => "token|oauth", +vi.mock("../../commands/auth-choice-options.static.js", () => ({ + formatStaticAuthChoiceChoicesForCli: () => "token|oauth", })); vi.mock("../../commands/onboard-provider-auth-flags.js", () => ({ diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 4dd285e63c1..8c742f0ab66 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -1,5 +1,5 @@ import type { Command } from "commander"; -import { formatAuthChoiceChoicesForCli } from "../../commands/auth-choice-options.js"; +import { formatStaticAuthChoiceChoicesForCli } from "../../commands/auth-choice-options.static.js"; import type { GatewayDaemonRuntime } from "../../commands/daemon-runtime.js"; import { ONBOARD_PROVIDER_AUTH_FLAGS } from "../../commands/onboard-provider-auth-flags.js"; import type { @@ -41,7 +41,7 @@ function resolveInstallDaemonFlag( return undefined; } -const AUTH_CHOICE_HELP = formatAuthChoiceChoicesForCli({ +const AUTH_CHOICE_HELP = formatStaticAuthChoiceChoicesForCli({ includeLegacyAliases: true, includeSkip: true, }); diff --git a/src/commands/auth-choice-options.static.ts b/src/commands/auth-choice-options.static.ts new file mode 100644 index 00000000000..f42c208333f --- /dev/null +++ b/src/commands/auth-choice-options.static.ts @@ -0,0 +1,332 @@ +import { AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI } from "./auth-choice-legacy.js"; +import { ONBOARD_PROVIDER_AUTH_FLAGS } from "./onboard-provider-auth-flags.js"; +import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js"; + +export type { AuthChoiceGroupId }; + +export type AuthChoiceOption = { + value: AuthChoice; + label: string; + hint?: string; +}; +export type AuthChoiceGroup = { + value: AuthChoiceGroupId; + label: string; + hint?: string; + options: AuthChoiceOption[]; +}; + +export const AUTH_CHOICE_GROUP_DEFS: { + value: AuthChoiceGroupId; + label: string; + hint?: string; + choices: AuthChoice[]; +}[] = [ + { + value: "openai", + label: "OpenAI", + hint: "Codex OAuth + API key", + choices: ["openai-codex", "openai-api-key"], + }, + { + value: "anthropic", + label: "Anthropic", + hint: "setup-token + API key", + choices: ["token", "apiKey"], + }, + { + value: "chutes", + label: "Chutes", + hint: "OAuth", + choices: ["chutes"], + }, + { + value: "minimax", + label: "MiniMax", + hint: "M2.5 (recommended)", + choices: ["minimax-global-oauth", "minimax-global-api", "minimax-cn-oauth", "minimax-cn-api"], + }, + { + value: "moonshot", + label: "Moonshot AI (Kimi K2.5)", + hint: "Kimi K2.5 + Kimi Coding", + choices: ["moonshot-api-key", "moonshot-api-key-cn", "kimi-code-api-key"], + }, + { + value: "google", + label: "Google", + hint: "Gemini API key + OAuth", + choices: ["gemini-api-key", "google-gemini-cli"], + }, + { + value: "xai", + label: "xAI (Grok)", + hint: "API key", + choices: ["xai-api-key"], + }, + { + value: "mistral", + label: "Mistral AI", + hint: "API key", + choices: ["mistral-api-key"], + }, + { + value: "volcengine", + label: "Volcano Engine", + hint: "API key", + choices: ["volcengine-api-key"], + }, + { + value: "byteplus", + label: "BytePlus", + hint: "API key", + choices: ["byteplus-api-key"], + }, + { + value: "openrouter", + label: "OpenRouter", + hint: "API key", + choices: ["openrouter-api-key"], + }, + { + value: "kilocode", + label: "Kilo Gateway", + hint: "API key (OpenRouter-compatible)", + choices: ["kilocode-api-key"], + }, + { + value: "qwen", + label: "Qwen", + hint: "OAuth", + choices: ["qwen-portal"], + }, + { + value: "zai", + label: "Z.AI", + hint: "GLM Coding Plan / Global / CN", + choices: ["zai-coding-global", "zai-coding-cn", "zai-global", "zai-cn"], + }, + { + value: "qianfan", + label: "Qianfan", + hint: "API key", + choices: ["qianfan-api-key"], + }, + { + value: "modelstudio", + label: "Alibaba Cloud Model Studio", + hint: "Coding Plan API key (CN / Global)", + choices: ["modelstudio-api-key-cn", "modelstudio-api-key"], + }, + { + value: "copilot", + label: "Copilot", + hint: "GitHub + local proxy", + choices: ["github-copilot", "copilot-proxy"], + }, + { + value: "ai-gateway", + label: "Vercel AI Gateway", + hint: "API key", + choices: ["ai-gateway-api-key"], + }, + { + value: "opencode", + label: "OpenCode", + hint: "Shared API key for Zen + Go catalogs", + choices: ["opencode-zen", "opencode-go"], + }, + { + value: "xiaomi", + label: "Xiaomi", + hint: "API key", + choices: ["xiaomi-api-key"], + }, + { + value: "synthetic", + label: "Synthetic", + hint: "Anthropic-compatible (multi-model)", + choices: ["synthetic-api-key"], + }, + { + value: "together", + label: "Together AI", + hint: "API key", + choices: ["together-api-key"], + }, + { + value: "huggingface", + label: "Hugging Face", + hint: "Inference API (HF token)", + choices: ["huggingface-api-key"], + }, + { + value: "venice", + label: "Venice AI", + hint: "Privacy-focused (uncensored models)", + choices: ["venice-api-key"], + }, + { + value: "litellm", + label: "LiteLLM", + hint: "Unified LLM gateway (100+ providers)", + choices: ["litellm-api-key"], + }, + { + value: "cloudflare-ai-gateway", + label: "Cloudflare AI Gateway", + hint: "Account ID + Gateway ID + API key", + choices: ["cloudflare-ai-gateway-api-key"], + }, + { + value: "custom", + label: "Custom Provider", + hint: "Any OpenAI or Anthropic compatible endpoint", + choices: ["custom-api-key"], + }, +]; + +const PROVIDER_AUTH_CHOICE_OPTION_HINTS: Partial> = { + "litellm-api-key": "Unified gateway for 100+ LLM providers", + "cloudflare-ai-gateway-api-key": "Account ID + Gateway ID + API key", + "venice-api-key": "Privacy-focused inference (uncensored models)", + "together-api-key": "Access to Llama, DeepSeek, Qwen, and more open models", + "huggingface-api-key": "Inference Providers — OpenAI-compatible chat", + "opencode-zen": "Shared OpenCode key; curated Zen catalog", + "opencode-go": "Shared OpenCode key; Kimi/GLM/MiniMax Go catalog", +}; + +const PROVIDER_AUTH_CHOICE_OPTION_LABELS: Partial> = { + "moonshot-api-key": "Kimi API key (.ai)", + "moonshot-api-key-cn": "Kimi API key (.cn)", + "kimi-code-api-key": "Kimi Code API key (subscription)", + "cloudflare-ai-gateway-api-key": "Cloudflare AI Gateway", + "opencode-zen": "OpenCode Zen catalog", + "opencode-go": "OpenCode Go catalog", +}; + +function buildProviderAuthChoiceOptions(): AuthChoiceOption[] { + return ONBOARD_PROVIDER_AUTH_FLAGS.map((flag) => ({ + value: flag.authChoice, + label: PROVIDER_AUTH_CHOICE_OPTION_LABELS[flag.authChoice] ?? flag.description, + ...(PROVIDER_AUTH_CHOICE_OPTION_HINTS[flag.authChoice] + ? { hint: PROVIDER_AUTH_CHOICE_OPTION_HINTS[flag.authChoice] } + : {}), + })); +} + +export const BASE_AUTH_CHOICE_OPTIONS: ReadonlyArray = [ + { + value: "token", + label: "Anthropic token (paste setup-token)", + hint: "run `claude setup-token` elsewhere, then paste the token here", + }, + { + value: "openai-codex", + label: "OpenAI Codex (ChatGPT OAuth)", + }, + { value: "chutes", label: "Chutes (OAuth)" }, + ...buildProviderAuthChoiceOptions(), + { + value: "moonshot-api-key-cn", + label: "Kimi API key (.cn)", + }, + { + value: "github-copilot", + label: "GitHub Copilot (GitHub device login)", + hint: "Uses GitHub device flow", + }, + { value: "gemini-api-key", label: "Google Gemini API key" }, + { + value: "google-gemini-cli", + label: "Google Gemini CLI OAuth", + hint: "Unofficial flow; review account-risk warning before use", + }, + { value: "zai-api-key", label: "Z.AI API key" }, + { + value: "zai-coding-global", + label: "Coding-Plan-Global", + hint: "GLM Coding Plan Global (api.z.ai)", + }, + { + value: "zai-coding-cn", + label: "Coding-Plan-CN", + hint: "GLM Coding Plan CN (open.bigmodel.cn)", + }, + { + value: "zai-global", + label: "Global", + hint: "Z.AI Global (api.z.ai)", + }, + { + value: "zai-cn", + label: "CN", + hint: "Z.AI CN (open.bigmodel.cn)", + }, + { + value: "xiaomi-api-key", + label: "Xiaomi API key", + }, + { + value: "minimax-global-oauth", + label: "MiniMax Global — OAuth (minimax.io)", + hint: "Only supports OAuth for the coding plan", + }, + { + value: "minimax-global-api", + label: "MiniMax Global — API Key (minimax.io)", + hint: "sk-api- or sk-cp- keys supported", + }, + { + value: "minimax-cn-oauth", + label: "MiniMax CN — OAuth (minimaxi.com)", + hint: "Only supports OAuth for the coding plan", + }, + { + value: "minimax-cn-api", + label: "MiniMax CN — API Key (minimaxi.com)", + hint: "sk-api- or sk-cp- keys supported", + }, + { value: "qwen-portal", label: "Qwen OAuth" }, + { + value: "copilot-proxy", + label: "Copilot Proxy (local)", + hint: "Local proxy for VS Code Copilot models", + }, + { value: "apiKey", label: "Anthropic API key" }, + { + value: "opencode-zen", + label: "OpenCode Zen catalog", + hint: "Claude, GPT, Gemini via opencode.ai/zen", + }, + { value: "qianfan-api-key", label: "Qianfan API key" }, + { + value: "modelstudio-api-key-cn", + label: "Coding Plan API Key for China (subscription)", + hint: "Endpoint: coding.dashscope.aliyuncs.com", + }, + { + value: "modelstudio-api-key", + label: "Coding Plan API Key for Global/Intl (subscription)", + hint: "Endpoint: coding-intl.dashscope.aliyuncs.com", + }, + { value: "custom-api-key", label: "Custom Provider" }, +]; + +export function formatStaticAuthChoiceChoicesForCli(params?: { + includeSkip?: boolean; + includeLegacyAliases?: boolean; +}): string { + const includeSkip = params?.includeSkip ?? true; + const includeLegacyAliases = params?.includeLegacyAliases ?? false; + const values = BASE_AUTH_CHOICE_OPTIONS.map((opt) => opt.value); + + if (includeSkip) { + values.push("skip"); + } + if (includeLegacyAliases) { + values.push(...AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI); + } + + return values.join("|"); +} diff --git a/src/commands/auth-choice-options.test.ts b/src/commands/auth-choice-options.test.ts index 74b729d5db8..c45297a001e 100644 --- a/src/commands/auth-choice-options.test.ts +++ b/src/commands/auth-choice-options.test.ts @@ -6,6 +6,7 @@ import { buildAuthChoiceOptions, formatAuthChoiceChoicesForCli, } from "./auth-choice-options.js"; +import { formatStaticAuthChoiceChoicesForCli } from "./auth-choice-options.static.js"; const resolveProviderWizardOptions = vi.hoisted(() => vi.fn<() => ProviderWizardOption[]>(() => []), @@ -104,6 +105,26 @@ describe("buildAuthChoiceOptions", () => { expect(cliChoices).toContain("codex-cli"); }); + it("keeps static cli help choices off the plugin-backed catalog", () => { + resolveProviderWizardOptions.mockReturnValue([ + { + value: "ollama", + label: "Ollama", + hint: "Cloud and local open models", + groupId: "ollama", + groupLabel: "Ollama", + }, + ]); + + const cliChoices = formatStaticAuthChoiceChoicesForCli({ + includeLegacyAliases: false, + includeSkip: true, + }).split("|"); + + expect(cliChoices).not.toContain("ollama"); + expect(cliChoices).toContain("skip"); + }); + it("shows Chutes in grouped provider selection", () => { const { groups } = buildAuthChoiceGroups({ store: EMPTY_STORE, diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index 95bb74d1c14..3e97a103aad 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -1,321 +1,15 @@ import type { AuthProfileStore } from "../agents/auth-profiles.js"; import type { OpenClawConfig } from "../config/config.js"; import { resolveProviderWizardOptions } from "../plugins/provider-wizard.js"; -import { AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI } from "./auth-choice-legacy.js"; -import { ONBOARD_PROVIDER_AUTH_FLAGS } from "./onboard-provider-auth-flags.js"; +import { + AUTH_CHOICE_GROUP_DEFS, + BASE_AUTH_CHOICE_OPTIONS, + type AuthChoiceGroup, + type AuthChoiceOption, + formatStaticAuthChoiceChoicesForCli, +} from "./auth-choice-options.static.js"; import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js"; -export type { AuthChoiceGroupId }; - -export type AuthChoiceOption = { - value: AuthChoice; - label: string; - hint?: string; -}; -export type AuthChoiceGroup = { - value: AuthChoiceGroupId; - label: string; - hint?: string; - options: AuthChoiceOption[]; -}; - -const AUTH_CHOICE_GROUP_DEFS: { - value: AuthChoiceGroupId; - label: string; - hint?: string; - choices: AuthChoice[]; -}[] = [ - { - value: "openai", - label: "OpenAI", - hint: "Codex OAuth + API key", - choices: ["openai-codex", "openai-api-key"], - }, - { - value: "anthropic", - label: "Anthropic", - hint: "setup-token + API key", - choices: ["token", "apiKey"], - }, - { - value: "chutes", - label: "Chutes", - hint: "OAuth", - choices: ["chutes"], - }, - { - value: "minimax", - label: "MiniMax", - hint: "M2.5 (recommended)", - choices: ["minimax-global-oauth", "minimax-global-api", "minimax-cn-oauth", "minimax-cn-api"], - }, - { - value: "moonshot", - label: "Moonshot AI (Kimi K2.5)", - hint: "Kimi K2.5 + Kimi Coding", - choices: ["moonshot-api-key", "moonshot-api-key-cn", "kimi-code-api-key"], - }, - { - value: "google", - label: "Google", - hint: "Gemini API key + OAuth", - choices: ["gemini-api-key", "google-gemini-cli"], - }, - { - value: "xai", - label: "xAI (Grok)", - hint: "API key", - choices: ["xai-api-key"], - }, - { - value: "mistral", - label: "Mistral AI", - hint: "API key", - choices: ["mistral-api-key"], - }, - { - value: "volcengine", - label: "Volcano Engine", - hint: "API key", - choices: ["volcengine-api-key"], - }, - { - value: "byteplus", - label: "BytePlus", - hint: "API key", - choices: ["byteplus-api-key"], - }, - { - value: "openrouter", - label: "OpenRouter", - hint: "API key", - choices: ["openrouter-api-key"], - }, - { - value: "kilocode", - label: "Kilo Gateway", - hint: "API key (OpenRouter-compatible)", - choices: ["kilocode-api-key"], - }, - { - value: "qwen", - label: "Qwen", - hint: "OAuth", - choices: ["qwen-portal"], - }, - { - value: "zai", - label: "Z.AI", - hint: "GLM Coding Plan / Global / CN", - choices: ["zai-coding-global", "zai-coding-cn", "zai-global", "zai-cn"], - }, - { - value: "qianfan", - label: "Qianfan", - hint: "API key", - choices: ["qianfan-api-key"], - }, - { - value: "modelstudio", - label: "Alibaba Cloud Model Studio", - hint: "Coding Plan API key (CN / Global)", - choices: ["modelstudio-api-key-cn", "modelstudio-api-key"], - }, - { - value: "copilot", - label: "Copilot", - hint: "GitHub + local proxy", - choices: ["github-copilot", "copilot-proxy"], - }, - { - value: "ai-gateway", - label: "Vercel AI Gateway", - hint: "API key", - choices: ["ai-gateway-api-key"], - }, - { - value: "opencode", - label: "OpenCode", - hint: "Shared API key for Zen + Go catalogs", - choices: ["opencode-zen", "opencode-go"], - }, - { - value: "xiaomi", - label: "Xiaomi", - hint: "API key", - choices: ["xiaomi-api-key"], - }, - { - value: "synthetic", - label: "Synthetic", - hint: "Anthropic-compatible (multi-model)", - choices: ["synthetic-api-key"], - }, - { - value: "together", - label: "Together AI", - hint: "API key", - choices: ["together-api-key"], - }, - { - value: "huggingface", - label: "Hugging Face", - hint: "Inference API (HF token)", - choices: ["huggingface-api-key"], - }, - { - value: "venice", - label: "Venice AI", - hint: "Privacy-focused (uncensored models)", - choices: ["venice-api-key"], - }, - { - value: "litellm", - label: "LiteLLM", - hint: "Unified LLM gateway (100+ providers)", - choices: ["litellm-api-key"], - }, - { - value: "cloudflare-ai-gateway", - label: "Cloudflare AI Gateway", - hint: "Account ID + Gateway ID + API key", - choices: ["cloudflare-ai-gateway-api-key"], - }, - { - value: "custom", - label: "Custom Provider", - hint: "Any OpenAI or Anthropic compatible endpoint", - choices: ["custom-api-key"], - }, -]; - -const PROVIDER_AUTH_CHOICE_OPTION_HINTS: Partial> = { - "litellm-api-key": "Unified gateway for 100+ LLM providers", - "cloudflare-ai-gateway-api-key": "Account ID + Gateway ID + API key", - "venice-api-key": "Privacy-focused inference (uncensored models)", - "together-api-key": "Access to Llama, DeepSeek, Qwen, and more open models", - "huggingface-api-key": "Inference Providers — OpenAI-compatible chat", - "opencode-zen": "Shared OpenCode key; curated Zen catalog", - "opencode-go": "Shared OpenCode key; Kimi/GLM/MiniMax Go catalog", -}; - -const PROVIDER_AUTH_CHOICE_OPTION_LABELS: Partial> = { - "moonshot-api-key": "Kimi API key (.ai)", - "moonshot-api-key-cn": "Kimi API key (.cn)", - "kimi-code-api-key": "Kimi Code API key (subscription)", - "cloudflare-ai-gateway-api-key": "Cloudflare AI Gateway", - "opencode-zen": "OpenCode Zen catalog", - "opencode-go": "OpenCode Go catalog", -}; - -function buildProviderAuthChoiceOptions(): AuthChoiceOption[] { - return ONBOARD_PROVIDER_AUTH_FLAGS.map((flag) => ({ - value: flag.authChoice, - label: PROVIDER_AUTH_CHOICE_OPTION_LABELS[flag.authChoice] ?? flag.description, - ...(PROVIDER_AUTH_CHOICE_OPTION_HINTS[flag.authChoice] - ? { hint: PROVIDER_AUTH_CHOICE_OPTION_HINTS[flag.authChoice] } - : {}), - })); -} - -const BASE_AUTH_CHOICE_OPTIONS: ReadonlyArray = [ - { - value: "token", - label: "Anthropic token (paste setup-token)", - hint: "run `claude setup-token` elsewhere, then paste the token here", - }, - { - value: "openai-codex", - label: "OpenAI Codex (ChatGPT OAuth)", - }, - { value: "chutes", label: "Chutes (OAuth)" }, - ...buildProviderAuthChoiceOptions(), - { - value: "moonshot-api-key-cn", - label: "Kimi API key (.cn)", - }, - { - value: "github-copilot", - label: "GitHub Copilot (GitHub device login)", - hint: "Uses GitHub device flow", - }, - { value: "gemini-api-key", label: "Google Gemini API key" }, - { - value: "google-gemini-cli", - label: "Google Gemini CLI OAuth", - hint: "Unofficial flow; review account-risk warning before use", - }, - { value: "zai-api-key", label: "Z.AI API key" }, - { - value: "zai-coding-global", - label: "Coding-Plan-Global", - hint: "GLM Coding Plan Global (api.z.ai)", - }, - { - value: "zai-coding-cn", - label: "Coding-Plan-CN", - hint: "GLM Coding Plan CN (open.bigmodel.cn)", - }, - { - value: "zai-global", - label: "Global", - hint: "Z.AI Global (api.z.ai)", - }, - { - value: "zai-cn", - label: "CN", - hint: "Z.AI CN (open.bigmodel.cn)", - }, - { - value: "xiaomi-api-key", - label: "Xiaomi API key", - }, - { - value: "minimax-global-oauth", - label: "MiniMax Global — OAuth (minimax.io)", - hint: "Only supports OAuth for the coding plan", - }, - { - value: "minimax-global-api", - label: "MiniMax Global — API Key (minimax.io)", - hint: "sk-api- or sk-cp- keys supported", - }, - { - value: "minimax-cn-oauth", - label: "MiniMax CN — OAuth (minimaxi.com)", - hint: "Only supports OAuth for the coding plan", - }, - { - value: "minimax-cn-api", - label: "MiniMax CN — API Key (minimaxi.com)", - hint: "sk-api- or sk-cp- keys supported", - }, - { value: "qwen-portal", label: "Qwen OAuth" }, - { - value: "copilot-proxy", - label: "Copilot Proxy (local)", - hint: "Local proxy for VS Code Copilot models", - }, - { value: "apiKey", label: "Anthropic API key" }, - { - value: "opencode-zen", - label: "OpenCode Zen catalog", - hint: "Claude, GPT, Gemini via opencode.ai/zen", - }, - { value: "qianfan-api-key", label: "Qianfan API key" }, - { - value: "modelstudio-api-key-cn", - label: "Coding Plan API Key for China (subscription)", - hint: "Endpoint: coding.dashscope.aliyuncs.com", - }, - { - value: "modelstudio-api-key", - label: "Coding Plan API Key for Global/Intl (subscription)", - hint: "Endpoint: coding-intl.dashscope.aliyuncs.com", - }, - { value: "custom-api-key", label: "Custom Provider" }, -]; - function resolveDynamicProviderCliChoices(params?: { config?: OpenClawConfig; workspaceDir?: string; @@ -331,20 +25,11 @@ export function formatAuthChoiceChoicesForCli(params?: { workspaceDir?: string; env?: NodeJS.ProcessEnv; }): string { - const includeSkip = params?.includeSkip ?? true; - const includeLegacyAliases = params?.includeLegacyAliases ?? false; const values = [ - ...BASE_AUTH_CHOICE_OPTIONS.map((opt) => opt.value), + ...formatStaticAuthChoiceChoicesForCli(params).split("|"), ...resolveDynamicProviderCliChoices(params), ]; - if (includeSkip) { - values.push("skip"); - } - if (includeLegacyAliases) { - values.push(...AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI); - } - return values.join("|"); } From bbb0c3e5d7d9acab512d70abceafdba11d7ff490 Mon Sep 17 00:00:00 2001 From: xiaoyi Date: Mon, 16 Mar 2026 03:14:30 +0800 Subject: [PATCH 03/16] CLI/completion: fix generator OOM and harden plugin registries (#45537) * fix: avoid OOM during completion script generation * CLI/completion: fix PowerShell nested command paths * CLI/completion: cover generated shell scripts * Changelog: note completion generator follow-up * Plugins: reserve shared registry names --------- Co-authored-by: Xiaoyi Co-authored-by: Vincent Koc --- CHANGELOG.md | 1 + src/cli/completion-cli.test.ts | 52 ++++++++++++ src/cli/completion-cli.ts | 136 +++++++++++++++--------------- src/plugins/loader.test.ts | 147 +++++++++++++++++++++++++++++++++ src/plugins/registry.ts | 42 ++++++++++ 5 files changed, 307 insertions(+), 71 deletions(-) create mode 100644 src/cli/completion-cli.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 052510b8628..ebbfb3f0924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Docs: https://docs.openclaw.ai - CLI/startup: lazy-load channel add and root help startup paths to trim avoidable RSS and help latency on constrained hosts. (#46784) Thanks @vincentkoc. - CLI/onboarding: import static provider definitions directly for onboarding model/config helpers so those paths no longer pull provider discovery just for built-in defaults. (#47467) Thanks @vincentkoc. - CLI/auth choice: lazy-load plugin/provider fallback resolution so mapped auth choices stay on the static path and only unknown choices pay the heavy provider load. (#47495) Thanks @vincentkoc. +- CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc. ## 2026.3.13 diff --git a/src/cli/completion-cli.test.ts b/src/cli/completion-cli.test.ts new file mode 100644 index 00000000000..d2f34b0e8cb --- /dev/null +++ b/src/cli/completion-cli.test.ts @@ -0,0 +1,52 @@ +import { Command } from "commander"; +import { describe, expect, it } from "vitest"; +import { getCompletionScript } from "./completion-cli.js"; + +function createCompletionProgram(): Command { + const program = new Command(); + program.name("openclaw"); + program.description("CLI root"); + program.option("-v, --verbose", "Verbose output"); + + const gateway = program.command("gateway").description("Gateway commands"); + gateway.option("--force", "Force the action"); + + gateway.command("status").description("Show gateway status").option("--json", "JSON output"); + gateway.command("restart").description("Restart gateway"); + + return program; +} + +describe("completion-cli", () => { + it("generates zsh functions for nested subcommands", () => { + const script = getCompletionScript("zsh", createCompletionProgram()); + + expect(script).toContain("_openclaw_gateway()"); + expect(script).toContain("(status) _openclaw_gateway_status ;;"); + expect(script).toContain("(restart) _openclaw_gateway_restart ;;"); + expect(script).toContain("--force[Force the action]"); + }); + + it("generates PowerShell command paths without the executable prefix", () => { + const script = getCompletionScript("powershell", createCompletionProgram()); + + expect(script).toContain("if ($commandPath -eq 'gateway') {"); + expect(script).toContain("if ($commandPath -eq 'gateway status') {"); + expect(script).not.toContain("if ($commandPath -eq 'openclaw gateway') {"); + expect(script).toContain("$completions = @('status','restart','--force')"); + }); + + it("generates fish completions for root and nested command contexts", () => { + const script = getCompletionScript("fish", createCompletionProgram()); + + expect(script).toContain( + 'complete -c openclaw -n "__fish_use_subcommand" -a "gateway" -d \'Gateway commands\'', + ); + expect(script).toContain( + 'complete -c openclaw -n "__fish_seen_subcommand_from gateway" -a "status" -d \'Show gateway status\'', + ); + expect(script).toContain( + "complete -c openclaw -n \"__fish_seen_subcommand_from gateway\" -l force -d 'Force the action'", + ); + }); +}); diff --git a/src/cli/completion-cli.ts b/src/cli/completion-cli.ts index 01cd02c018c..cbc235e41f9 100644 --- a/src/cli/completion-cli.ts +++ b/src/cli/completion-cli.ts @@ -69,7 +69,7 @@ export async function completionCacheExists( return pathExists(cachePath); } -function getCompletionScript(shell: CompletionShell, program: Command): string { +export function getCompletionScript(shell: CompletionShell, program: Command): string { if (shell === "zsh") { return generateZshCompletion(program); } @@ -442,17 +442,19 @@ function generateZshSubcmdList(cmd: Command): string { } function generateZshSubcommands(program: Command, prefix: string): string { - let script = ""; - for (const cmd of program.commands) { - const cmdName = cmd.name(); - const funcName = `_${prefix}_${cmdName.replace(/-/g, "_")}`; + const segments: string[] = []; - // Recurse first - script += generateZshSubcommands(cmd, `${prefix}_${cmdName.replace(/-/g, "_")}`); + const visit = (current: Command, currentPrefix: string) => { + for (const cmd of current.commands) { + const cmdName = cmd.name(); + const nextPrefix = `${currentPrefix}_${cmdName.replace(/-/g, "_")}`; + const funcName = `_${nextPrefix}`; - const subCommands = cmd.commands; - if (subCommands.length > 0) { - script += ` + visit(cmd, nextPrefix); + + const subCommands = cmd.commands; + if (subCommands.length > 0) { + segments.push(` ${funcName}() { local -a commands local -a options @@ -470,17 +472,21 @@ ${funcName}() { ;; esac } -`; - } else { - script += ` +`); + continue; + } + + segments.push(` ${funcName}() { _arguments -C \\ ${generateZshArgs(cmd)} } -`; +`); } - } - return script; + }; + + visit(program, prefix); + return segments.join(""); } function generateBashCompletion(program: Command): string { @@ -528,38 +534,34 @@ function generateBashSubcommand(cmd: Command): string { function generatePowerShellCompletion(program: Command): string { const rootCmd = program.name(); + const segments: string[] = []; - const visit = (cmd: Command, parents: string[]): string => { - const cmdName = cmd.name(); - const fullPath = [...parents, cmdName].join(" "); - - let script = ""; + const visit = (cmd: Command, pathSegments: string[]) => { + const fullPath = pathSegments.join(" "); // Command completion for this level const subCommands = cmd.commands.map((c) => c.name()); const options = cmd.options.map((o) => o.flags.split(/[ ,|]+/)[0]); // Take first flag const allCompletions = [...subCommands, ...options].map((s) => `'${s}'`).join(","); - if (allCompletions.length > 0) { - script += ` + if (fullPath.length > 0 && allCompletions.length > 0) { + segments.push(` if ($commandPath -eq '${fullPath}') { $completions = @(${allCompletions}) $completions | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_) } } -`; +`); } - // Recurse for (const sub of cmd.commands) { - script += visit(sub, [...parents, cmdName]); + visit(sub, [...pathSegments, sub.name()]); } - - return script; }; - const rootBody = visit(program, []); + visit(program, []); + const rootBody = segments.join(""); return ` Register-ArgumentCompleter -Native -CommandName ${rootCmd} -ScriptBlock { @@ -593,65 +595,57 @@ Register-ArgumentCompleter -Native -CommandName ${rootCmd} -ScriptBlock { function generateFishCompletion(program: Command): string { const rootCmd = program.name(); - let script = ""; + const segments: string[] = []; const visit = (cmd: Command, parents: string[]) => { const cmdName = cmd.name(); - const fullPath = [...parents]; - if (parents.length > 0) { - fullPath.push(cmdName); - } // Only push if not root, or consistent root handling - - // Fish uses 'seen_subcommand_from' to determine context. - // For root: complete -c openclaw -n "__fish_use_subcommand" -a "subcmd" -d "desc" // Root logic if (parents.length === 0) { // Subcommands of root for (const sub of cmd.commands) { - script += buildFishSubcommandCompletionLine({ - rootCmd, - condition: "__fish_use_subcommand", - name: sub.name(), - description: sub.description(), - }); + segments.push( + buildFishSubcommandCompletionLine({ + rootCmd, + condition: "__fish_use_subcommand", + name: sub.name(), + description: sub.description(), + }), + ); } // Options of root for (const opt of cmd.options) { - script += buildFishOptionCompletionLine({ - rootCmd, - condition: "__fish_use_subcommand", - flags: opt.flags, - description: opt.description, - }); + segments.push( + buildFishOptionCompletionLine({ + rootCmd, + condition: "__fish_use_subcommand", + flags: opt.flags, + description: opt.description, + }), + ); } } else { - // Nested commands - // Logic: if seen subcommand matches parents... - // But fish completion logic is simpler if we just say "if we haven't seen THIS command yet but seen parent" - // Actually, a robust fish completion often requires defining a function to check current line. - // For simplicity, we'll assume standard fish helper __fish_seen_subcommand_from. - - // To properly scope to 'openclaw gateway' and not 'openclaw other gateway', we need to check the sequence. - // A simplified approach: - // Subcommands for (const sub of cmd.commands) { - script += buildFishSubcommandCompletionLine({ - rootCmd, - condition: `__fish_seen_subcommand_from ${cmdName}`, - name: sub.name(), - description: sub.description(), - }); + segments.push( + buildFishSubcommandCompletionLine({ + rootCmd, + condition: `__fish_seen_subcommand_from ${cmdName}`, + name: sub.name(), + description: sub.description(), + }), + ); } // Options for (const opt of cmd.options) { - script += buildFishOptionCompletionLine({ - rootCmd, - condition: `__fish_seen_subcommand_from ${cmdName}`, - flags: opt.flags, - description: opt.description, - }); + segments.push( + buildFishOptionCompletionLine({ + rootCmd, + condition: `__fish_seen_subcommand_from ${cmdName}`, + flags: opt.flags, + description: opt.description, + }), + ); } } @@ -661,5 +655,5 @@ function generateFishCompletion(program: Command): string { }; visit(program, []); - return script; + return segments.join(""); } diff --git a/src/plugins/loader.test.ts b/src/plugins/loader.test.ts index c37cfbfd46c..ac6ff410268 100644 --- a/src/plugins/loader.test.ts +++ b/src/plugins/loader.test.ts @@ -986,6 +986,153 @@ describe("loadOpenClawPlugins", () => { expect(httpPlugin?.httpRoutes).toBe(1); }); + it("rejects duplicate plugin-visible hook names", () => { + useNoBundledPlugins(); + const first = writePlugin({ + id: "hook-owner-a", + filename: "hook-owner-a.cjs", + body: `module.exports = { id: "hook-owner-a", register(api) { + api.registerHook("gateway:startup", () => {}, { name: "shared-hook" }); +} };`, + }); + const second = writePlugin({ + id: "hook-owner-b", + filename: "hook-owner-b.cjs", + body: `module.exports = { id: "hook-owner-b", register(api) { + api.registerHook("gateway:startup", () => {}, { name: "shared-hook" }); +} };`, + }); + + const registry = loadOpenClawPlugins({ + cache: false, + config: { + plugins: { + load: { paths: [first.file, second.file] }, + allow: ["hook-owner-a", "hook-owner-b"], + }, + }, + }); + + expect(registry.hooks.filter((entry) => entry.entry.hook.name === "shared-hook")).toHaveLength( + 1, + ); + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "hook-owner-b" && + diag.message === "hook already registered: shared-hook (hook-owner-a)", + ), + ).toBe(true); + }); + + it("rejects duplicate plugin service ids", () => { + useNoBundledPlugins(); + const first = writePlugin({ + id: "service-owner-a", + filename: "service-owner-a.cjs", + body: `module.exports = { id: "service-owner-a", register(api) { + api.registerService({ id: "shared-service", start() {} }); +} };`, + }); + const second = writePlugin({ + id: "service-owner-b", + filename: "service-owner-b.cjs", + body: `module.exports = { id: "service-owner-b", register(api) { + api.registerService({ id: "shared-service", start() {} }); +} };`, + }); + + const registry = loadOpenClawPlugins({ + cache: false, + config: { + plugins: { + load: { paths: [first.file, second.file] }, + allow: ["service-owner-a", "service-owner-b"], + }, + }, + }); + + expect(registry.services.filter((entry) => entry.service.id === "shared-service")).toHaveLength( + 1, + ); + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "service-owner-b" && + diag.message === "service already registered: shared-service (service-owner-a)", + ), + ).toBe(true); + }); + + it("requires plugin CLI registrars to declare explicit command roots", () => { + useNoBundledPlugins(); + const plugin = writePlugin({ + id: "cli-missing-metadata", + filename: "cli-missing-metadata.cjs", + body: `module.exports = { id: "cli-missing-metadata", register(api) { + api.registerCli(() => {}); +} };`, + }); + + const registry = loadRegistryFromSinglePlugin({ + plugin, + pluginConfig: { + allow: ["cli-missing-metadata"], + }, + }); + + expect(registry.cliRegistrars).toHaveLength(0); + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "cli-missing-metadata" && + diag.message === "cli registration missing explicit commands metadata", + ), + ).toBe(true); + }); + + it("rejects duplicate plugin CLI command roots", () => { + useNoBundledPlugins(); + const first = writePlugin({ + id: "cli-owner-a", + filename: "cli-owner-a.cjs", + body: `module.exports = { id: "cli-owner-a", register(api) { + api.registerCli(() => {}, { commands: ["shared-cli"] }); +} };`, + }); + const second = writePlugin({ + id: "cli-owner-b", + filename: "cli-owner-b.cjs", + body: `module.exports = { id: "cli-owner-b", register(api) { + api.registerCli(() => {}, { commands: ["shared-cli"] }); +} };`, + }); + + const registry = loadOpenClawPlugins({ + cache: false, + config: { + plugins: { + load: { paths: [first.file, second.file] }, + allow: ["cli-owner-a", "cli-owner-b"], + }, + }, + }); + + expect(registry.cliRegistrars).toHaveLength(1); + expect(registry.cliRegistrars[0]?.pluginId).toBe("cli-owner-a"); + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "cli-owner-b" && + diag.message === "cli command already registered: shared-cli (cli-owner-a)", + ), + ).toBe(true); + }); + it("registers http routes", () => { useNoBundledPlugins(); const plugin = writePlugin({ diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index ca987dc8e79..c1c63cc96cb 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -238,6 +238,16 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { }); return; } + const existingHook = registry.hooks.find((entry) => entry.entry.hook.name === name); + if (existingHook) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `hook already registered: ${name} (${existingHook.pluginId})`, + }); + return; + } const description = entry?.hook.description ?? opts?.description ?? ""; const hookEntry: HookEntry = entry @@ -473,6 +483,28 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { opts?: { commands?: string[] }, ) => { const commands = (opts?.commands ?? []).map((cmd) => cmd.trim()).filter(Boolean); + if (commands.length === 0) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: "cli registration missing explicit commands metadata", + }); + return; + } + const existing = registry.cliRegistrars.find((entry) => + entry.commands.some((command) => commands.includes(command)), + ); + if (existing) { + const overlap = commands.find((command) => existing.commands.includes(command)); + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `cli command already registered: ${overlap ?? commands[0]} (${existing.pluginId})`, + }); + return; + } record.cliCommands.push(...commands); registry.cliRegistrars.push({ pluginId: record.id, @@ -487,6 +519,16 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { if (!id) { return; } + const existing = registry.services.find((entry) => entry.service.id === id); + if (existing) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `service already registered: ${id} (${existing.pluginId})`, + }); + return; + } record.services.push(id); registry.services.push({ pluginId: record.id, From e2dac5d5cbf6e2c395e294e7569b13afa2e758c7 Mon Sep 17 00:00:00 2001 From: Nimrod Gutman Date: Sun, 15 Mar 2026 21:16:27 +0200 Subject: [PATCH 04/16] fix(plugins): load bundled extensions from dist (#47560) --- CHANGELOG.md | 1 + extensions/llm-task/src/llm-task-tool.test.ts | 4 +- extensions/llm-task/src/llm-task-tool.ts | 34 +---------- extensions/whatsapp/src/channel.ts | 8 +-- extensions/whatsapp/src/runtime.ts | 3 +- package.json | 5 +- scripts/copy-bundled-plugin-metadata.mjs | 57 +++++++++++++++++++ src/plugin-sdk/subpaths.test.ts | 5 ++ src/plugin-sdk/whatsapp.ts | 6 ++ src/plugins/loader.test.ts | 36 ++++++++++++ src/plugins/loader.ts | 33 +++++++++++ tsconfig.json | 1 + tsdown.config.ts | 53 +++++++++++++++++ vitest.config.ts | 4 ++ 14 files changed, 206 insertions(+), 44 deletions(-) create mode 100644 scripts/copy-bundled-plugin-metadata.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index ebbfb3f0924..fc9aa9435ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Docs: https://docs.openclaw.ai - CLI/onboarding: import static provider definitions directly for onboarding model/config helpers so those paths no longer pull provider discovery just for built-in defaults. (#47467) Thanks @vincentkoc. - CLI/auth choice: lazy-load plugin/provider fallback resolution so mapped auth choices stay on the static path and only unknown choices pay the heavy provider load. (#47495) Thanks @vincentkoc. - CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc. +- Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse. ## 2026.3.13 diff --git a/extensions/llm-task/src/llm-task-tool.test.ts b/extensions/llm-task/src/llm-task-tool.test.ts index 2bf0cb655aa..49feb7929ff 100644 --- a/extensions/llm-task/src/llm-task-tool.test.ts +++ b/extensions/llm-task/src/llm-task-tool.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -vi.mock("../../../src/agents/pi-embedded-runner.js", () => { +vi.mock("openclaw/extension-api", () => { return { runEmbeddedPiAgent: vi.fn(async () => ({ meta: { startedAt: Date.now() }, @@ -9,7 +9,7 @@ vi.mock("../../../src/agents/pi-embedded-runner.js", () => { }; }); -import { runEmbeddedPiAgent } from "../../../src/agents/pi-embedded-runner.js"; +import { runEmbeddedPiAgent } from "openclaw/extension-api"; import { createLlmTaskTool } from "./llm-task-tool.js"; // oxlint-disable-next-line typescript/no-explicit-any diff --git a/extensions/llm-task/src/llm-task-tool.ts b/extensions/llm-task/src/llm-task-tool.ts index ff2037e534a..d79e0a51130 100644 --- a/extensions/llm-task/src/llm-task-tool.ts +++ b/extensions/llm-task/src/llm-task-tool.ts @@ -2,6 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { Type } from "@sinclair/typebox"; import Ajv from "ajv"; +import { runEmbeddedPiAgent } from "openclaw/extension-api"; import { formatThinkingLevels, formatXHighModelHint, @@ -9,39 +10,8 @@ import { resolvePreferredOpenClawTmpDir, supportsXHighThinking, } from "openclaw/plugin-sdk/llm-task"; -// NOTE: This extension is intended to be bundled with OpenClaw. -// When running from source (tests/dev), OpenClaw internals live under src/. -// When running from a built install, internals live under dist/ (no src/ tree). -// So we resolve internal imports dynamically with src-first, dist-fallback. import type { OpenClawPluginApi } from "openclaw/plugin-sdk/llm-task"; -type RunEmbeddedPiAgentFn = (params: Record) => Promise; - -async function loadRunEmbeddedPiAgent(): Promise { - // Source checkout (tests/dev) - try { - const mod = await import("../../../src/agents/pi-embedded-runner.js"); - // oxlint-disable-next-line typescript/no-explicit-any - if (typeof (mod as any).runEmbeddedPiAgent === "function") { - // oxlint-disable-next-line typescript/no-explicit-any - return (mod as any).runEmbeddedPiAgent; - } - } catch { - // ignore - } - - // Bundled install (built) - // NOTE: there is no src/ tree in a packaged install. Prefer a stable internal entrypoint. - const distExtensionApi = "../../../dist/extensionAPI.js"; - const mod = (await import(distExtensionApi)) as { runEmbeddedPiAgent?: unknown }; - // oxlint-disable-next-line typescript/no-explicit-any - const fn = (mod as any).runEmbeddedPiAgent; - if (typeof fn !== "function") { - throw new Error("Internal error: runEmbeddedPiAgent not available"); - } - return fn as RunEmbeddedPiAgentFn; -} - function stripCodeFences(s: string): string { const trimmed = s.trim(); const m = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i); @@ -209,8 +179,6 @@ export function createLlmTaskTool(api: OpenClawPluginApi) { const sessionId = `llm-task-${Date.now()}`; const sessionFile = path.join(tmpDir, "session.json"); - const runEmbeddedPiAgent = await loadRunEmbeddedPiAgent(); - const result = await runEmbeddedPiAgent({ sessionId, sessionFile, diff --git a/extensions/whatsapp/src/channel.ts b/extensions/whatsapp/src/channel.ts index 8a60dc44432..1745f8caa74 100644 --- a/extensions/whatsapp/src/channel.ts +++ b/extensions/whatsapp/src/channel.ts @@ -1,11 +1,9 @@ -import { - buildAccountScopedDmSecurityPolicy, - collectAllowlistProviderGroupPolicyWarnings, - collectOpenGroupPolicyRouteAllowlistWarnings, -} from "openclaw/plugin-sdk/compat"; import { applyAccountNameToChannelSection, buildChannelConfigSchema, + buildAccountScopedDmSecurityPolicy, + collectAllowlistProviderGroupPolicyWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, createActionGate, createWhatsAppOutboundBase, DEFAULT_ACCOUNT_ID, diff --git a/extensions/whatsapp/src/runtime.ts b/extensions/whatsapp/src/runtime.ts index 13ace8243db..bf415eb17db 100644 --- a/extensions/whatsapp/src/runtime.ts +++ b/extensions/whatsapp/src/runtime.ts @@ -1,5 +1,4 @@ -import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat"; -import type { PluginRuntime } from "openclaw/plugin-sdk/whatsapp"; +import { createPluginRuntimeStore, type PluginRuntime } from "openclaw/plugin-sdk/whatsapp"; const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime } = createPluginRuntimeStore("WhatsApp runtime not initialized"); diff --git a/package.json b/package.json index 053e4bea2a3..2d880e80fe7 100644 --- a/package.json +++ b/package.json @@ -212,6 +212,7 @@ "types": "./dist/plugin-sdk/keyed-async-queue.d.ts", "default": "./dist/plugin-sdk/keyed-async-queue.js" }, + "./extension-api": "./dist/extensionAPI.js", "./cli-entry": "./openclaw.mjs" }, "scripts": { @@ -224,8 +225,8 @@ "android:run": "cd apps/android && ./gradlew :app:installDebug && adb shell am start -n ai.openclaw.app/.MainActivity", "android:test": "cd apps/android && ./gradlew :app:testDebugUnitTest", "android:test:integration": "OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_ANDROID_NODE=1 vitest run --config vitest.live.config.ts src/gateway/android-node.capabilities.live.test.ts", - "build": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", - "build:docker": "node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", + "build": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && node scripts/copy-bundled-plugin-metadata.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", + "build:docker": "node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && node scripts/copy-bundled-plugin-metadata.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", "build:plugin-sdk:dts": "tsc -p tsconfig.plugin-sdk.dts.json || true", "build:strict-smoke": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && pnpm build:plugin-sdk:dts", "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh", diff --git a/scripts/copy-bundled-plugin-metadata.mjs b/scripts/copy-bundled-plugin-metadata.mjs new file mode 100644 index 00000000000..40d8baa5299 --- /dev/null +++ b/scripts/copy-bundled-plugin-metadata.mjs @@ -0,0 +1,57 @@ +#!/usr/bin/env node + +import fs from "node:fs"; +import path from "node:path"; + +const repoRoot = process.cwd(); +const extensionsRoot = path.join(repoRoot, "extensions"); +const distExtensionsRoot = path.join(repoRoot, "dist", "extensions"); + +function rewritePackageExtensions(entries) { + if (!Array.isArray(entries)) { + return undefined; + } + + return entries + .filter((entry) => typeof entry === "string" && entry.trim().length > 0) + .map((entry) => { + const normalized = entry.replace(/^\.\//, ""); + const rewritten = normalized.replace(/\.[^.]+$/u, ".js"); + return `./${rewritten}`; + }); +} + +for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { + if (!dirent.isDirectory()) { + continue; + } + + const pluginDir = path.join(extensionsRoot, dirent.name); + const manifestPath = path.join(pluginDir, "openclaw.plugin.json"); + if (!fs.existsSync(manifestPath)) { + continue; + } + + const distPluginDir = path.join(distExtensionsRoot, dirent.name); + fs.mkdirSync(distPluginDir, { recursive: true }); + fs.copyFileSync(manifestPath, path.join(distPluginDir, "openclaw.plugin.json")); + + const packageJsonPath = path.join(pluginDir, "package.json"); + if (!fs.existsSync(packageJsonPath)) { + continue; + } + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + if (packageJson.openclaw && "extensions" in packageJson.openclaw) { + packageJson.openclaw = { + ...packageJson.openclaw, + extensions: rewritePackageExtensions(packageJson.openclaw.extensions), + }; + } + + fs.writeFileSync( + path.join(distPluginDir, "package.json"), + `${JSON.stringify(packageJson, null, 2)}\n`, + "utf8", + ); +} diff --git a/src/plugin-sdk/subpaths.test.ts b/src/plugin-sdk/subpaths.test.ts index 2d971c82255..e0d4827b879 100644 --- a/src/plugin-sdk/subpaths.test.ts +++ b/src/plugin-sdk/subpaths.test.ts @@ -1,3 +1,4 @@ +import * as extensionApi from "openclaw/extension-api"; import * as compatSdk from "openclaw/plugin-sdk/compat"; import * as discordSdk from "openclaw/plugin-sdk/discord"; import * as imessageSdk from "openclaw/plugin-sdk/imessage"; @@ -132,4 +133,8 @@ describe("plugin-sdk subpath exports", () => { const zalo = await import("openclaw/plugin-sdk/zalo"); expect(typeof zalo.resolveClientIp).toBe("function"); }); + + it("exports the extension api bridge", () => { + expect(typeof extensionApi.runEmbeddedPiAgent).toBe("function"); + }); }); diff --git a/src/plugin-sdk/whatsapp.ts b/src/plugin-sdk/whatsapp.ts index f18a953bf7a..4ea4fa8d2de 100644 --- a/src/plugin-sdk/whatsapp.ts +++ b/src/plugin-sdk/whatsapp.ts @@ -25,6 +25,11 @@ export { listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, } from "../channels/plugins/directory-config.js"; +export { + collectAllowlistProviderGroupPolicyWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, +} from "../channels/plugins/group-policy-warnings.js"; +export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js"; export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js"; export { @@ -44,5 +49,6 @@ export { resolveWhatsAppHeartbeatRecipients } from "../channels/plugins/whatsapp export { WhatsAppConfigSchema } from "../config/zod-schema.providers-whatsapp.js"; export { createActionGate, readStringParam } from "../agents/tools/common.js"; +export { createPluginRuntimeStore } from "./runtime-store.js"; export { normalizeE164 } from "../utils.js"; diff --git a/src/plugins/loader.test.ts b/src/plugins/loader.test.ts index ac6ff410268..e0d3a3537d0 100644 --- a/src/plugins/loader.test.ts +++ b/src/plugins/loader.test.ts @@ -284,6 +284,22 @@ function createPluginSdkAliasFixture(params?: { return { root, srcFile, distFile }; } +function createExtensionApiAliasFixture(params?: { srcBody?: string; distBody?: string }) { + const root = makeTempDir(); + const srcFile = path.join(root, "src", "extensionAPI.ts"); + const distFile = path.join(root, "dist", "extensionAPI.js"); + mkdirSafe(path.dirname(srcFile)); + mkdirSafe(path.dirname(distFile)); + fs.writeFileSync( + path.join(root, "package.json"), + JSON.stringify({ name: "openclaw", type: "module" }, null, 2), + "utf-8", + ); + fs.writeFileSync(srcFile, params?.srcBody ?? "export {};\n", "utf-8"); + fs.writeFileSync(distFile, params?.distBody ?? "export {};\n", "utf-8"); + return { root, srcFile, distFile }; +} + afterEach(() => { clearPluginLoaderCache(); if (prevBundledDir === undefined) { @@ -2334,4 +2350,24 @@ describe("loadOpenClawPlugins", () => { ); expect(resolved).toBe(srcFile); }); + + it("prefers dist extension-api alias when loader runs from dist", () => { + const { root, distFile } = createExtensionApiAliasFixture(); + + const resolved = __testing.resolveExtensionApiAlias({ + modulePath: path.join(root, "dist", "plugins", "loader.js"), + }); + expect(resolved).toBe(distFile); + }); + + it("prefers src extension-api alias when loader runs from src in non-production", () => { + const { root, srcFile } = createExtensionApiAliasFixture(); + + const resolved = withEnv({ NODE_ENV: undefined }, () => + __testing.resolveExtensionApiAlias({ + modulePath: path.join(root, "src", "plugins", "loader.ts"), + }), + ); + expect(resolved).toBe(srcFile); + }); }); diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts index 253ad63afc4..20d5772d3f7 100644 --- a/src/plugins/loader.ts +++ b/src/plugins/loader.ts @@ -124,6 +124,36 @@ const resolvePluginSdkAliasFile = (params: { const resolvePluginSdkAlias = (): string | null => resolvePluginSdkAliasFile({ srcFile: "root-alias.cjs", distFile: "root-alias.cjs" }); +const resolveExtensionApiAlias = (params: { modulePath?: string } = {}): string | null => { + try { + const modulePath = params.modulePath ?? fileURLToPath(import.meta.url); + const packageRoot = resolveOpenClawPackageRootSync({ + cwd: path.dirname(modulePath), + }); + if (!packageRoot) { + return null; + } + + const orderedKinds = resolvePluginSdkAliasCandidateOrder({ + modulePath, + isProduction: process.env.NODE_ENV === "production", + }); + const candidateMap = { + src: path.join(packageRoot, "src", "extensionAPI.ts"), + dist: path.join(packageRoot, "dist", "extensionAPI.js"), + } as const; + for (const kind of orderedKinds) { + const candidate = candidateMap[kind]; + if (fs.existsSync(candidate)) { + return candidate; + } + } + } catch { + // ignore + } + return null; +}; + const cachedPluginSdkExportedSubpaths = new Map(); function listPluginSdkExportedSubpaths(params: { modulePath?: string } = {}): string[] { @@ -172,6 +202,7 @@ const resolvePluginSdkScopedAliasMap = (): Record => { export const __testing = { listPluginSdkAliasCandidates, listPluginSdkExportedSubpaths, + resolveExtensionApiAlias, resolvePluginSdkAliasCandidateOrder, resolvePluginSdkAliasFile, maxPluginRegistryCacheEntries: MAX_PLUGIN_REGISTRY_CACHE_ENTRIES, @@ -701,7 +732,9 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi return jitiLoader; } const pluginSdkAlias = resolvePluginSdkAlias(); + const extensionApiAlias = resolveExtensionApiAlias(); const aliasMap = { + ...(extensionApiAlias ? { "openclaw/extension-api": extensionApiAlias } : {}), ...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}), ...resolvePluginSdkScopedAliasMap(), }; diff --git a/tsconfig.json b/tsconfig.json index bc6439e921f..e2f9e4ff97e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "target": "es2023", "useDefineForClassFields": false, "paths": { + "openclaw/extension-api": ["./src/extensionAPI.ts"], "openclaw/plugin-sdk": ["./src/plugin-sdk/index.ts"], "openclaw/plugin-sdk/*": ["./src/plugin-sdk/*.ts"], "openclaw/plugin-sdk/account-id": ["./src/plugin-sdk/account-id.ts"] diff --git a/tsdown.config.ts b/tsdown.config.ts index acd4fc3e0c8..b1aa8749307 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,3 +1,5 @@ +import fs from "node:fs"; +import path from "node:path"; import { defineConfig } from "tsdown"; const env = { @@ -87,6 +89,51 @@ const pluginSdkEntrypoints = [ "keyed-async-queue", ] as const; +function listBundledPluginBuildEntries(): Record { + const extensionsRoot = path.join(process.cwd(), "extensions"); + const entries: Record = {}; + + for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { + if (!dirent.isDirectory()) { + continue; + } + + const pluginDir = path.join(extensionsRoot, dirent.name); + const manifestPath = path.join(pluginDir, "openclaw.plugin.json"); + if (!fs.existsSync(manifestPath)) { + continue; + } + + const packageJsonPath = path.join(pluginDir, "package.json"); + let packageEntries: string[] = []; + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as { + openclaw?: { extensions?: unknown }; + }; + packageEntries = Array.isArray(packageJson.openclaw?.extensions) + ? packageJson.openclaw.extensions.filter( + (entry): entry is string => typeof entry === "string" && entry.trim().length > 0, + ) + : []; + } catch { + packageEntries = []; + } + } + + const sourceEntries = packageEntries.length > 0 ? packageEntries : ["./index.ts"]; + for (const entry of sourceEntries) { + const normalizedEntry = entry.replace(/^\.\//, ""); + const entryKey = `extensions/${dirent.name}/${normalizedEntry.replace(/\.[^.]+$/u, "")}`; + entries[entryKey] = path.join("extensions", dirent.name, normalizedEntry); + } + } + + return entries; +} + +const bundledPluginBuildEntries = listBundledPluginBuildEntries(); + export default defineConfig([ nodeBuildConfig({ entry: "src/index.ts", @@ -122,6 +169,12 @@ export default defineConfig([ entry: Object.fromEntries(pluginSdkEntrypoints.map((e) => [e, `src/plugin-sdk/${e}.ts`])), outDir: "dist/plugin-sdk", }), + nodeBuildConfig({ + // Bundle bundled plugin entrypoints so built gateway startup can load JS + // directly from dist/extensions instead of transpiling extensions/*.ts via Jiti. + entry: bundledPluginBuildEntries, + outDir: "dist", + }), nodeBuildConfig({ entry: "src/extensionAPI.ts", }), diff --git a/vitest.config.ts b/vitest.config.ts index 5e0a192d5a3..70011a6a0b8 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -58,6 +58,10 @@ export default defineConfig({ resolve: { // Keep this ordered: the base `openclaw/plugin-sdk` alias is a prefix match. alias: [ + { + find: "openclaw/extension-api", + replacement: path.join(repoRoot, "src", "extensionAPI.ts"), + }, ...pluginSdkSubpaths.map((subpath) => ({ find: `openclaw/plugin-sdk/${subpath}`, replacement: path.join(repoRoot, "src", "plugin-sdk", `${subpath}.ts`), From 42837a04bfa9b430f70e17de13a81f116d7c1287 Mon Sep 17 00:00:00 2001 From: "peizhe.chen" Date: Mon, 16 Mar 2026 03:21:11 +0800 Subject: [PATCH 05/16] fix(models): preserve stream usage compat opt-ins (#45733) Preserves explicit `supportsUsageInStreaming` overrides from built-in provider catalogs and user config instead of unconditionally forcing `false` on non-native openai-completions endpoints. Adds `applyNativeStreamingUsageCompat()` to set `supportsUsageInStreaming: true` on ModelStudio (DashScope) and Moonshot models at config build time so their native streaming usage works out of the box. Closes #46142 Co-authored-by: pezy --- src/agents/model-compat.test.ts | 37 +++++++++ src/agents/model-compat.ts | 6 +- src/agents/models-config.plan.ts | 4 +- ...odels-config.providers.modelstudio.test.ts | 52 ++++++------ .../models-config.providers.moonshot.test.ts | 55 ++++++++++++- src/agents/models-config.providers.ts | 79 ++++++++++++++++++- 6 files changed, 203 insertions(+), 30 deletions(-) diff --git a/src/agents/model-compat.test.ts b/src/agents/model-compat.test.ts index 733d9a2f47f..bda8ac664db 100644 --- a/src/agents/model-compat.test.ts +++ b/src/agents/model-compat.test.ts @@ -295,6 +295,17 @@ describe("normalizeModelCompat", () => { expect(supportsUsageInStreaming(normalized)).toBe(true); }); + it("preserves explicit supportsUsageInStreaming false on non-native endpoints", () => { + const model = { + ...baseModel(), + provider: "custom-cpa", + baseUrl: "https://proxy.example.com/v1", + compat: { supportsUsageInStreaming: false }, + }; + const normalized = normalizeModelCompat(model); + expect(supportsUsageInStreaming(normalized)).toBe(false); + }); + it("still forces flags off when not explicitly set by user", () => { const model = { ...baseModel(), @@ -348,6 +359,32 @@ describe("normalizeModelCompat", () => { expect(supportsUsageInStreaming(normalized)).toBe(false); expect(supportsStrictMode(normalized)).toBe(false); }); + + it("leaves fully explicit non-native compat untouched", () => { + const model = baseModel(); + model.baseUrl = "https://proxy.example.com/v1"; + model.compat = { + supportsDeveloperRole: false, + supportsUsageInStreaming: true, + supportsStrictMode: true, + }; + const normalized = normalizeModelCompat(model); + expect(normalized).toBe(model); + }); + + it("preserves explicit usage compat when developer role is explicitly enabled", () => { + const model = baseModel(); + model.baseUrl = "https://proxy.example.com/v1"; + model.compat = { + supportsDeveloperRole: true, + supportsUsageInStreaming: true, + supportsStrictMode: true, + }; + const normalized = normalizeModelCompat(model); + expect(supportsDeveloperRole(normalized)).toBe(true); + expect(supportsUsageInStreaming(normalized)).toBe(true); + expect(supportsStrictMode(normalized)).toBe(true); + }); }); describe("isModernModelRef", () => { diff --git a/src/agents/model-compat.ts b/src/agents/model-compat.ts index 46e37733aec..26522da6e67 100644 --- a/src/agents/model-compat.ts +++ b/src/agents/model-compat.ts @@ -66,11 +66,11 @@ export function normalizeModelCompat(model: Model): Model { return model; } const forcedDeveloperRole = compat?.supportsDeveloperRole === true; - const forcedUsageStreaming = compat?.supportsUsageInStreaming === true; + const hasStreamingUsageOverride = compat?.supportsUsageInStreaming !== undefined; const targetStrictMode = compat?.supportsStrictMode ?? false; if ( compat?.supportsDeveloperRole !== undefined && - compat?.supportsUsageInStreaming !== undefined && + hasStreamingUsageOverride && compat?.supportsStrictMode !== undefined ) { return model; @@ -83,7 +83,7 @@ export function normalizeModelCompat(model: Model): Model { ? { ...compat, supportsDeveloperRole: forcedDeveloperRole || false, - supportsUsageInStreaming: forcedUsageStreaming || false, + ...(hasStreamingUsageOverride ? {} : { supportsUsageInStreaming: false }), supportsStrictMode: targetStrictMode, } : { diff --git a/src/agents/models-config.plan.ts b/src/agents/models-config.plan.ts index 601a0edfda1..31794180c3c 100644 --- a/src/agents/models-config.plan.ts +++ b/src/agents/models-config.plan.ts @@ -6,6 +6,7 @@ import { type ExistingProviderConfig, } from "./models-config.merge.js"; import { + applyNativeStreamingUsageCompat, enforceSourceManagedProviderSecrets, normalizeProviders, resolveImplicitProviders, @@ -126,7 +127,8 @@ export async function planOpenClawModelsJson(params: { sourceSecretDefaults: params.sourceConfigForSecrets?.secrets?.defaults, secretRefManagedProviders, }) ?? mergedProviders; - const nextContents = `${JSON.stringify({ providers: secretEnforcedProviders }, null, 2)}\n`; + const finalProviders = applyNativeStreamingUsageCompat(secretEnforcedProviders); + const nextContents = `${JSON.stringify({ providers: finalProviders }, null, 2)}\n`; if (params.existingRaw === nextContents) { return { action: "noop" }; diff --git a/src/agents/models-config.providers.modelstudio.test.ts b/src/agents/models-config.providers.modelstudio.test.ts index df4000cc27d..619146d635c 100644 --- a/src/agents/models-config.providers.modelstudio.test.ts +++ b/src/agents/models-config.providers.modelstudio.test.ts @@ -1,32 +1,36 @@ -import { mkdtempSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { withEnvAsync } from "../test-utils/env.js"; -import { resolveImplicitProvidersForTest } from "./models-config.e2e-harness.js"; -import { buildModelStudioProvider } from "./models-config.providers.js"; - -const modelStudioApiKeyEnv = ["MODELSTUDIO_API", "KEY"].join("_"); +import { + applyNativeStreamingUsageCompat, + buildModelStudioProvider, +} from "./models-config.providers.js"; describe("Model Studio implicit provider", () => { - it("should include modelstudio when MODELSTUDIO_API_KEY is configured", async () => { - const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-")); - const modelStudioApiKey = "test-key"; // pragma: allowlist secret - await withEnvAsync({ [modelStudioApiKeyEnv]: modelStudioApiKey }, async () => { - const providers = await resolveImplicitProvidersForTest({ agentDir }); - expect(providers?.modelstudio).toBeDefined(); - expect(providers?.modelstudio?.apiKey).toBe("MODELSTUDIO_API_KEY"); - expect(providers?.modelstudio?.baseUrl).toBe("https://coding-intl.dashscope.aliyuncs.com/v1"); + it("should opt native Model Studio baseUrls into streaming usage", () => { + const providers = applyNativeStreamingUsageCompat({ + modelstudio: buildModelStudioProvider(), }); + expect(providers?.modelstudio).toBeDefined(); + expect(providers?.modelstudio?.baseUrl).toBe("https://coding-intl.dashscope.aliyuncs.com/v1"); + expect( + providers?.modelstudio?.models?.every( + (model) => model.compat?.supportsUsageInStreaming === true, + ), + ).toBe(true); }); - it("should build the static Model Studio provider catalog", () => { - const provider = buildModelStudioProvider(); - const modelIds = provider.models.map((model) => model.id); - expect(provider.api).toBe("openai-completions"); - expect(provider.baseUrl).toBe("https://coding-intl.dashscope.aliyuncs.com/v1"); - expect(modelIds).toContain("qwen3.5-plus"); - expect(modelIds).toContain("qwen3-coder-plus"); - expect(modelIds).toContain("kimi-k2.5"); + it("should keep streaming usage opt-in disabled for custom Model Studio-compatible baseUrls", () => { + const providers = applyNativeStreamingUsageCompat({ + modelstudio: { + ...buildModelStudioProvider(), + baseUrl: "https://proxy.example.com/v1", + }, + }); + expect(providers?.modelstudio).toBeDefined(); + expect(providers?.modelstudio?.baseUrl).toBe("https://proxy.example.com/v1"); + expect( + providers?.modelstudio?.models?.some( + (model) => model.compat?.supportsUsageInStreaming === true, + ), + ).toBe(false); }); }); diff --git a/src/agents/models-config.providers.moonshot.test.ts b/src/agents/models-config.providers.moonshot.test.ts index 00e1f5949c6..c235266800a 100644 --- a/src/agents/models-config.providers.moonshot.test.ts +++ b/src/agents/models-config.providers.moonshot.test.ts @@ -7,7 +7,11 @@ import { MOONSHOT_CN_BASE_URL, } from "../commands/onboard-auth.models.js"; import { captureEnv } from "../test-utils/env.js"; -import { resolveImplicitProviders } from "./models-config.providers.js"; +import { + applyNativeStreamingUsageCompat, + resolveImplicitProviders, +} from "./models-config.providers.js"; +import { buildMoonshotProvider } from "./models-config.providers.static.js"; describe("moonshot implicit provider (#33637)", () => { it("uses explicit CN baseUrl when provided", async () => { @@ -39,6 +43,31 @@ describe("moonshot implicit provider (#33637)", () => { expect(providers?.moonshot).toBeDefined(); expect(providers?.moonshot?.baseUrl).toBe(MOONSHOT_CN_BASE_URL); expect(providers?.moonshot?.apiKey).toBeDefined(); + expect(providers?.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBeUndefined(); + } finally { + envSnapshot.restore(); + } + }); + + it("keeps streaming usage opt-in unset before the final compat pass", async () => { + const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-")); + const envSnapshot = captureEnv(["MOONSHOT_API_KEY"]); + process.env.MOONSHOT_API_KEY = "sk-test-custom"; + + try { + const providers = await resolveImplicitProviders({ + agentDir, + explicitProviders: { + moonshot: { + baseUrl: "https://proxy.example.com/v1", + api: "openai-completions", + models: [], + }, + }, + }); + expect(providers?.moonshot).toBeDefined(); + expect(providers?.moonshot?.baseUrl).toBe("https://proxy.example.com/v1"); + expect(providers?.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBeUndefined(); } finally { envSnapshot.restore(); } @@ -53,8 +82,32 @@ describe("moonshot implicit provider (#33637)", () => { const providers = await resolveImplicitProviders({ agentDir }); expect(providers?.moonshot).toBeDefined(); expect(providers?.moonshot?.baseUrl).toBe(MOONSHOT_AI_BASE_URL); + expect(providers?.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBeUndefined(); } finally { envSnapshot.restore(); } }); + + it("opts native Moonshot baseUrls into streaming usage only after the final compat pass", () => { + const defaultProviders = applyNativeStreamingUsageCompat({ + moonshot: buildMoonshotProvider(), + }); + expect(defaultProviders.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBe(true); + + const cnProviders = applyNativeStreamingUsageCompat({ + moonshot: { + ...buildMoonshotProvider(), + baseUrl: MOONSHOT_CN_BASE_URL, + }, + }); + expect(cnProviders.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBe(true); + + const customProviders = applyNativeStreamingUsageCompat({ + moonshot: { + ...buildMoonshotProvider(), + baseUrl: "https://proxy.example.com/v1", + }, + }); + expect(customProviders.moonshot?.models?.[0]?.compat?.supportsUsageInStreaming).toBeUndefined(); + }); }); diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 03110d3fba5..19d2f1327ba 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -81,6 +81,15 @@ type SecretDefaults = { exec?: string; }; +const MOONSHOT_NATIVE_BASE_URLS = new Set([ + "https://api.moonshot.ai/v1", + "https://api.moonshot.cn/v1", +]); +const MODELSTUDIO_NATIVE_BASE_URLS = new Set([ + "https://coding-intl.dashscope.aliyuncs.com/v1", + "https://coding.dashscope.aliyuncs.com/v1", +]); + const ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/; function normalizeApiKeyConfig(value: string): string { @@ -89,6 +98,65 @@ function normalizeApiKeyConfig(value: string): string { return match?.[1] ?? trimmed; } +function normalizeProviderBaseUrl(baseUrl: string | undefined): string { + const trimmed = baseUrl?.trim(); + if (!trimmed) { + return ""; + } + try { + const url = new URL(trimmed); + url.hash = ""; + url.search = ""; + return url.toString().replace(/\/+$/, "").toLowerCase(); + } catch { + return trimmed.replace(/\/+$/, "").toLowerCase(); + } +} + +function withStreamingUsageCompat(provider: ProviderConfig): ProviderConfig { + if (!Array.isArray(provider.models) || provider.models.length === 0) { + return provider; + } + + let changed = false; + const models = provider.models.map((model) => { + if (model.compat?.supportsUsageInStreaming !== undefined) { + return model; + } + changed = true; + return { + ...model, + compat: { + ...model.compat, + supportsUsageInStreaming: true, + }, + }; + }); + + return changed ? { ...provider, models } : provider; +} + +export function applyNativeStreamingUsageCompat( + providers: Record, +): Record { + let changed = false; + const nextProviders: Record = {}; + + for (const [providerKey, provider] of Object.entries(providers)) { + const normalizedBaseUrl = normalizeProviderBaseUrl(provider.baseUrl); + const isNativeMoonshot = + providerKey === "moonshot" && MOONSHOT_NATIVE_BASE_URLS.has(normalizedBaseUrl); + const isNativeModelStudio = + providerKey === "modelstudio" && MODELSTUDIO_NATIVE_BASE_URLS.has(normalizedBaseUrl); + const nextProvider = + isNativeMoonshot || isNativeModelStudio ? withStreamingUsageCompat(provider) : provider; + nextProviders[providerKey] = nextProvider; + changed ||= nextProvider !== provider; + } + + return changed ? nextProviders : providers; +} + function resolveEnvApiKeyVarName( provider: string, env: NodeJS.ProcessEnv = process.env, @@ -684,7 +752,16 @@ const SIMPLE_IMPLICIT_PROVIDER_LOADERS: ImplicitProviderLoader[] = [ apiKey, })), withApiKey("qianfan", async ({ apiKey }) => ({ ...buildQianfanProvider(), apiKey })), - withApiKey("modelstudio", async ({ apiKey }) => ({ ...buildModelStudioProvider(), apiKey })), + withApiKey("modelstudio", async ({ apiKey, explicitProvider }) => { + const explicitBaseUrl = explicitProvider?.baseUrl; + return { + ...buildModelStudioProvider(), + ...(typeof explicitBaseUrl === "string" && explicitBaseUrl.trim() + ? { baseUrl: explicitBaseUrl.trim() } + : {}), + apiKey, + }; + }), withApiKey("openrouter", async ({ apiKey }) => ({ ...buildOpenrouterProvider(), apiKey })), withApiKey("nvidia", async ({ apiKey }) => ({ ...buildNvidiaProvider(), apiKey })), withApiKey("kilocode", async ({ apiKey }) => ({ From 51631e5797d8191b1ecfc5f126f1764ac41eb74b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 12:27:29 -0700 Subject: [PATCH 06/16] Plugins: reserve context engine ownership --- src/context-engine/context-engine.test.ts | 24 +++++++-- src/context-engine/registry.ts | 34 +++++++++--- src/plugins/loader.test.ts | 65 +++++++++++++++++++++++ src/plugins/registry.ts | 22 +++++++- 4 files changed, 133 insertions(+), 12 deletions(-) diff --git a/src/context-engine/context-engine.test.ts b/src/context-engine/context-engine.test.ts index cd0f2f50439..5cdc03a7114 100644 --- a/src/context-engine/context-engine.test.ts +++ b/src/context-engine/context-engine.test.ts @@ -231,18 +231,36 @@ describe("Registry tests", () => { expect(Array.isArray(ids)).toBe(true); }); - it("registering the same id overwrites the previous factory", () => { + it("registering the same id with the same owner refreshes the factory", () => { const factory1 = () => new MockContextEngine(); const factory2 = () => new MockContextEngine(); - registerContextEngine("reg-overwrite", factory1); + expect(registerContextEngine("reg-overwrite", factory1, { owner: "owner-a" })).toEqual({ + ok: true, + }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory1); - registerContextEngine("reg-overwrite", factory2); + expect(registerContextEngine("reg-overwrite", factory2, { owner: "owner-a" })).toEqual({ + ok: true, + }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory2); expect(getContextEngineFactory("reg-overwrite")).not.toBe(factory1); }); + it("rejects context engine registrations from a different owner", () => { + const factory1 = () => new MockContextEngine(); + const factory2 = () => new MockContextEngine(); + + expect(registerContextEngine("reg-owner-guard", factory1, { owner: "owner-a" })).toEqual({ + ok: true, + }); + expect(registerContextEngine("reg-owner-guard", factory2, { owner: "owner-b" })).toEqual({ + ok: false, + existingOwner: "owner-a", + }); + expect(getContextEngineFactory("reg-owner-guard")).toBe(factory1); + }); + it("shares registered engines across duplicate module copies", async () => { const registryUrl = new URL("./registry.ts", import.meta.url).href; const suffix = Date.now().toString(36); diff --git a/src/context-engine/registry.ts b/src/context-engine/registry.ts index d73266c62de..8b5474dc127 100644 --- a/src/context-engine/registry.ts +++ b/src/context-engine/registry.ts @@ -7,6 +7,7 @@ import type { ContextEngine } from "./types.js"; * Supports async creation for engines that need DB connections etc. */ export type ContextEngineFactory = () => ContextEngine | Promise; +export type ContextEngineRegistrationResult = { ok: true } | { ok: false; existingOwner: string }; // --------------------------------------------------------------------------- // Registry (module-level singleton) @@ -15,7 +16,13 @@ export type ContextEngineFactory = () => ContextEngine | Promise; const CONTEXT_ENGINE_REGISTRY_STATE = Symbol.for("openclaw.contextEngineRegistryState"); type ContextEngineRegistryState = { - engines: Map; + engines: Map< + string, + { + factory: ContextEngineFactory; + owner: string; + } + >; }; // Keep context-engine registrations process-global so duplicated dist chunks @@ -26,7 +33,7 @@ function getContextEngineRegistryState(): ContextEngineRegistryState { }; if (!globalState[CONTEXT_ENGINE_REGISTRY_STATE]) { globalState[CONTEXT_ENGINE_REGISTRY_STATE] = { - engines: new Map(), + engines: new Map(), }; } return globalState[CONTEXT_ENGINE_REGISTRY_STATE]; @@ -35,15 +42,26 @@ function getContextEngineRegistryState(): ContextEngineRegistryState { /** * Register a context engine implementation under the given id. */ -export function registerContextEngine(id: string, factory: ContextEngineFactory): void { - getContextEngineRegistryState().engines.set(id, factory); +export function registerContextEngine( + id: string, + factory: ContextEngineFactory, + opts?: { owner?: string }, +): ContextEngineRegistrationResult { + const owner = opts?.owner?.trim() || "core"; + const registry = getContextEngineRegistryState().engines; + const existing = registry.get(id); + if (existing && existing.owner !== owner) { + return { ok: false, existingOwner: existing.owner }; + } + registry.set(id, { factory, owner }); + return { ok: true }; } /** * Return the factory for a registered engine, or undefined. */ export function getContextEngineFactory(id: string): ContextEngineFactory | undefined { - return getContextEngineRegistryState().engines.get(id); + return getContextEngineRegistryState().engines.get(id)?.factory; } /** @@ -73,13 +91,13 @@ export async function resolveContextEngine(config?: OpenClawConfig): Promise { ).toBe(true); }); + it("rejects plugin context engine ids reserved by core", () => { + useNoBundledPlugins(); + const plugin = writePlugin({ + id: "context-engine-core-collision", + filename: "context-engine-core-collision.cjs", + body: `module.exports = { id: "context-engine-core-collision", register(api) { + api.registerContextEngine("legacy", () => ({})); +} };`, + }); + + const registry = loadRegistryFromSinglePlugin({ + plugin, + pluginConfig: { + allow: ["context-engine-core-collision"], + }, + }); + + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "context-engine-core-collision" && + diag.message === "context engine id reserved by core: legacy", + ), + ).toBe(true); + }); + + it("rejects duplicate plugin context engine ids", () => { + useNoBundledPlugins(); + const first = writePlugin({ + id: "context-engine-owner-a", + filename: "context-engine-owner-a.cjs", + body: `module.exports = { id: "context-engine-owner-a", register(api) { + api.registerContextEngine("shared-context-engine-loader-test", () => ({})); +} };`, + }); + const second = writePlugin({ + id: "context-engine-owner-b", + filename: "context-engine-owner-b.cjs", + body: `module.exports = { id: "context-engine-owner-b", register(api) { + api.registerContextEngine("shared-context-engine-loader-test", () => ({})); +} };`, + }); + + const registry = loadOpenClawPlugins({ + cache: false, + config: { + plugins: { + load: { paths: [first.file, second.file] }, + allow: ["context-engine-owner-a", "context-engine-owner-b"], + }, + }, + }); + + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "context-engine-owner-b" && + diag.message === + "context engine already registered: shared-context-engine-loader-test (plugin:context-engine-owner-a)", + ), + ).toBe(true); + }); + it("requires plugin CLI registrars to declare explicit command roots", () => { useNoBundledPlugins(); const plugin = writePlugin({ diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index c1c63cc96cb..952c8d7744b 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -15,6 +15,7 @@ import { normalizePluginHttpPath } from "./http-path.js"; import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js"; import { normalizeRegisteredProvider } from "./provider-validation.js"; import type { PluginRuntime } from "./runtime/types.js"; +import { defaultSlotIdForKey } from "./slots.js"; import { isPluginHookName, isPromptInjectionHookName, @@ -653,7 +654,26 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { registerCli: (registrar, opts) => registerCli(record, registrar, opts), registerService: (service) => registerService(record, service), registerCommand: (command) => registerCommand(record, command), - registerContextEngine: (id, factory) => registerContextEngine(id, factory), + registerContextEngine: (id, factory) => { + if (id === defaultSlotIdForKey("contextEngine")) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `context engine id reserved by core: ${id}`, + }); + return; + } + const result = registerContextEngine(id, factory, { owner: `plugin:${record.id}` }); + if (!result.ok) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `context engine already registered: ${id} (${result.existingOwner})`, + }); + } + }, resolvePath: (input: string) => resolveUserPath(input), on: (hookName, handler, opts) => registerTypedHook(record, hookName, handler, opts, params.hookPolicy), From 4a7fbe090af47f63d59bceb8f54cb6106c04a397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Dinh?= <82420070+No898@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:40:35 +0100 Subject: [PATCH 07/16] docs(zalo): document current Marketplace bot behavior (openclaw#47552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified: - pnpm check:docs Co-authored-by: Tomáš Dinh <82420070+No898@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/channels/zalo.md | 89 ++++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc9aa9435ae..2b85cd40bb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai - Feishu/streaming: add `onReasoningStream` and `onReasoningEnd` support to streaming cards, so `/reasoning stream` renders thinking tokens as markdown blockquotes in the same card — matching the Telegram channel's reasoning lane behavior. (#46029) - Refactor/channels: remove the legacy channel shim directories and point channel-specific imports directly at the extension-owned implementations. (#45967) thanks @scoootscooob. - Android/nodes: add `callLog.search` plus shared Call Log permission wiring so Android nodes can search recent call history through the gateway. (#44073) Thanks @lxk7280. +- Docs/Zalo: clarify the Marketplace-bot support matrix and config guidance so the Zalo channel docs match current Bot Creator behavior more closely. (#47552) Thanks @No898. ### Fixes diff --git a/docs/channels/zalo.md b/docs/channels/zalo.md index 77b288b0ab7..cf53b574e42 100644 --- a/docs/channels/zalo.md +++ b/docs/channels/zalo.md @@ -7,7 +7,7 @@ title: "Zalo" # Zalo (Bot API) -Status: experimental. DMs are supported; group handling is available with explicit group policy controls. +Status: experimental. DMs are supported. The [Capabilities](#capabilities) section below reflects current Marketplace-bot behavior. ## Plugin required @@ -25,7 +25,7 @@ Zalo ships as a plugin and is not bundled with the core install. - Or pick **Zalo** in onboarding and confirm the install prompt 2. Set the token: - Env: `ZALO_BOT_TOKEN=...` - - Or config: `channels.zalo.botToken: "..."`. + - Or config: `channels.zalo.accounts.default.botToken: "..."`. 3. Restart the gateway (or finish onboarding). 4. DM access is pairing by default; approve the pairing code on first contact. @@ -36,8 +36,12 @@ Minimal config: channels: { zalo: { enabled: true, - botToken: "12345689:abc-xyz", - dmPolicy: "pairing", + accounts: { + default: { + botToken: "12345689:abc-xyz", + dmPolicy: "pairing", + }, + }, }, }, } @@ -48,10 +52,13 @@ Minimal config: Zalo is a Vietnam-focused messaging app; its Bot API lets the Gateway run a bot for 1:1 conversations. It is a good fit for support or notifications where you want deterministic routing back to Zalo. +This page reflects current OpenClaw behavior for **Zalo Bot Creator / Marketplace bots**. +**Zalo Official Account (OA) bots** are a different Zalo product surface and may behave differently. + - A Zalo Bot API channel owned by the Gateway. - Deterministic routing: replies go back to Zalo; the model never chooses channels. - DMs share the agent's main session. -- Groups are supported with policy controls (`groupPolicy` + `groupAllowFrom`) and default to fail-closed allowlist behavior. +- The [Capabilities](#capabilities) section below shows current Marketplace-bot support. ## Setup (fast path) @@ -59,7 +66,7 @@ It is a good fit for support or notifications where you want deterministic routi 1. Go to [https://bot.zaloplatforms.com](https://bot.zaloplatforms.com) and sign in. 2. Create a new bot and configure its settings. -3. Copy the bot token (format: `12345689:abc-xyz`). +3. Copy the full bot token (typically `numeric_id:secret`). For Marketplace bots, the usable runtime token may appear in the bot's welcome message after creation. ### 2) Configure the token (env or config) @@ -70,13 +77,19 @@ Example: channels: { zalo: { enabled: true, - botToken: "12345689:abc-xyz", - dmPolicy: "pairing", + accounts: { + default: { + botToken: "12345689:abc-xyz", + dmPolicy: "pairing", + }, + }, }, }, } ``` +If you later move to a Zalo bot surface where groups are available, you can add group-specific config such as `groupPolicy` and `groupAllowFrom` explicitly. For current Marketplace-bot behavior, see [Capabilities](#capabilities). + Env option: `ZALO_BOT_TOKEN=...` (works for the default account only). Multi-account support: use `channels.zalo.accounts` with per-account tokens and optional `name`. @@ -109,14 +122,23 @@ Multi-account support: use `channels.zalo.accounts` with per-account tokens and ## Access control (Groups) +For **Zalo Bot Creator / Marketplace bots**, group support was not available in practice because the bot could not be added to a group at all. + +That means the group-related config keys below exist in the schema, but were not usable for Marketplace bots: + - `channels.zalo.groupPolicy` controls group inbound handling: `open | allowlist | disabled`. -- Default behavior is fail-closed: `allowlist`. - `channels.zalo.groupAllowFrom` restricts which sender IDs can trigger the bot in groups. - If `groupAllowFrom` is unset, Zalo falls back to `allowFrom` for sender checks. -- `groupPolicy: "disabled"` blocks all group messages. -- `groupPolicy: "open"` allows any group member (mention-gated). - Runtime note: if `channels.zalo` is missing entirely, runtime still falls back to `groupPolicy="allowlist"` for safety. +The group policy values (when group access is available on your bot surface) are: + +- `groupPolicy: "disabled"` — blocks all group messages. +- `groupPolicy: "open"` — allows any group member (mention-gated). +- `groupPolicy: "allowlist"` — fail-closed default; only allowed senders are accepted. + +If you are using a different Zalo bot product surface and have verified working group behavior, document that separately rather than assuming it matches the Marketplace-bot flow. + ## Long-polling vs webhook - Default: long-polling (no public URL required). @@ -133,23 +155,36 @@ Multi-account support: use `channels.zalo.accounts` with per-account tokens and ## Supported message types +For a quick support snapshot, see [Capabilities](#capabilities). The notes below add detail where the behavior needs extra context. + - **Text messages**: Full support with 2000 character chunking. -- **Image messages**: Download and process inbound images; send images via `sendPhoto`. -- **Stickers**: Logged but not fully processed (no agent response). -- **Unsupported types**: Logged (e.g., messages from protected users). +- **Plain URLs in text**: Behave like normal text input. +- **Link previews / rich link cards**: See the Marketplace-bot status in [Capabilities](#capabilities); they did not reliably trigger a reply. +- **Image messages**: See the Marketplace-bot status in [Capabilities](#capabilities); inbound image handling was unreliable (typing indicator without a final reply). +- **Stickers**: See the Marketplace-bot status in [Capabilities](#capabilities). +- **Voice notes / audio files / video / generic file attachments**: See the Marketplace-bot status in [Capabilities](#capabilities). +- **Unsupported types**: Logged (for example, messages from protected users). ## Capabilities -| Feature | Status | -| --------------- | -------------------------------------------------------- | -| Direct messages | ✅ Supported | -| Groups | ⚠️ Supported with policy controls (allowlist by default) | -| Media (images) | ✅ Supported | -| Reactions | ❌ Not supported | -| Threads | ❌ Not supported | -| Polls | ❌ Not supported | -| Native commands | ❌ Not supported | -| Streaming | ⚠️ Blocked (2000 char limit) | +This table summarizes current **Zalo Bot Creator / Marketplace bot** behavior in OpenClaw. + +| Feature | Status | +| --------------------------- | --------------------------------------- | +| Direct messages | ✅ Supported | +| Groups | ❌ Not available for Marketplace bots | +| Media (inbound images) | ⚠️ Limited / verify in your environment | +| Media (outbound images) | ⚠️ Not re-tested for Marketplace bots | +| Plain URLs in text | ✅ Supported | +| Link previews | ⚠️ Unreliable for Marketplace bots | +| Reactions | ❌ Not supported | +| Stickers | ⚠️ No agent reply for Marketplace bots | +| Voice notes / audio / video | ⚠️ No agent reply for Marketplace bots | +| File attachments | ⚠️ No agent reply for Marketplace bots | +| Threads | ❌ Not supported | +| Polls | ❌ Not supported | +| Native commands | ❌ Not supported | +| Streaming | ⚠️ Blocked (2000 char limit) | ## Delivery targets (CLI/cron) @@ -175,6 +210,8 @@ Multi-account support: use `channels.zalo.accounts` with per-account tokens and Full configuration: [Configuration](/gateway/configuration) +The flat top-level keys (`channels.zalo.botToken`, `channels.zalo.dmPolicy`, and similar) are a legacy single-account shorthand. Prefer `channels.zalo.accounts..*` for new configs. Both forms are still documented here because they exist in the schema. + Provider options: - `channels.zalo.enabled`: enable/disable channel startup. @@ -182,7 +219,7 @@ Provider options: - `channels.zalo.tokenFile`: read token from a regular file path. Symlinks are rejected. - `channels.zalo.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). - `channels.zalo.allowFrom`: DM allowlist (user IDs). `open` requires `"*"`. The wizard will ask for numeric IDs. -- `channels.zalo.groupPolicy`: `open | allowlist | disabled` (default: allowlist). +- `channels.zalo.groupPolicy`: `open | allowlist | disabled` (default: allowlist). Present in config; see [Capabilities](#capabilities) and [Access control (Groups)](#access-control-groups) for current Marketplace-bot behavior. - `channels.zalo.groupAllowFrom`: group sender allowlist (user IDs). Falls back to `allowFrom` when unset. - `channels.zalo.mediaMaxMb`: inbound/outbound media cap (MB, default 5). - `channels.zalo.webhookUrl`: enable webhook mode (HTTPS required). @@ -198,7 +235,7 @@ Multi-account options: - `channels.zalo.accounts..enabled`: enable/disable account. - `channels.zalo.accounts..dmPolicy`: per-account DM policy. - `channels.zalo.accounts..allowFrom`: per-account allowlist. -- `channels.zalo.accounts..groupPolicy`: per-account group policy. +- `channels.zalo.accounts..groupPolicy`: per-account group policy. Present in config; see [Capabilities](#capabilities) and [Access control (Groups)](#access-control-groups) for current Marketplace-bot behavior. - `channels.zalo.accounts..groupAllowFrom`: per-account group sender allowlist. - `channels.zalo.accounts..webhookUrl`: per-account webhook URL. - `channels.zalo.accounts..webhookSecret`: per-account webhook secret. From a2080421a115d3289dbce88f562b03e6e34c6680 Mon Sep 17 00:00:00 2001 From: Onur Solmaz <2453968+osolmaz@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:42:39 +0100 Subject: [PATCH 08/16] Docs: move release runbook to maintainer repo (#47532) * Docs: redact private release setup * Docs: tighten release order * Docs: move release runbook to maintainer repo * Docs: delete public mac release page * Docs: remove zh-CN mac release page * Docs: turn release checklist into release policy * Docs: point release policy to private docs * Docs: regenerate zh-CN release policy pages * Docs: preserve Doctor in zh-CN hubs * Docs: fix zh-CN polls label * Docs: tighten docs i18n term guardrails * Docs: enforce zh-CN glossary coverage --- AGENTS.md | 44 ++--- docs/.i18n/glossary.zh-CN.json | 16 ++ docs/docs.json | 8 +- docs/platforms/mac/release.md | 90 ---------- docs/reference/RELEASING.md | 169 +++---------------- docs/start/hubs.md | 3 +- docs/zh-CN/AGENTS.md | 4 +- docs/zh-CN/platforms/mac/release.md | 92 ----------- docs/zh-CN/reference/RELEASING.md | 137 ++++------------ docs/zh-CN/start/hubs.md | 25 +-- package.json | 3 +- scripts/check-docs-i18n-glossary.mjs | 237 +++++++++++++++++++++++++++ scripts/docs-i18n/prompt.go | 17 +- 13 files changed, 358 insertions(+), 487 deletions(-) delete mode 100644 docs/platforms/mac/release.md delete mode 100644 docs/zh-CN/platforms/mac/release.md create mode 100644 scripts/check-docs-i18n-glossary.mjs diff --git a/AGENTS.md b/AGENTS.md index 245eedf3d4b..1197f6fb48f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,6 +72,8 @@ - `docs/zh-CN/**` is generated; do not edit unless the user explicitly asks. - Pipeline: update English docs → adjust glossary (`docs/.i18n/glossary.zh-CN.json`) → run `scripts/docs-i18n` → apply targeted fixes only if instructed. +- Before rerunning `scripts/docs-i18n`, add glossary entries for any new technical terms, page titles, or short nav labels that must stay in English or use a fixed translation (for example `Doctor` or `Polls`). +- `pnpm docs:check-i18n-glossary` enforces glossary coverage for changed English doc titles and short internal doc labels before translation reruns. - Translation memory: `docs/.i18n/zh-CN.tm.jsonl` (generated). - See `docs/.i18n/README.md`. - The pipeline can be slow/inefficient; if it’s dragging, ping @jospalmbier on Discord instead of hacking around it. @@ -97,7 +99,7 @@ - Prefer Bun for TypeScript execution (scripts, dev, tests): `bun ` / `bunx `. - Run CLI in dev: `pnpm openclaw ...` (bun) or `pnpm dev`. - Node remains supported for running built output (`dist/*`) and production installs. -- Mac packaging (dev): `scripts/package-mac-app.sh` defaults to current arch. Release checklist: `docs/platforms/mac/release.md`. +- Mac packaging (dev): `scripts/package-mac-app.sh` defaults to current arch. - Type-check/build: `pnpm build` - TypeScript checks: `pnpm tsgo` - Lint/format: `pnpm check` @@ -179,7 +181,7 @@ - Pi sessions live under `~/.openclaw/sessions/` by default; the base directory is not configurable. - Environment variables: see `~/.profile`. - Never commit or publish real phone numbers, videos, or live configuration values. Use obviously fake placeholders in docs, tests, and examples. -- Release flow: always read `docs/reference/RELEASING.md` and `docs/platforms/mac/release.md` before any release work; do not ask routine questions once those docs answer them. +- Release flow: use the private [maintainer release docs](https://github.com/openclaw/maintainers/blob/main/release/README.md) for the actual runbook; use `docs/reference/RELEASING.md` for the public release policy. ## GHSA (Repo Advisory) Patch/Publish @@ -256,14 +258,13 @@ - If shared guardrails are available locally, review them; otherwise follow this repo's guidance. - SwiftUI state management (iOS/macOS): prefer the `Observation` framework (`@Observable`, `@Bindable`) over `ObservableObject`/`@StateObject`; don’t introduce new `ObservableObject` unless required for compatibility, and migrate existing usages when touching related code. - Connection providers: when adding a new connection, update every UI surface and docs (macOS app, web UI, mobile if applicable, onboarding/overview docs) and add matching status + configuration forms so provider lists and settings stay in sync. -- Version locations: `package.json` (CLI), `apps/android/app/build.gradle.kts` (versionName/versionCode), `apps/ios/Sources/Info.plist` + `apps/ios/Tests/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `apps/macos/Sources/OpenClaw/Resources/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `docs/install/updating.md` (pinned npm version), `docs/platforms/mac/release.md` (APP_VERSION/APP_BUILD examples), Peekaboo Xcode projects/Info.plists (MARKETING_VERSION/CURRENT_PROJECT_VERSION). +- Version locations: `package.json` (CLI), `apps/android/app/build.gradle.kts` (versionName/versionCode), `apps/ios/Sources/Info.plist` + `apps/ios/Tests/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `apps/macos/Sources/OpenClaw/Resources/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `docs/install/updating.md` (pinned npm version), and Peekaboo Xcode projects/Info.plists (MARKETING_VERSION/CURRENT_PROJECT_VERSION). - "Bump version everywhere" means all version locations above **except** `appcast.xml` (only touch appcast when cutting a new macOS Sparkle release). - **Restart apps:** “restart iOS/Android apps” means rebuild (recompile/install) and relaunch, not just kill/launch. - **Device checks:** before testing, verify connected real devices (iOS/Android) before reaching for simulators/emulators. - iOS Team ID lookup: `security find-identity -p codesigning -v` → use Apple Development (…) TEAMID. Fallback: `defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers`. - A2UI bundle hash: `src/canvas-host/a2ui/.bundle.hash` is auto-generated; ignore unexpected changes, and only regenerate via `pnpm canvas:a2ui:bundle` (or `scripts/bundle-a2ui.sh`) when needed. Commit the hash as a separate commit. -- Release signing/notary keys are managed outside the repo; follow internal release docs. -- Notary auth env vars (`APP_STORE_CONNECT_ISSUER_ID`, `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_API_KEY_P8`) are expected in your environment (per internal release docs). +- Release signing/notary credentials are managed outside the repo; maintainers keep that setup in the private [maintainer release docs](https://github.com/openclaw/maintainers/tree/main/release). - **Multi-agent safety:** do **not** create/apply/drop `git stash` entries unless explicitly requested (this includes `git pull --rebase --autostash`). Assume other agents may be working; keep unrelated WIP untouched and avoid cross-cutting state changes. - **Multi-agent safety:** when the user says "push", you may `git pull --rebase` to integrate latest changes (never discard other agents' work). When the user says "commit", scope to your changes only. When the user says "commit all", commit everything in grouped chunks. - **Multi-agent safety:** do **not** create/remove/modify `git worktree` checkouts (or edit `.worktrees/*`) unless explicitly requested. @@ -290,35 +291,12 @@ - Release guardrails: do not change version numbers without operator’s explicit consent; always ask permission before running any npm publish/release step. - Beta release guardrail: when using a beta Git tag (for example `vYYYY.M.D-beta.N`), publish npm with a matching beta version suffix (for example `YYYY.M.D-beta.N`) rather than a plain version on `--tag beta`; otherwise the plain version name gets consumed/blocked. -## NPM + 1Password (publish/verify) +## Release Auth -- Use the 1password skill; all `op` commands must run inside a fresh tmux session. -- Correct 1Password path for npm release auth: `op://Private/Npmjs` (use that item; OTP stays `op://Private/Npmjs/one-time password?attribute=otp`). -- Sign in: `eval "$(op signin --account my.1password.com)"` (app unlocked + integration on). -- OTP: `op read 'op://Private/Npmjs/one-time password?attribute=otp'`. -- Publish: `npm publish --access public --otp=""` (run from the package dir). -- Verify without local npmrc side effects: `npm view version --userconfig "$(mktemp)"`. -- Kill the tmux session after publish. - -## Plugin Release Fast Path (no core `openclaw` publish) - -- Release only already-on-npm plugins. Source list is in `docs/reference/RELEASING.md` under "Current npm plugin list". -- Run all CLI `op` calls and `npm publish` inside tmux to avoid hangs/interruption: - - `tmux new -d -s release-plugins-$(date +%Y%m%d-%H%M%S)` - - `eval "$(op signin --account my.1password.com)"` -- 1Password helpers: - - password used by `npm login`: - `op item get Npmjs --format=json | jq -r '.fields[] | select(.id=="password").value'` - - OTP: - `op read 'op://Private/Npmjs/one-time password?attribute=otp'` -- Fast publish loop (local helper script in `/tmp` is fine; keep repo clean): - - compare local plugin `version` to `npm view version` - - only run `npm publish --access public --otp=""` when versions differ - - skip if package is missing on npm or version already matches. -- Keep `openclaw` untouched: never run publish from repo root unless explicitly requested. -- Post-check for each release: - - per-plugin: `npm view @openclaw/ version --userconfig "$(mktemp)"` should be `2026.2.17` - - core guard: `npm view openclaw version --userconfig "$(mktemp)"` should stay at previous version unless explicitly requested. +- Core `openclaw` publish uses GitHub trusted publishing; do not use `NPM_TOKEN` or the plugin OTP flow for core releases. +- Separate `@openclaw/*` plugin publishes use a different maintainer-only auth flow. +- Plugin scope: only publish already-on-npm `@openclaw/*` plugins. Bundled disk-tree-only plugins stay out. +- Maintainers: private 1Password item names, tmux rules, plugin publish helpers, and local mac signing/notary setup live in the private [maintainer release docs](https://github.com/openclaw/maintainers/blob/main/release/README.md). ## Changelog Release Notes diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json index bde108074c2..f8941862b94 100644 --- a/docs/.i18n/glossary.zh-CN.json +++ b/docs/.i18n/glossary.zh-CN.json @@ -123,6 +123,22 @@ "source": "Network model", "target": "网络模型" }, + { + "source": "Doctor", + "target": "Doctor" + }, + { + "source": "Polls", + "target": "投票" + }, + { + "source": "Release Policy", + "target": "发布策略" + }, + { + "source": "Release policy", + "target": "发布策略" + }, { "source": "for full details", "target": "了解详情" diff --git a/docs/docs.json b/docs/docs.json index 98c88e0177c..8855a7335d6 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -469,7 +469,7 @@ }, { "source": "/mac/release", - "destination": "/platforms/mac/release" + "destination": "/reference/RELEASING" }, { "source": "/mac/remote", @@ -1166,7 +1166,6 @@ "platforms/mac/permissions", "platforms/mac/remote", "platforms/mac/signing", - "platforms/mac/release", "platforms/mac/bundled-gateway", "platforms/mac/xpc", "platforms/mac/skills", @@ -1351,7 +1350,7 @@ "pages": ["reference/credits"] }, { - "group": "Release notes", + "group": "Release policy", "pages": ["reference/RELEASING", "reference/test"] }, { @@ -1750,7 +1749,6 @@ "zh-CN/platforms/mac/permissions", "zh-CN/platforms/mac/remote", "zh-CN/platforms/mac/signing", - "zh-CN/platforms/mac/release", "zh-CN/platforms/mac/bundled-gateway", "zh-CN/platforms/mac/xpc", "zh-CN/platforms/mac/skills", @@ -1933,7 +1931,7 @@ "pages": ["zh-CN/reference/credits"] }, { - "group": "发布说明", + "group": "发布策略", "pages": ["zh-CN/reference/RELEASING", "zh-CN/reference/test"] }, { diff --git a/docs/platforms/mac/release.md b/docs/platforms/mac/release.md deleted file mode 100644 index 5276d46848e..00000000000 --- a/docs/platforms/mac/release.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -summary: "OpenClaw macOS release checklist (Sparkle feed, packaging, signing)" -read_when: - - Cutting or validating a OpenClaw macOS release - - Updating the Sparkle appcast or feed assets -title: "macOS Release" ---- - -# OpenClaw macOS release (Sparkle) - -This app now ships Sparkle auto-updates. Release builds must be Developer ID–signed, zipped, and published with a signed appcast entry. - -## Prereqs - -- Developer ID Application cert installed (example: `Developer ID Application: ()`). -- Sparkle private key path set in the environment as `SPARKLE_PRIVATE_KEY_FILE` (path to your Sparkle ed25519 private key; public key baked into Info.plist). If it is missing, check `~/.profile`. -- Notary credentials (keychain profile or API key) for `xcrun notarytool` if you want Gatekeeper-safe DMG/zip distribution. - - We use a Keychain profile named `openclaw-notary`, created from App Store Connect API key env vars in your shell profile: - - `APP_STORE_CONNECT_API_KEY_P8`, `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID` - - `echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/openclaw-notary.p8` - - `xcrun notarytool store-credentials "openclaw-notary" --key /tmp/openclaw-notary.p8 --key-id "$APP_STORE_CONNECT_KEY_ID" --issuer "$APP_STORE_CONNECT_ISSUER_ID"` -- `pnpm` deps installed (`pnpm install --config.node-linker=hoisted`). -- Sparkle tools are fetched automatically via SwiftPM at `apps/macos/.build/artifacts/sparkle/Sparkle/bin/` (`sign_update`, `generate_appcast`, etc.). - -## Build & package - -Notes: - -- `APP_BUILD` maps to `CFBundleVersion`/`sparkle:version`; keep it numeric + monotonic (no `-beta`), or Sparkle compares it as equal. -- If `APP_BUILD` is omitted, `scripts/package-mac-app.sh` derives a Sparkle-safe default from `APP_VERSION` (`YYYYMMDDNN`: stable defaults to `90`, prereleases use a suffix-derived lane) and uses the higher of that value and git commit count. -- You can still override `APP_BUILD` explicitly when release engineering needs a specific monotonic value. -- For `BUILD_CONFIG=release`, `scripts/package-mac-app.sh` now defaults to universal (`arm64 x86_64`) automatically. You can still override with `BUILD_ARCHS=arm64` or `BUILD_ARCHS=x86_64`. For local/dev builds (`BUILD_CONFIG=debug`), it defaults to the current architecture (`$(uname -m)`). -- Use `scripts/package-mac-dist.sh` for release artifacts (zip + DMG + notarization). Use `scripts/package-mac-app.sh` for local/dev packaging. - -```bash -# From repo root; set release IDs so Sparkle feed is enabled. -# This command builds release artifacts without notarization. -# APP_BUILD must be numeric + monotonic for Sparkle compare. -# Default is auto-derived from APP_VERSION when omitted. -SKIP_NOTARIZE=1 \ -BUNDLE_ID=ai.openclaw.mac \ -APP_VERSION=2026.3.13 \ -BUILD_CONFIG=release \ -SIGN_IDENTITY="Developer ID Application: ()" \ -scripts/package-mac-dist.sh - -# `package-mac-dist.sh` already creates the zip + DMG. -# If you used `package-mac-app.sh` directly instead, create them manually: -# If you want notarization/stapling in this step, use the NOTARIZE command below. -ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.3.13.zip - -# Optional: build a styled DMG for humans (drag to /Applications) -scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.3.13.dmg - -# Recommended: build + notarize/staple zip + DMG -# First, create a keychain profile once: -# xcrun notarytool store-credentials "openclaw-notary" \ -# --apple-id "" --team-id "" --password "" -NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \ -BUNDLE_ID=ai.openclaw.mac \ -APP_VERSION=2026.3.13 \ -BUILD_CONFIG=release \ -SIGN_IDENTITY="Developer ID Application: ()" \ -scripts/package-mac-dist.sh - -# Optional: ship dSYM alongside the release -ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.3.13.dSYM.zip -``` - -## Appcast entry - -Use the release note generator so Sparkle renders formatted HTML notes: - -```bash -SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.3.13.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml -``` - -Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry. -Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing. - -## Publish & verify - -- Upload `OpenClaw-2026.3.13.zip` (and `OpenClaw-2026.3.13.dSYM.zip`) to the GitHub release for tag `v2026.3.13`. -- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`. -- Sanity checks: - - `curl -I https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml` returns 200. - - `curl -I ` returns 200 after assets upload. - - On a previous public build, run “Check for Updates…” from the About tab and verify Sparkle installs the new build cleanly. - -Definition of done: signed app + appcast are published, update flow works from an older installed version, and release assets are attached to the GitHub release. diff --git a/docs/reference/RELEASING.md b/docs/reference/RELEASING.md index d94f3866c83..275675c7dba 100644 --- a/docs/reference/RELEASING.md +++ b/docs/reference/RELEASING.md @@ -1,161 +1,42 @@ --- -title: "Release Checklist" -summary: "Step-by-step release checklist for npm + macOS app" +title: "Release Policy" +summary: "Public release channels, version naming, and cadence" read_when: - - Cutting a new npm release - - Cutting a new macOS app release - - Verifying metadata before publishing + - Looking for public release channel definitions + - Looking for version naming and cadence --- -# Release Checklist (npm + macOS) +# Release Policy -Use `pnpm` from the repo root with Node 24 by default. Node 22 LTS, currently `22.16+`, remains supported for compatibility. Keep the working tree clean before tagging/publishing. +OpenClaw has three public release lanes: -## Operator trigger +- stable: tagged releases that publish to npm `latest` +- beta: prerelease tags that publish to npm `beta` +- dev: the moving head of `main` -When the operator says “release”, immediately do this preflight (no extra questions unless blocked): - -- Read this doc and `docs/platforms/mac/release.md`. -- Load env from `~/.profile` and confirm `SPARKLE_PRIVATE_KEY_FILE` + App Store Connect vars are set (SPARKLE_PRIVATE_KEY_FILE should live in `~/.profile`). -- Use Sparkle keys from `~/Library/CloudStorage/Dropbox/Backup/Sparkle` if needed. - -## Versioning - -Current OpenClaw releases use date-based versioning. +## Version naming - Stable release version: `YYYY.M.D` - Git tag: `vYYYY.M.D` - - Examples from repo history: `v2026.2.26`, `v2026.3.8` - Beta prerelease version: `YYYY.M.D-beta.N` - Git tag: `vYYYY.M.D-beta.N` - - Examples from repo history: `v2026.2.15-beta.1`, `v2026.3.8-beta.1` -- Fallback correction tag: `vYYYY.M.D-N` - - Use only as a last-resort recovery tag when a published immutable release burned the original stable tag and you cannot reuse it. - - The npm package version stays `YYYY.M.D`; the `-N` suffix is only for the git tag and GitHub release. - - Prefer betas for normal pre-release iteration, then cut a clean stable tag once ready. -- Use the same version string everywhere, minus the leading `v` where Git tags are not used: - - `package.json`: `2026.3.8` - - Git tag: `v2026.3.8` - - GitHub release title: `openclaw 2026.3.8` -- Do not zero-pad month or day. Use `2026.3.8`, not `2026.03.08`. -- Stable and beta are npm dist-tags, not separate release lines: - - `latest` = stable - - `beta` = prerelease/testing -- Dev is the moving head of `main`, not a normal git-tagged release. -- The tag-triggered preview run accepts stable, beta, and fallback correction tags, and rejects versions whose CalVer date is more than 2 UTC calendar days away from the release date. +- Do not zero-pad month or day +- `latest` means the current stable npm release +- `beta` means the current prerelease npm release +- Beta releases may ship before the macOS app catches up -Historical note: +## Release cadence -- Older tags such as `v2026.1.11-1`, `v2026.2.6-3`, and `v2.0.0-beta2` exist in repo history. -- Treat correction tags as a fallback-only escape hatch. New releases should still use `vYYYY.M.D` for stable and `vYYYY.M.D-beta.N` for beta. +- Releases move beta-first +- Stable follows only after the latest beta is validated +- Detailed release procedure, approvals, credentials, and recovery notes are + maintainer-only -1. **Version & metadata** +## Public references -- [ ] Bump `package.json` version (e.g., `2026.1.29`). -- [ ] Run `pnpm plugins:sync` to align extension package versions + changelogs. -- [ ] Update CLI/version strings in [`src/version.ts`](https://github.com/openclaw/openclaw/blob/main/src/version.ts) and the Baileys user agent in [`src/web/session.ts`](https://github.com/openclaw/openclaw/blob/main/src/web/session.ts). -- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`openclaw.mjs`](https://github.com/openclaw/openclaw/blob/main/openclaw.mjs) for `openclaw`. -- [ ] If dependencies changed, run `pnpm install` so `pnpm-lock.yaml` is current. +- [`.github/workflows/openclaw-npm-release.yml`](https://github.com/openclaw/openclaw/blob/main/.github/workflows/openclaw-npm-release.yml) +- [`scripts/openclaw-npm-release-check.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/openclaw-npm-release-check.ts) -2. **Build & artifacts** - -- [ ] If A2UI inputs changed, run `pnpm canvas:a2ui:bundle` and commit any updated [`src/canvas-host/a2ui/a2ui.bundle.js`](https://github.com/openclaw/openclaw/blob/main/src/canvas-host/a2ui/a2ui.bundle.js). -- [ ] `pnpm run build` (regenerates `dist/`). -- [ ] Verify npm package `files` includes all required `dist/*` folders (notably `dist/node-host/**` and `dist/acp/**` for headless node + ACP CLI). -- [ ] Confirm `dist/build-info.json` exists and includes the expected `commit` hash (CLI banner uses this for npm installs). -- [ ] Optional: `npm pack --pack-destination /tmp` after the build; inspect the tarball contents and keep it handy for the GitHub release (do **not** commit it). - -3. **Changelog & docs** - -- [ ] Update `CHANGELOG.md` with user-facing highlights (create the file if missing); keep entries strictly descending by version. -- [ ] Ensure README examples/flags match current CLI behavior (notably new commands or options). - -4. **Validation** - -- [ ] `pnpm build` -- [ ] `pnpm check` -- [ ] `pnpm test` (or `pnpm test:coverage` if you need coverage output) -- [ ] `pnpm release:check` (verifies npm pack contents) -- [ ] If `pnpm config:docs:check` fails as part of release validation and the config-surface change is intentional, run `pnpm config:docs:gen`, review `docs/.generated/config-baseline.json` and `docs/.generated/config-baseline.jsonl`, commit the updated baselines, then rerun `pnpm release:check`. -- [ ] `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke` (Docker install smoke test, fast path; required before release) - - If the immediate previous npm release is known broken, set `OPENCLAW_INSTALL_SMOKE_PREVIOUS=` or `OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS=1` for the preinstall step. -- [ ] (Optional) Full installer smoke (adds non-root + CLI coverage): `pnpm test:install:smoke` -- [ ] (Optional) Installer E2E (Docker, runs `curl -fsSL https://openclaw.ai/install.sh | bash`, onboards, then runs real tool calls): - - `pnpm test:install:e2e:openai` (requires `OPENAI_API_KEY`) - - `pnpm test:install:e2e:anthropic` (requires `ANTHROPIC_API_KEY`) - - `pnpm test:install:e2e` (requires both keys; runs both providers) -- [ ] (Optional) Spot-check the web gateway if your changes affect send/receive paths. - -5. **macOS app (Sparkle)** - -- [ ] Build + sign the macOS app, then zip it for distribution. -- [ ] Generate the Sparkle appcast (HTML notes via [`scripts/make_appcast.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/make_appcast.sh)) and update `appcast.xml`. -- [ ] Keep the app zip (and optional dSYM zip) ready to attach to the GitHub release. -- [ ] Follow [macOS release](/platforms/mac/release) for the exact commands and required env vars. - - `APP_BUILD` must be numeric + monotonic (no `-beta`) so Sparkle compares versions correctly. - - If notarizing, use the `openclaw-notary` keychain profile created from App Store Connect API env vars (see [macOS release](/platforms/mac/release)). - -6. **Publish (npm)** - -- [ ] Confirm git status is clean; commit and push as needed. -- [ ] Confirm npm trusted publishing is configured for the `openclaw` package. -- [ ] Do not rely on an `NPM_TOKEN` secret for this workflow; the publish job uses GitHub OIDC trusted publishing. -- [ ] Push the matching git tag to trigger the preview run in `.github/workflows/openclaw-npm-release.yml`. -- [ ] Run `OpenClaw NPM Release` manually with the same tag to publish after `npm-release` environment approval. - - Stable tags publish to npm `latest`. - - Beta tags publish to npm `beta`. - - Fallback correction tags like `v2026.3.13-1` map to npm version `2026.3.13`. - - Both the preview run and the manual publish run reject tags that do not map back to `package.json`, are not on `main`, or whose CalVer date is more than 2 UTC calendar days away from the release date. - - If `openclaw@YYYY.M.D` is already published, a fallback correction tag is still useful for GitHub release and Docker recovery, but npm publish will not republish that version. -- [ ] Verify the registry: `npm view openclaw version`, `npm view openclaw dist-tags`, and `npx -y openclaw@X.Y.Z --version` (or `--help`). - -### Troubleshooting (notes from 2.0.0-beta2 release) - -- **npm pack/publish hangs or produces huge tarball**: the macOS app bundle in `dist/OpenClaw.app` (and release zips) get swept into the package. Fix by whitelisting publish contents via `package.json` `files` (include dist subdirs, docs, skills; exclude app bundles). Confirm with `npm pack --dry-run` that `dist/OpenClaw.app` is not listed. -- **npm auth web loop for dist-tags**: use legacy auth to get an OTP prompt: - - `NPM_CONFIG_AUTH_TYPE=legacy npm dist-tag add openclaw@X.Y.Z latest` -- **`npx` verification fails with `ECOMPROMISED: Lock compromised`**: retry with a fresh cache: - - `NPM_CONFIG_CACHE=/tmp/npm-cache-$(date +%s) npx -y openclaw@X.Y.Z --version` -- **Tag needs recovery after a late fix**: if the original stable tag is tied to an immutable GitHub release, mint a fallback correction tag like `vX.Y.Z-1` instead of trying to force-update `vX.Y.Z`. - - Keep the npm package version at `X.Y.Z`; the correction suffix is for the git tag and GitHub release only. - - Use this only as a last resort. For normal iteration, prefer beta tags and then cut a clean stable release. - -7. **GitHub release + appcast** - -- [ ] Tag and push: `git tag vX.Y.Z && git push origin vX.Y.Z` (or `git push --tags`). - - Pushing the tag also triggers the npm release workflow. -- [ ] Create/refresh the GitHub release for `vX.Y.Z` with **title `openclaw X.Y.Z`** (not just the tag); body should include the **full** changelog section for that version (Highlights + Changes + Fixes), inline (no bare links), and **must not repeat the title inside the body**. -- [ ] Attach artifacts: `npm pack` tarball (optional), `OpenClaw-X.Y.Z.zip`, and `OpenClaw-X.Y.Z.dSYM.zip` (if generated). -- [ ] Commit the updated `appcast.xml` and push it (Sparkle feeds from main). -- [ ] From a clean temp directory (no `package.json`), run `npx -y openclaw@X.Y.Z send --help` to confirm install/CLI entrypoints work. -- [ ] Announce/share release notes. - -## Plugin publish scope (npm) - -We only publish **existing npm plugins** under the `@openclaw/*` scope. Bundled -plugins that are not on npm stay **disk-tree only** (still shipped in -`extensions/**`). - -Process to derive the list: - -1. `npm search @openclaw --json` and capture the package names. -2. Compare with `extensions/*/package.json` names. -3. Publish only the **intersection** (already on npm). - -Current npm plugin list (update as needed): - -- @openclaw/bluebubbles -- @openclaw/diagnostics-otel -- @openclaw/discord -- @openclaw/feishu -- @openclaw/lobster -- @openclaw/matrix -- @openclaw/msteams -- @openclaw/nextcloud-talk -- @openclaw/nostr -- @openclaw/voice-call -- @openclaw/zalo -- @openclaw/zalouser - -Release notes must also call out **new optional bundled plugins** that are **not -on by default** (example: `tlon`). +Maintainers use the private release docs in +[`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md) +for the actual runbook. diff --git a/docs/start/hubs.md b/docs/start/hubs.md index cad1e41e114..9833b467378 100644 --- a/docs/start/hubs.md +++ b/docs/start/hubs.md @@ -157,7 +157,6 @@ Use these hubs to discover every page, including deep dives and reference docs t - [macOS permissions](/platforms/mac/permissions) - [macOS remote](/platforms/mac/remote) - [macOS signing](/platforms/mac/signing) -- [macOS release](/platforms/mac/release) - [macOS gateway (launchd)](/platforms/mac/bundled-gateway) - [macOS XPC](/platforms/mac/xpc) - [macOS skills](/platforms/mac/skills) @@ -190,5 +189,5 @@ Use these hubs to discover every page, including deep dives and reference docs t ## Testing + release - [Testing](/reference/test) -- [Release checklist](/reference/RELEASING) +- [Release policy](/reference/RELEASING) - [Device models](/reference/device-models) diff --git a/docs/zh-CN/AGENTS.md b/docs/zh-CN/AGENTS.md index cbf46cc310f..719a3576480 100644 --- a/docs/zh-CN/AGENTS.md +++ b/docs/zh-CN/AGENTS.md @@ -12,7 +12,7 @@ - 目标文档:`docs/zh-CN/**/*.md` - 术语表:`docs/.i18n/glossary.zh-CN.json` - 翻译记忆库:`docs/.i18n/zh-CN.tm.jsonl` -- 提示词规则:`scripts/docs-i18n/translator.go` +- 提示词规则:`scripts/docs-i18n/prompt.go` 常用运行方式: @@ -31,6 +31,8 @@ go run scripts/docs-i18n/main.go -mode segment docs/channels/matrix.md 注意事项: - doc 模式用于整页翻译;segment 模式用于小范围修补(依赖 TM)。 +- 新增技术术语、页面标题或短导航标签时,先更新 `docs/.i18n/glossary.zh-CN.json`,再跑 `doc` 模式;不要指望模型自行保留英文术语或固定译名。 +- `pnpm docs:check-i18n-glossary` 会检查变更过的英文文档标题和短内部链接标签是否已写入 glossary。 - 超大文件若超时,优先做**定点替换**或拆分后再跑。 - 翻译后检查中文引号、CJK-Latin 间距和术语一致性。 diff --git a/docs/zh-CN/platforms/mac/release.md b/docs/zh-CN/platforms/mac/release.md deleted file mode 100644 index d087a2bcb8c..00000000000 --- a/docs/zh-CN/platforms/mac/release.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -read_when: - - 制作或验证 OpenClaw macOS 发布版本 - - 更新 Sparkle appcast 或订阅源资源 -summary: OpenClaw macOS 发布清单(Sparkle 订阅源、打包、签名) -title: macOS 发布 -x-i18n: - generated_at: "2026-02-01T21:33:17Z" - model: claude-opus-4-5 - provider: pi - source_hash: 703c08c13793cd8c96bd4c31fb4904cdf4ffff35576e7ea48a362560d371cb30 - source_path: platforms/mac/release.md - workflow: 15 ---- - -# OpenClaw macOS 发布(Sparkle) - -本应用现已支持 Sparkle 自动更新。发布构建必须经过 Developer ID 签名、压缩,并发布包含签名的 appcast 条目。 - -## 前提条件 - -- 已安装 Developer ID Application 证书(示例:`Developer ID Application: ()`)。 -- 环境变量 `SPARKLE_PRIVATE_KEY_FILE` 已设置为 Sparkle ed25519 私钥路径(公钥已嵌入 Info.plist)。如果缺失,请检查 `~/.profile`。 -- 用于 `xcrun notarytool` 的公证凭据(钥匙串配置文件或 API 密钥),以实现通过 Gatekeeper 安全分发的 DMG/zip。 - - 我们使用名为 `openclaw-notary` 的钥匙串配置文件,由 shell 配置文件中的 App Store Connect API 密钥环境变量创建: - - `APP_STORE_CONNECT_API_KEY_P8`、`APP_STORE_CONNECT_KEY_ID`、`APP_STORE_CONNECT_ISSUER_ID` - - `echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/openclaw-notary.p8` - - `xcrun notarytool store-credentials "openclaw-notary" --key /tmp/openclaw-notary.p8 --key-id "$APP_STORE_CONNECT_KEY_ID" --issuer "$APP_STORE_CONNECT_ISSUER_ID"` -- 已安装 `pnpm` 依赖(`pnpm install --config.node-linker=hoisted`)。 -- Sparkle 工具通过 SwiftPM 自动获取,位于 `apps/macos/.build/artifacts/sparkle/Sparkle/bin/`(`sign_update`、`generate_appcast` 等)。 - -## 构建与打包 - -注意事项: - -- `APP_BUILD` 映射到 `CFBundleVersion`/`sparkle:version`;保持纯数字且单调递增(不含 `-beta`),否则 Sparkle 会将其视为相同版本。 -- 默认为当前架构(`$(uname -m)`)。对于发布/通用构建,设置 `BUILD_ARCHS="arm64 x86_64"`(或 `BUILD_ARCHS=all`)。 -- 使用 `scripts/package-mac-dist.sh` 生成发布产物(zip + DMG + 公证)。使用 `scripts/package-mac-app.sh` 进行本地/开发打包。 - -```bash -# 从仓库根目录运行;设置发布 ID 以启用 Sparkle 订阅源。 -# APP_BUILD 必须为纯数字且单调递增,以便 Sparkle 正确比较。 -BUNDLE_ID=bot.molt.mac \ -APP_VERSION=2026.1.27-beta.1 \ -APP_BUILD="$(git rev-list --count HEAD)" \ -BUILD_CONFIG=release \ -SIGN_IDENTITY="Developer ID Application: ()" \ -scripts/package-mac-app.sh - -# 打包用于分发的 zip(包含资源分支以支持 Sparkle 增量更新) -ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.zip - -# 可选:同时构建适合用户使用的样式化 DMG(拖拽到 /Applications) -scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.dmg - -# 推荐:构建 + 公证/装订 zip + DMG -# 首先,创建一次钥匙串配置文件: -# xcrun notarytool store-credentials "openclaw-notary" \ -# --apple-id "" --team-id "" --password "" -NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \ -BUNDLE_ID=bot.molt.mac \ -APP_VERSION=2026.1.27-beta.1 \ -APP_BUILD="$(git rev-list --count HEAD)" \ -BUILD_CONFIG=release \ -SIGN_IDENTITY="Developer ID Application: ()" \ -scripts/package-mac-dist.sh - -# 可选:随发布一起提供 dSYM -ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.1.27-beta.1.dSYM.zip -``` - -## Appcast 条目 - -使用发布说明生成器,以便 Sparkle 渲染格式化的 HTML 说明: - -```bash -SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.1.27-beta.1.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml -``` - -从 `CHANGELOG.md`(通过 [`scripts/changelog-to-html.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/changelog-to-html.sh))生成 HTML 发布说明,并将其嵌入 appcast 条目。 -发布时,将更新后的 `appcast.xml` 与发布资源(zip + dSYM)一起提交。 - -## 发布与验证 - -- 将 `OpenClaw-2026.1.27-beta.1.zip`(和 `OpenClaw-2026.1.27-beta.1.dSYM.zip`)上传到标签 `v2026.1.27-beta.1` 对应的 GitHub 发布。 -- 确保原始 appcast URL 与内置的订阅源匹配:`https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`。 -- 完整性检查: - - `curl -I https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml` 返回 200。 - - `curl -I ` 在资源上传后返回 200。 - - 在之前的公开构建版本上,从 About 选项卡运行"Check for Updates…",验证 Sparkle 能正常安装新构建。 - -完成定义:已签名的应用 + appcast 已发布,从旧版本的更新流程正常工作,且发布资源已附加到 GitHub 发布。 diff --git a/docs/zh-CN/reference/RELEASING.md b/docs/zh-CN/reference/RELEASING.md index 81b0832f11c..cb1d02f60e8 100644 --- a/docs/zh-CN/reference/RELEASING.md +++ b/docs/zh-CN/reference/RELEASING.md @@ -1,123 +1,48 @@ --- read_when: - - 发布新的 npm 版本 - - 发布新的 macOS 应用版本 - - 发布前验证元数据 -summary: npm + macOS 应用的逐步发布清单 + - 查找公开发布渠道的定义 + - 查找版本命名与发布节奏 +summary: 公开发布渠道、版本命名与发布节奏 +title: 发布策略 x-i18n: - generated_at: "2026-02-03T10:09:28Z" - model: claude-opus-4-5 + generated_at: "2026-03-15T19:23:11Z" + model: claude-opus-4-6 provider: pi - source_hash: 1a684bc26665966eb3c9c816d58d18eead008fd710041181ece38c21c5ff1c62 + source_hash: df332d3169de7099661725d9266955456e80fc3d3ff95cb7aaf9997a02f0baaf source_path: reference/RELEASING.md workflow: 15 --- -# 发布清单(npm + macOS) +# 发布策略 -从仓库根目录使用 `pnpm`(Node 22+)。在打标签/发布前保持工作树干净。 +OpenClaw 有三个公开发布渠道: -## 操作员触发 +- stable:带标签的正式发布,发布到 npm `latest` +- beta:预发布标签,发布到 npm `beta` +- dev:`main` 分支的最新提交 -当操作员说"release"时,立即执行此预检(除非遇到阻碍否则不要额外提问): +## 版本命名 -- 阅读本文档和 `docs/platforms/mac/release.md`。 -- 从 `~/.profile` 加载环境变量并确认 `SPARKLE_PRIVATE_KEY_FILE` + App Store Connect 变量已设置(SPARKLE_PRIVATE_KEY_FILE 应位于 `~/.profile` 中)。 -- 如需要,使用 `~/Library/CloudStorage/Dropbox/Backup/Sparkle` 中的 Sparkle 密钥。 +- 正式发布版本号:`YYYY.M.D` + - Git 标签:`vYYYY.M.D` +- Beta 预发布版本号:`YYYY.M.D-beta.N` + - Git 标签:`vYYYY.M.D-beta.N` +- 月份和日期不补零 +- `latest` 表示当前 npm 正式发布版本 +- `beta` 表示当前 npm 预发布版本 +- Beta 版本可能会在 macOS 应用跟进之前发布 -1. **版本和元数据** +## 发布节奏 -- [ ] 更新 `package.json` 版本(例如 `2026.1.29`)。 -- [ ] 运行 `pnpm plugins:sync` 以对齐扩展包版本和变更日志。 -- [ ] 更新 CLI/版本字符串:[`src/cli/program.ts`](https://github.com/openclaw/openclaw/blob/main/src/cli/program.ts) 和 [`src/provider-web.ts`](https://github.com/openclaw/openclaw/blob/main/src/provider-web.ts) 中的 Baileys user agent。 -- [ ] 确认包元数据(name、description、repository、keywords、license)以及 `bin` 映射指向 [`openclaw.mjs`](https://github.com/openclaw/openclaw/blob/main/openclaw.mjs) 作为 `openclaw`。 -- [ ] 如果依赖项有变化,运行 `pnpm install` 确保 `pnpm-lock.yaml` 是最新的。 +- 发布遵循 beta 优先原则 +- 仅在最新的 beta 版本验证通过后才会发布正式版本 +- 详细的发布流程、审批、凭证和恢复说明仅限维护者查阅 -2. **构建和产物** +## 公开参考 -- [ ] 如果 A2UI 输入有变化,运行 `pnpm canvas:a2ui:bundle` 并提交更新后的 [`src/canvas-host/a2ui/a2ui.bundle.js`](https://github.com/openclaw/openclaw/blob/main/src/canvas-host/a2ui/a2ui.bundle.js)。 -- [ ] `pnpm run build`(重新生成 `dist/`)。 -- [ ] 验证 npm 包的 `files` 包含所有必需的 `dist/*` 文件夹(特别是用于 headless node + ACP CLI 的 `dist/node-host/**` 和 `dist/acp/**`)。 -- [ ] 确认 `dist/build-info.json` 存在并包含预期的 `commit` 哈希(CLI 横幅在 npm 安装时使用此信息)。 -- [ ] 可选:构建后运行 `npm pack --pack-destination /tmp`;检查 tarball 内容并保留以备 GitHub 发布使用(**不要**提交它)。 +- [`.github/workflows/openclaw-npm-release.yml`](https://github.com/openclaw/openclaw/blob/main/.github/workflows/openclaw-npm-release.yml) +- [`scripts/openclaw-npm-release-check.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/openclaw-npm-release-check.ts) -3. **变更日志和文档** - -- [ ] 更新 `CHANGELOG.md`,添加面向用户的亮点(如果文件不存在则创建);按版本严格降序排列条目。 -- [ ] 确保 README 示例/标志与当前 CLI 行为匹配(特别是新命令或选项)。 - -4. **验证** - -- [ ] `pnpm build` -- [ ] `pnpm check` -- [ ] `pnpm test`(如需覆盖率输出则使用 `pnpm test:coverage`) -- [ ] `pnpm release:check`(验证 npm pack 内容) -- [ ] `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke`(Docker 安装冒烟测试,快速路径;发布前必需) - - 如果已知上一个 npm 发布版本有问题,为预安装步骤设置 `OPENCLAW_INSTALL_SMOKE_PREVIOUS=` 或 `OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS=1`。 -- [ ](可选)完整安装程序冒烟测试(添加非 root + CLI 覆盖):`pnpm test:install:smoke` -- [ ](可选)安装程序 E2E(Docker,运行 `curl -fsSL https://openclaw.ai/install.sh | bash`,新手引导,然后运行真实工具调用): - - `pnpm test:install:e2e:openai`(需要 `OPENAI_API_KEY`) - - `pnpm test:install:e2e:anthropic`(需要 `ANTHROPIC_API_KEY`) - - `pnpm test:install:e2e`(需要两个密钥;运行两个提供商) -- [ ](可选)如果你的更改影响发送/接收路径,抽查 Web Gateway 网关。 - -5. **macOS 应用(Sparkle)** - -- [ ] 构建并签名 macOS 应用,然后压缩以供分发。 -- [ ] 生成 Sparkle appcast(通过 [`scripts/make_appcast.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/make_appcast.sh) 生成 HTML 注释)并更新 `appcast.xml`。 -- [ ] 保留应用 zip(和可选的 dSYM zip)以便附加到 GitHub 发布。 -- [ ] 按照 [macOS 发布](/platforms/mac/release) 获取确切命令和所需环境变量。 - - `APP_BUILD` 必须是数字且单调递增(不带 `-beta`),以便 Sparkle 正确比较版本。 - - 如果进行公证,使用从 App Store Connect API 环境变量创建的 `openclaw-notary` 钥匙串配置文件(参见 [macOS 发布](/platforms/mac/release))。 - -6. **发布(npm)** - -- [ ] 确认 git 状态干净;根据需要提交并推送。 -- [ ] 如需要,`npm login`(验证 2FA)。 -- [ ] `npm publish --access public`(预发布版本使用 `--tag beta`)。 -- [ ] 验证注册表:`npm view openclaw version`、`npm view openclaw dist-tags` 和 `npx -y openclaw@X.Y.Z --version`(或 `--help`)。 - -### 故障排除(来自 2.0.0-beta2 发布的笔记) - -- **npm pack/publish 挂起或产生巨大 tarball**:`dist/OpenClaw.app` 中的 macOS 应用包(和发布 zip)被扫入包中。通过 `package.json` 的 `files` 白名单发布内容来修复(包含 dist 子目录、docs、skills;排除应用包)。用 `npm pack --dry-run` 确认 `dist/OpenClaw.app` 未列出。 -- **npm auth dist-tags 的 Web 循环**:使用旧版认证以获取 OTP 提示: - - `NPM_CONFIG_AUTH_TYPE=legacy npm dist-tag add openclaw@X.Y.Z latest` -- **`npx` 验证失败并显示 `ECOMPROMISED: Lock compromised`**:使用新缓存重试: - - `NPM_CONFIG_CACHE=/tmp/npm-cache-$(date +%s) npx -y openclaw@X.Y.Z --version` -- **延迟修复后需要重新指向标签**:强制更新并推送标签,然后确保 GitHub 发布资产仍然匹配: - - `git tag -f vX.Y.Z && git push -f origin vX.Y.Z` - -7. **GitHub 发布 + appcast** - -- [ ] 打标签并推送:`git tag vX.Y.Z && git push origin vX.Y.Z`(或 `git push --tags`)。 -- [ ] 为 `vX.Y.Z` 创建/刷新 GitHub 发布,**标题为 `openclaw X.Y.Z`**(不仅仅是标签);正文应包含该版本的**完整**变更日志部分(亮点 + 更改 + 修复),内联显示(无裸链接),且**不得在正文中重复标题**。 -- [ ] 附加产物:`npm pack` tarball(可选)、`OpenClaw-X.Y.Z.zip` 和 `OpenClaw-X.Y.Z.dSYM.zip`(如果生成)。 -- [ ] 提交更新后的 `appcast.xml` 并推送(Sparkle 从 main 获取源)。 -- [ ] 从干净的临时目录(无 `package.json`),运行 `npx -y openclaw@X.Y.Z send --help` 确认安装/CLI 入口点正常工作。 -- [ ] 宣布/分享发布说明。 - -## 插件发布范围(npm) - -我们只发布 `@openclaw/*` 范围下的**现有 npm 插件**。不在 npm 上的内置插件保持**仅磁盘树**(仍在 `extensions/**` 中发布)。 - -获取列表的流程: - -1. `npm search @openclaw --json` 并捕获包名。 -2. 与 `extensions/*/package.json` 名称比较。 -3. 只发布**交集**(已在 npm 上)。 - -当前 npm 插件列表(根据需要更新): - -- @openclaw/bluebubbles -- @openclaw/diagnostics-otel -- @openclaw/discord -- @openclaw/lobster -- @openclaw/matrix -- @openclaw/msteams -- @openclaw/nextcloud-talk -- @openclaw/nostr -- @openclaw/voice-call -- @openclaw/zalo -- @openclaw/zalouser - -发布说明还必须标注**默认未启用**的**新可选内置插件**(例如:`tlon`)。 +维护者使用 +[`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md) +中的私有发布文档作为实际操作手册。 diff --git a/docs/zh-CN/start/hubs.md b/docs/zh-CN/start/hubs.md index a2e6260fdf2..b303102dcc0 100644 --- a/docs/zh-CN/start/hubs.md +++ b/docs/zh-CN/start/hubs.md @@ -1,20 +1,24 @@ --- read_when: - 你想要一份完整的文档地图 -summary: 链接到每篇 OpenClaw 文档的导航中心 +summary: 链接到所有 OpenClaw 文档的导航中心 title: 文档导航中心 x-i18n: - generated_at: "2026-02-04T17:55:29Z" - model: claude-opus-4-5 + generated_at: "2026-03-15T19:29:16Z" + model: claude-opus-4-6 provider: pi - source_hash: c4b4572b64d36c9690988b8f964b0712f551ee6491b18a493701a17d2d352cb4 + source_hash: e12e8b7881311fdaf08cd297392911dfa30dc46031a7038b6bb9011d166b1669 source_path: start/hubs.md workflow: 15 --- # 文档导航中心 -使用这些导航中心发现每一个页面,包括深入解析和参考文档——它们不一定出现在左侧导航栏中。 + +如果你是 OpenClaw 新用户,请从[入门指南](/start/getting-started)开始。 + + +使用这些导航中心发现每一个页面,包括深入解析和参考文档——它们可能不会出现在左侧导航栏中。 ## 从这里开始 @@ -75,7 +79,6 @@ x-i18n: - [模型提供商中心](/providers/models) - [WhatsApp](/channels/whatsapp) - [Telegram](/channels/telegram) -- [Telegram(grammY 注意事项)](/channels/grammy) - [Slack](/channels/slack) - [Discord](/channels/discord) - [Mattermost](/channels/mattermost)(插件) @@ -113,17 +116,18 @@ x-i18n: - [OpenProse](/prose) - [CLI 参考](/cli) - [Exec 工具](/tools/exec) +- [PDF 工具](/tools/pdf) - [提权模式](/tools/elevated) - [定时任务](/automation/cron-jobs) - [定时任务 vs 心跳](/automation/cron-vs-heartbeat) - [思考 + 详细输出](/tools/thinking) - [模型](/concepts/models) - [子智能体](/tools/subagents) -- [Agent send CLI](/tools/agent-send) +- [智能体发送 CLI](/tools/agent-send) - [终端界面](/web/tui) - [浏览器控制](/tools/browser) - [浏览器(Linux 故障排除)](/tools/browser-linux-troubleshooting) -- [轮询](/automation/poll) +- [投票](/automation/poll) ## 节点、媒体、语音 @@ -160,7 +164,6 @@ x-i18n: - [macOS 权限](/platforms/mac/permissions) - [macOS 远程](/platforms/mac/remote) - [macOS 签名](/platforms/mac/signing) -- [macOS 发布](/platforms/mac/release) - [macOS Gateway 网关 (launchd)](/platforms/mac/bundled-gateway) - [macOS XPC](/platforms/mac/xpc) - [macOS Skills](/platforms/mac/skills) @@ -183,8 +186,6 @@ x-i18n: ## 实验(探索性) - [新手引导配置协议](/experiments/onboarding-config-protocol) -- [定时任务加固笔记](/experiments/plans/cron-add-hardening) -- [群组策略加固笔记](/experiments/plans/group-policy-hardening) - [研究:记忆](/experiments/research/memory) - [模型配置探索](/experiments/proposals/model-config) @@ -195,5 +196,5 @@ x-i18n: ## 测试 + 发布 - [测试](/reference/test) -- [发布检查清单](/reference/RELEASING) +- [发布策略](/reference/RELEASING) - [设备型号](/reference/device-models) diff --git a/package.json b/package.json index 2d880e80fe7..a839cdd3ec1 100644 --- a/package.json +++ b/package.json @@ -231,7 +231,7 @@ "build:strict-smoke": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && pnpm build:plugin-sdk:dts", "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh", "check": "pnpm check:host-env-policy:swift && pnpm format:check && pnpm tsgo && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:plugins:no-monolithic-plugin-sdk-entry-imports && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope", - "check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-links", + "check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-i18n-glossary && pnpm docs:check-links", "check:host-env-policy:swift": "node scripts/generate-host-env-security-policy-swift.mjs --check", "check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500", "config:docs:check": "node --import tsx scripts/generate-config-doc-baseline.ts --check", @@ -246,6 +246,7 @@ "deadcode:ts-unused": "pnpm dlx ts-unused-exports tsconfig.json --ignoreTestFiles --exitWithCount", "dev": "node scripts/run-node.mjs", "docs:bin": "node scripts/build-docs-list.mjs", + "docs:check-i18n-glossary": "node scripts/check-docs-i18n-glossary.mjs", "docs:check-links": "node scripts/docs-link-audit.mjs", "docs:dev": "cd docs && mint dev", "docs:list": "node scripts/docs-list.js", diff --git a/scripts/check-docs-i18n-glossary.mjs b/scripts/check-docs-i18n-glossary.mjs new file mode 100644 index 00000000000..96f890bc4ff --- /dev/null +++ b/scripts/check-docs-i18n-glossary.mjs @@ -0,0 +1,237 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; + +const ROOT = process.cwd(); +const GLOSSARY_PATH = path.join(ROOT, "docs", ".i18n", "glossary.zh-CN.json"); +const DOC_FILE_RE = /^docs\/(?!zh-CN\/).+\.(md|mdx)$/i; +const LIST_ITEM_LINK_RE = /^\s*(?:[-*]|\d+\.)\s+\[([^\]]+)\]\((\/[^)]+)\)/; +const MAX_TITLE_WORDS = 8; +const MAX_LABEL_WORDS = 6; +const MAX_TERM_LENGTH = 80; + +/** + * @typedef {{ + * file: string; + * line: number; + * kind: "title" | "link label"; + * term: string; + * }} TermMatch + */ + +function parseArgs(argv) { + /** @type {{ base: string; head: string }} */ + const args = { base: "", head: "" }; + for (let i = 0; i < argv.length; i += 1) { + if (argv[i] === "--base") { + args.base = argv[i + 1] ?? ""; + i += 1; + continue; + } + if (argv[i] === "--head") { + args.head = argv[i + 1] ?? ""; + i += 1; + } + } + return args; +} + +function runGit(args) { + return execFileSync("git", args, { + cwd: ROOT, + stdio: ["ignore", "pipe", "pipe"], + encoding: "utf8", + }).trim(); +} + +function resolveBase(explicitBase) { + if (explicitBase) { + return explicitBase; + } + + const envBase = process.env.DOCS_I18N_GLOSSARY_BASE?.trim(); + if (envBase) { + return envBase; + } + + for (const candidate of ["origin/main", "fork/main", "main"]) { + try { + return runGit(["merge-base", candidate, "HEAD"]); + } catch { + // Try the next candidate. + } + } + + return ""; +} + +function listChangedDocs(base, head) { + const args = ["diff", "--name-only", "--diff-filter=ACMR", base]; + if (head) { + args.push(head); + } + args.push("--", "docs"); + + return runGit(args) + .split("\n") + .map((line) => line.trim()) + .filter((line) => DOC_FILE_RE.test(line)); +} + +function loadGlossarySources() { + const data = fs.readFileSync(GLOSSARY_PATH, "utf8"); + const entries = JSON.parse(data); + return new Set(entries.map((entry) => String(entry.source || "").trim()).filter(Boolean)); +} + +function containsLatin(text) { + return /[A-Za-z]/.test(text); +} + +function wordCount(text) { + return text.trim().split(/\s+/).filter(Boolean).length; +} + +function unquoteScalar(raw) { + const value = raw.trim(); + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { + return value.slice(1, -1).trim(); + } + return value; +} + +function isGlossaryCandidate(term, maxWords) { + if (!term) { + return false; + } + if (!containsLatin(term)) { + return false; + } + if (term.includes("`")) { + return false; + } + if (term.length > MAX_TERM_LENGTH) { + return false; + } + return wordCount(term) <= maxWords; +} + +function readGitFile(base, relPath) { + try { + return runGit(["show", `${base}:${relPath}`]); + } catch { + return ""; + } +} + +/** + * @param {string} file + * @param {string} text + * @returns {Map} + */ +function extractTerms(file, text) { + /** @type {Map} */ + const terms = new Map(); + const lines = text.split("\n"); + + if (lines[0]?.trim() === "---") { + for (let index = 1; index < lines.length; index += 1) { + const line = lines[index]; + if (line.trim() === "---") { + break; + } + + const match = line.match(/^title:\s*(.+)\s*$/); + if (!match) { + continue; + } + + const title = unquoteScalar(match[1]); + if (isGlossaryCandidate(title, MAX_TITLE_WORDS)) { + terms.set(title, { file, line: index + 1, kind: "title", term: title }); + } + break; + } + } + + for (let index = 0; index < lines.length; index += 1) { + const match = lines[index].match(LIST_ITEM_LINK_RE); + if (!match) { + continue; + } + + const label = match[1].trim(); + if (!isGlossaryCandidate(label, MAX_LABEL_WORDS)) { + continue; + } + + if (!terms.has(label)) { + terms.set(label, { file, line: index + 1, kind: "link label", term: label }); + } + } + + return terms; +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + const base = resolveBase(args.base); + + if (!base) { + console.warn( + "docs:check-i18n-glossary: no merge base found; skipping glossary coverage check.", + ); + process.exit(0); + } + + const changedDocs = listChangedDocs(base, args.head); + if (changedDocs.length === 0) { + process.exit(0); + } + + const glossary = loadGlossarySources(); + /** @type {TermMatch[]} */ + const missing = []; + + for (const relPath of changedDocs) { + const absPath = path.join(ROOT, relPath); + if (!fs.existsSync(absPath)) { + continue; + } + + const currentTerms = extractTerms(relPath, fs.readFileSync(absPath, "utf8")); + const baseTerms = extractTerms(relPath, readGitFile(base, relPath)); + + for (const [term, match] of currentTerms) { + if (baseTerms.has(term)) { + continue; + } + if (glossary.has(term)) { + continue; + } + missing.push(match); + } + } + + if (missing.length === 0) { + process.exit(0); + } + + console.error("docs:check-i18n-glossary: missing zh-CN glossary entries for changed doc labels:"); + for (const match of missing) { + console.error(`- ${match.file}:${match.line} ${match.kind} "${match.term}"`); + } + console.error(""); + console.error( + "Add exact source terms to docs/.i18n/glossary.zh-CN.json before rerunning docs-i18n.", + ); + console.error(`Checked changed English docs relative to ${base}.`); + process.exit(1); +} + +main(); diff --git a/scripts/docs-i18n/prompt.go b/scripts/docs-i18n/prompt.go index 8ecf8688140..773dfd8fcfd 100644 --- a/scripts/docs-i18n/prompt.go +++ b/scripts/docs-i18n/prompt.go @@ -58,6 +58,11 @@ Rules: - Do not remove, reorder, or summarize content. - Use fluent, idiomatic technical Chinese; avoid slang or jokes. - Use neutral documentation tone; prefer “你/你的”, avoid “您/您的”. +- Glossary terms are mandatory. When a source term matches a glossary entry, use + the glossary target exactly, including headings, link labels, and short + UI-style labels. +- If a glossary target is identical to the source text, preserve that term in + English exactly as written. - Insert a space between Latin characters and CJK text (W3C CLREQ), e.g., “Gateway 网关”, “Skills 配置”. - Use Chinese quotation marks “ and ” for Chinese prose; keep ASCII quotes inside code spans/blocks or literal CLI/keys. - Keep product names in English: OpenClaw, Pi, WhatsApp, Telegram, Discord, iMessage, Slack, Microsoft Teams, Google Chat, Signal. @@ -90,6 +95,11 @@ Rules: - Do not remove, reorder, or summarize content. - Use fluent, idiomatic technical Japanese; avoid slang or jokes. - Use neutral documentation tone; avoid overly formal honorifics (e.g., avoid “〜でございます”). +- Glossary terms are mandatory. When a source term matches a glossary entry, use + the glossary target exactly, including headings, link labels, and short + UI-style labels. +- If a glossary target is identical to the source text, preserve that term in + English exactly as written. - Use Japanese quotation marks 「 and 」 for Japanese prose; keep ASCII quotes inside code spans/blocks or literal CLI/keys. - Do not add or remove spacing around Latin text just because it borders Japanese; keep spacing stable unless required by Japanese grammar. - Keep product names in English: OpenClaw, Pi, WhatsApp, Telegram, Discord, iMessage, Slack, Microsoft Teams, Google Chat, Signal. @@ -121,6 +131,11 @@ Rules: - Do not remove, reorder, or summarize content. - Use fluent, idiomatic technical language in the target language; avoid slang or jokes. - Use neutral documentation tone. +- Glossary terms are mandatory. When a source term matches a glossary entry, use + the glossary target exactly, including headings, link labels, and short + UI-style labels. +- If a glossary target is identical to the source text, preserve that term in + English exactly as written. - Keep product names in English: OpenClaw, Pi, WhatsApp, Telegram, Discord, iMessage, Slack, Microsoft Teams, Google Chat, Signal. - Keep these terms in English: Skills, local loopback, Tailscale. - Never output an empty response; if unsure, return the source text unchanged. @@ -135,7 +150,7 @@ func buildGlossaryPrompt(glossary []GlossaryEntry) string { return "" } var lines []string - lines = append(lines, "Preferred translations (use when natural):") + lines = append(lines, "Required terminology (use exactly when the source term matches):") for _, entry := range glossary { if entry.Source == "" || entry.Target == "" { continue From 594920f8cc9693e4b2f8bba2512711ab0f2f201f Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Sun, 15 Mar 2026 16:19:27 -0400 Subject: [PATCH 09/16] Scripts: rebuild on extension and tsdown config changes (#47571) Merged via squash. Prepared head SHA: edd8ed825469128bbe85f86e2e1341f6c57687d7 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras --- CHANGELOG.md | 1 + README.md | 2 +- docs/help/debugging.md | 12 +- docs/start/setup.md | 3 +- scripts/run-node.d.mts | 2 + scripts/run-node.mjs | 127 ++++++++++-- scripts/watch-node.mjs | 28 +-- src/infra/run-node.test.ts | 362 +++++++++++++++++++++++++++++++++++ src/infra/watch-node.test.ts | 41 +++- 9 files changed, 539 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b85cd40bb3..0f77551f4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ Docs: https://docs.openclaw.ai - CLI/auth choice: lazy-load plugin/provider fallback resolution so mapped auth choices stay on the static path and only unknown choices pay the heavy provider load. (#47495) Thanks @vincentkoc. - CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc. - Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse. +- Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) thanks @gumadeiras. ## 2026.3.13 diff --git a/README.md b/README.md index d5a22313f27..fee53d83065 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ pnpm build pnpm openclaw onboard --install-daemon -# Dev loop (auto-reload on TS changes) +# Dev loop (auto-reload on source/config changes) pnpm gateway:watch ``` diff --git a/docs/help/debugging.md b/docs/help/debugging.md index 61539ec39a3..04fd150ef20 100644 --- a/docs/help/debugging.md +++ b/docs/help/debugging.md @@ -40,11 +40,17 @@ pnpm gateway:watch This maps to: ```bash -node --watch-path src --watch-path tsconfig.json --watch-path package.json --watch-preserve-output scripts/run-node.mjs gateway --force +node scripts/watch-node.mjs gateway --force ``` -Add any gateway CLI flags after `gateway:watch` and they will be passed through -on each restart. +The watcher restarts on build-relevant files under `src/`, extension source files, +extension `package.json` and `openclaw.plugin.json` metadata, `tsconfig.json`, +`package.json`, and `tsdown.config.ts`. Extension metadata changes restart the +gateway without forcing a `tsdown` rebuild; source and config changes still +rebuild `dist` first. + +Add any gateway CLI flags after `gateway:watch` and they will be passed through on +each restart. ## Dev profile + dev gateway (--dev) diff --git a/docs/start/setup.md b/docs/start/setup.md index 205f14d20a5..bf127cc0ad0 100644 --- a/docs/start/setup.md +++ b/docs/start/setup.md @@ -96,7 +96,8 @@ pnpm install pnpm gateway:watch ``` -`gateway:watch` runs the gateway in watch mode and reloads on TypeScript changes. +`gateway:watch` runs the gateway in watch mode and reloads on relevant source, +config, and bundled-plugin metadata changes. ### 2) Point the macOS app at your running Gateway diff --git a/scripts/run-node.d.mts b/scripts/run-node.d.mts index 1fc9a1437e0..e86c269d4d3 100644 --- a/scripts/run-node.d.mts +++ b/scripts/run-node.d.mts @@ -1,4 +1,6 @@ export const runNodeWatchedPaths: string[]; +export function isBuildRelevantRunNodePath(repoPath: string): boolean; +export function isRestartRelevantRunNodePath(repoPath: string): boolean; export function runNodeMain(params?: { spawn?: ( diff --git a/scripts/run-node.mjs b/scripts/run-node.mjs index 90e7c137209..0e3acd763b9 100644 --- a/scripts/run-node.mjs +++ b/scripts/run-node.mjs @@ -8,7 +8,63 @@ import { pathToFileURL } from "node:url"; const compiler = "tsdown"; const compilerArgs = ["exec", compiler, "--no-clean"]; -export const runNodeWatchedPaths = ["src", "tsconfig.json", "package.json"]; +const runNodeSourceRoots = ["src", "extensions"]; +const runNodeConfigFiles = ["tsconfig.json", "package.json", "tsdown.config.ts"]; +export const runNodeWatchedPaths = [...runNodeSourceRoots, ...runNodeConfigFiles]; +const extensionSourceFilePattern = /\.(?:[cm]?[jt]sx?)$/; +const extensionRestartMetadataFiles = new Set(["openclaw.plugin.json", "package.json"]); + +const normalizePath = (filePath) => String(filePath ?? "").replaceAll("\\", "/"); + +const isIgnoredSourcePath = (relativePath) => { + const normalizedPath = normalizePath(relativePath); + return ( + normalizedPath.endsWith(".test.ts") || + normalizedPath.endsWith(".test.tsx") || + normalizedPath.endsWith("test-helpers.ts") + ); +}; + +const isBuildRelevantSourcePath = (relativePath) => { + const normalizedPath = normalizePath(relativePath); + return extensionSourceFilePattern.test(normalizedPath) && !isIgnoredSourcePath(normalizedPath); +}; + +export const isBuildRelevantRunNodePath = (repoPath) => { + const normalizedPath = normalizePath(repoPath).replace(/^\.\/+/, ""); + if (runNodeConfigFiles.includes(normalizedPath)) { + return true; + } + if (normalizedPath.startsWith("src/")) { + return !isIgnoredSourcePath(normalizedPath.slice("src/".length)); + } + if (normalizedPath.startsWith("extensions/")) { + return isBuildRelevantSourcePath(normalizedPath.slice("extensions/".length)); + } + return false; +}; + +const isRestartRelevantExtensionPath = (relativePath) => { + const normalizedPath = normalizePath(relativePath); + if (extensionRestartMetadataFiles.has(path.posix.basename(normalizedPath))) { + return true; + } + return isBuildRelevantSourcePath(normalizedPath); +}; + +export const isRestartRelevantRunNodePath = (repoPath) => { + const normalizedPath = normalizePath(repoPath).replace(/^\.\/+/, ""); + if (runNodeConfigFiles.includes(normalizedPath)) { + return true; + } + if (normalizedPath.startsWith("src/")) { + return !isIgnoredSourcePath(normalizedPath.slice("src/".length)); + } + if (normalizedPath.startsWith("extensions/")) { + return isRestartRelevantExtensionPath(normalizedPath.slice("extensions/".length)); + } + return false; +}; const statMtime = (filePath, fsImpl = fs) => { try { @@ -18,16 +74,12 @@ const statMtime = (filePath, fsImpl = fs) => { } }; -const isExcludedSource = (filePath, srcRoot) => { - const relativePath = path.relative(srcRoot, filePath); +const isExcludedSource = (filePath, sourceRoot, sourceRootName) => { + const relativePath = normalizePath(path.relative(sourceRoot, filePath)); if (relativePath.startsWith("..")) { return false; } - return ( - relativePath.endsWith(".test.ts") || - relativePath.endsWith(".test.tsx") || - relativePath.endsWith(`test-helpers.ts`) - ); + return !isBuildRelevantRunNodePath(path.posix.join(sourceRootName, relativePath)); }; const findLatestMtime = (dirPath, shouldSkip, deps) => { @@ -89,15 +141,39 @@ const resolveGitHead = (deps) => { return head || null; }; +const readGitStatus = (deps) => { + try { + const result = deps.spawnSync( + "git", + ["status", "--porcelain", "--untracked-files=normal", "--", ...runNodeWatchedPaths], + { + cwd: deps.cwd, + encoding: "utf8", + stdio: ["ignore", "pipe", "ignore"], + }, + ); + if (result.status !== 0) { + return null; + } + return result.stdout ?? ""; + } catch { + return null; + } +}; + +const parseGitStatusPaths = (output) => + output + .split("\n") + .flatMap((line) => line.slice(3).split(" -> ")) + .map((entry) => normalizePath(entry.trim())) + .filter(Boolean); + const hasDirtySourceTree = (deps) => { - const output = runGit( - ["status", "--porcelain", "--untracked-files=normal", "--", ...runNodeWatchedPaths], - deps, - ); + const output = readGitStatus(deps); if (output === null) { return null; } - return output.length > 0; + return parseGitStatusPaths(output).some((repoPath) => isBuildRelevantRunNodePath(repoPath)); }; const readBuildStamp = (deps) => { @@ -119,12 +195,18 @@ const readBuildStamp = (deps) => { }; const hasSourceMtimeChanged = (stampMtime, deps) => { - const srcMtime = findLatestMtime( - deps.srcRoot, - (candidate) => isExcludedSource(candidate, deps.srcRoot), - deps, - ); - return srcMtime != null && srcMtime > stampMtime; + let latestSourceMtime = null; + for (const sourceRoot of deps.sourceRoots) { + const sourceMtime = findLatestMtime( + sourceRoot.path, + (candidate) => isExcludedSource(candidate, sourceRoot.path, sourceRoot.name), + deps, + ); + if (sourceMtime != null && (latestSourceMtime == null || sourceMtime > latestSourceMtime)) { + latestSourceMtime = sourceMtime; + } + } + return latestSourceMtime != null && latestSourceMtime > stampMtime; }; const shouldBuild = (deps) => { @@ -223,8 +305,11 @@ export async function runNodeMain(params = {}) { deps.distRoot = path.join(deps.cwd, "dist"); deps.distEntry = path.join(deps.distRoot, "/entry.js"); deps.buildStampPath = path.join(deps.distRoot, ".buildstamp"); - deps.srcRoot = path.join(deps.cwd, "src"); - deps.configFiles = [path.join(deps.cwd, "tsconfig.json"), path.join(deps.cwd, "package.json")]; + deps.sourceRoots = runNodeSourceRoots.map((sourceRoot) => ({ + name: sourceRoot, + path: path.join(deps.cwd, sourceRoot), + })); + deps.configFiles = runNodeConfigFiles.map((filePath) => path.join(deps.cwd, filePath)); if (!shouldBuild(deps)) { return await runOpenClaw(deps); diff --git a/scripts/watch-node.mjs b/scripts/watch-node.mjs index 891e07439a1..e4598ae79fe 100644 --- a/scripts/watch-node.mjs +++ b/scripts/watch-node.mjs @@ -1,26 +1,32 @@ #!/usr/bin/env node import { spawn } from "node:child_process"; +import path from "node:path"; import process from "node:process"; import { pathToFileURL } from "node:url"; import chokidar from "chokidar"; -import { runNodeWatchedPaths } from "./run-node.mjs"; +import { isRestartRelevantRunNodePath, runNodeWatchedPaths } from "./run-node.mjs"; const WATCH_NODE_RUNNER = "scripts/run-node.mjs"; const WATCH_RESTART_SIGNAL = "SIGTERM"; const buildRunnerArgs = (args) => [WATCH_NODE_RUNNER, ...args]; -const normalizePath = (filePath) => String(filePath ?? "").replaceAll("\\", "/"); +const normalizePath = (filePath) => + String(filePath ?? "") + .replaceAll("\\", "/") + .replace(/^\.\/+/, ""); -const isIgnoredWatchPath = (filePath) => { - const normalizedPath = normalizePath(filePath); - return ( - normalizedPath.endsWith(".test.ts") || - normalizedPath.endsWith(".test.tsx") || - normalizedPath.endsWith("test-helpers.ts") - ); +const resolveRepoPath = (filePath, cwd) => { + const rawPath = String(filePath ?? ""); + if (path.isAbsolute(rawPath)) { + return normalizePath(path.relative(cwd, rawPath)); + } + return normalizePath(rawPath); }; +const isIgnoredWatchPath = (filePath, cwd) => + !isRestartRelevantRunNodePath(resolveRepoPath(filePath, cwd)); + export async function runWatchMain(params = {}) { const deps = { spawn: params.spawn ?? spawn, @@ -52,7 +58,7 @@ export async function runWatchMain(params = {}) { const watcher = deps.createWatcher(deps.watchPaths, { ignoreInitial: true, - ignored: (watchPath) => isIgnoredWatchPath(watchPath), + ignored: (watchPath) => isIgnoredWatchPath(watchPath, deps.cwd), }); const settle = (code) => { @@ -89,7 +95,7 @@ export async function runWatchMain(params = {}) { }; const requestRestart = (changedPath) => { - if (shuttingDown || isIgnoredWatchPath(changedPath)) { + if (shuttingDown || isIgnoredWatchPath(changedPath, deps.cwd)) { return; } if (!watchProcess) { diff --git a/src/infra/run-node.test.ts b/src/infra/run-node.test.ts index 0b8cf1090bc..7ba07fdaf2d 100644 --- a/src/infra/run-node.test.ts +++ b/src/infra/run-node.test.ts @@ -24,6 +24,12 @@ function createExitedProcess(code: number | null, signal: string | null = null) }; } +function expectedBuildSpawn(platform: NodeJS.Platform = process.platform) { + return platform === "win32" + ? ["cmd.exe", "/d", "/s", "/c", "pnpm", "exec", "tsdown", "--no-clean"] + : ["pnpm", "exec", "tsdown", "--no-clean"]; +} + describe("run-node script", () => { it.runIf(process.platform !== "win32")( "preserves control-ui assets by building with tsdown --no-clean", @@ -161,4 +167,360 @@ describe("run-node script", () => { expect(exitCode).toBe(23); }); }); + + it("rebuilds when extension sources are newer than the build stamp", async () => { + await withTempDir(async (tmp) => { + const extensionPath = path.join(tmp, "extensions", "demo", "src", "index.ts"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + await fs.mkdir(path.dirname(extensionPath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(extensionPath, "export const extensionValue = 1;\n", "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + const newTime = new Date("2026-03-13T12:00:01.000Z"); + await fs.utimes(tsconfigPath, stampTime, stampTime); + await fs.utimes(packageJsonPath, stampTime, stampTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + await fs.utimes(extensionPath, newTime, newTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = () => ({ status: 1, stdout: "" }); + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([ + expectedBuildSpawn(), + [process.execPath, "openclaw.mjs", "status"], + ]); + }); + }); + + it("skips rebuilding when extension package metadata is newer than the build stamp", async () => { + await withTempDir(async (tmp) => { + const packagePath = path.join(tmp, "extensions", "demo", "package.json"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await fs.mkdir(path.dirname(packagePath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile( + packagePath, + '{"name":"demo","openclaw":{"extensions":["./index.ts"]}}\n', + "utf-8", + ); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const oldTime = new Date("2026-03-13T10:00:00.000Z"); + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + const newTime = new Date("2026-03-13T12:00:01.000Z"); + await fs.utimes(tsconfigPath, oldTime, oldTime); + await fs.utimes(packageJsonPath, oldTime, oldTime); + await fs.utimes(tsdownConfigPath, oldTime, oldTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + await fs.utimes(packagePath, newTime, newTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = () => ({ status: 1, stdout: "" }); + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + }); + }); + + it("skips rebuilding for dirty non-source files under extensions", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const readmePath = path.join(tmp, "extensions", "demo", "README.md"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(path.dirname(readmePath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(readmePath, "# demo\n", "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + await fs.utimes(srcPath, stampTime, stampTime); + await fs.utimes(readmePath, stampTime, stampTime); + await fs.utimes(tsconfigPath, stampTime, stampTime); + await fs.utimes(packageJsonPath, stampTime, stampTime); + await fs.utimes(tsdownConfigPath, stampTime, stampTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = (cmd: string, args: string[]) => { + if (cmd === "git" && args[0] === "rev-parse") { + return { status: 0, stdout: "abc123\n" }; + } + if (cmd === "git" && args[0] === "status") { + return { status: 0, stdout: " M extensions/demo/README.md\n" }; + } + return { status: 1, stdout: "" }; + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + }); + }); + + it("skips rebuilding for dirty extension manifests that only affect runtime reload", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const manifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(path.dirname(manifestPath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(manifestPath, '{"id":"demo"}\n', "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + await fs.utimes(srcPath, stampTime, stampTime); + await fs.utimes(manifestPath, stampTime, stampTime); + await fs.utimes(tsconfigPath, stampTime, stampTime); + await fs.utimes(packageJsonPath, stampTime, stampTime); + await fs.utimes(tsdownConfigPath, stampTime, stampTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = (cmd: string, args: string[]) => { + if (cmd === "git" && args[0] === "rev-parse") { + return { status: 0, stdout: "abc123\n" }; + } + if (cmd === "git" && args[0] === "status") { + return { status: 0, stdout: " M extensions/demo/openclaw.plugin.json\n" }; + } + return { status: 1, stdout: "" }; + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + }); + }); + + it("skips rebuilding when only non-source extension files are newer than the build stamp", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const readmePath = path.join(tmp, "extensions", "demo", "README.md"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(path.dirname(readmePath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(readmePath, "# demo\n", "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const oldTime = new Date("2026-03-13T10:00:00.000Z"); + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + const newTime = new Date("2026-03-13T12:00:01.000Z"); + await fs.utimes(srcPath, oldTime, oldTime); + await fs.utimes(tsconfigPath, oldTime, oldTime); + await fs.utimes(packageJsonPath, oldTime, oldTime); + await fs.utimes(tsdownConfigPath, oldTime, oldTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + await fs.utimes(readmePath, newTime, newTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = () => ({ status: 1, stdout: "" }); + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + }); + }); + + it("rebuilds when tsdown config is newer than the build stamp", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const oldTime = new Date("2026-03-13T10:00:00.000Z"); + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + const newTime = new Date("2026-03-13T12:00:01.000Z"); + await fs.utimes(srcPath, oldTime, oldTime); + await fs.utimes(tsconfigPath, oldTime, oldTime); + await fs.utimes(packageJsonPath, oldTime, oldTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + await fs.utimes(tsdownConfigPath, newTime, newTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = (cmd: string, args: string[]) => { + if (cmd === "git" && args[0] === "rev-parse") { + return { status: 0, stdout: "abc123\n" }; + } + if (cmd === "git" && args[0] === "status") { + return { status: 0, stdout: "" }; + } + return { status: 1, stdout: "" }; + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([ + expectedBuildSpawn(), + [process.execPath, "openclaw.mjs", "status"], + ]); + }); + }); }); diff --git a/src/infra/watch-node.test.ts b/src/infra/watch-node.test.ts index 89ec4b79ef2..8fa92bae1df 100644 --- a/src/infra/watch-node.test.ts +++ b/src/infra/watch-node.test.ts @@ -44,10 +44,17 @@ describe("watch-node script", () => { { ignoreInitial: boolean; ignored: (watchPath: string) => boolean }, ]; expect(watchPaths).toEqual(runNodeWatchedPaths); + expect(watchPaths).toContain("extensions"); + expect(watchPaths).toContain("tsdown.config.ts"); expect(watchOptions.ignoreInitial).toBe(true); expect(watchOptions.ignored("src/infra/watch-node.test.ts")).toBe(true); expect(watchOptions.ignored("src/infra/watch-node.test.tsx")).toBe(true); expect(watchOptions.ignored("src/infra/watch-node-test-helpers.ts")).toBe(true); + expect(watchOptions.ignored("extensions/voice-call/README.md")).toBe(true); + expect(watchOptions.ignored("extensions/voice-call/openclaw.plugin.json")).toBe(false); + expect(watchOptions.ignored("extensions/voice-call/package.json")).toBe(false); + expect(watchOptions.ignored("extensions/voice-call/index.ts")).toBe(false); + expect(watchOptions.ignored("extensions/voice-call/src/runtime.ts")).toBe(false); expect(watchOptions.ignored("src/infra/watch-node.ts")).toBe(false); expect(watchOptions.ignored("tsconfig.json")).toBe(false); @@ -120,9 +127,24 @@ describe("watch-node script", () => { }), }); const childB = Object.assign(new EventEmitter(), { + kill: vi.fn(function () { + queueMicrotask(() => childB.emit("exit", 0, null)); + }), + }); + const childC = Object.assign(new EventEmitter(), { + kill: vi.fn(function () { + queueMicrotask(() => childC.emit("exit", 0, null)); + }), + }); + const childD = Object.assign(new EventEmitter(), { kill: vi.fn(() => {}), }); - const spawn = vi.fn().mockReturnValueOnce(childA).mockReturnValueOnce(childB); + const spawn = vi + .fn() + .mockReturnValueOnce(childA) + .mockReturnValueOnce(childB) + .mockReturnValueOnce(childC) + .mockReturnValueOnce(childD); const watcher = Object.assign(new EventEmitter(), { close: vi.fn(async () => {}), }); @@ -151,11 +173,26 @@ describe("watch-node script", () => { expect(spawn).toHaveBeenCalledTimes(1); expect(childA.kill).not.toHaveBeenCalled(); - watcher.emit("change", "src/infra/watch-node.ts"); + watcher.emit("change", "extensions/voice-call/README.md"); + await new Promise((resolve) => setImmediate(resolve)); + expect(spawn).toHaveBeenCalledTimes(1); + expect(childA.kill).not.toHaveBeenCalled(); + + watcher.emit("change", "extensions/voice-call/openclaw.plugin.json"); await new Promise((resolve) => setImmediate(resolve)); expect(childA.kill).toHaveBeenCalledWith("SIGTERM"); expect(spawn).toHaveBeenCalledTimes(2); + watcher.emit("change", "extensions/voice-call/package.json"); + await new Promise((resolve) => setImmediate(resolve)); + expect(childB.kill).toHaveBeenCalledWith("SIGTERM"); + expect(spawn).toHaveBeenCalledTimes(3); + + watcher.emit("change", "src/infra/watch-node.ts"); + await new Promise((resolve) => setImmediate(resolve)); + expect(childC.kill).toHaveBeenCalledWith("SIGTERM"); + expect(spawn).toHaveBeenCalledTimes(4); + fakeProcess.emit("SIGINT"); const exitCode = await runPromise; expect(exitCode).toBe(130); From 07f890fa45bc782fab594fdfc77505aca6ea4c4b Mon Sep 17 00:00:00 2001 From: Ted Li Date: Sun, 15 Mar 2026 13:31:30 -0700 Subject: [PATCH 10/16] fix(release): block oversized npm packs that regress low-memory startup (#46850) * fix(release): guard npm pack size regressions * fix(release): fail closed when npm omits pack size --- scripts/release-check.ts | 59 ++++++++++++++++++++++++++++++++++++-- test/release-check.test.ts | 32 +++++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/scripts/release-check.ts b/scripts/release-check.ts index 6f621cef2d5..34d37634d6f 100755 --- a/scripts/release-check.ts +++ b/scripts/release-check.ts @@ -15,7 +15,7 @@ import { sparkleBuildFloorsFromShortVersion, type SparkleBuildFloors } from "./s export { collectBundledExtensionManifestErrors } from "./lib/bundled-extension-manifest.ts"; type PackFile = { path: string }; -type PackResult = { files?: PackFile[] }; +type PackResult = { files?: PackFile[]; filename?: string; unpackedSize?: number }; const requiredPathGroups = [ ["dist/index.js", "dist/index.mjs"], @@ -112,6 +112,10 @@ const requiredPathGroups = [ "dist/build-info.json", ]; const forbiddenPrefixes = ["dist/OpenClaw.app/"]; +// 2026.3.12 ballooned to ~213.6 MiB unpacked and correlated with low-memory +// startup/doctor OOM reports. Keep enough headroom for the current pack while +// failing fast if duplicate/shim content sneaks back into the release artifact. +const npmPackUnpackedSizeBudgetBytes = 160 * 1024 * 1024; const appcastPath = resolve("appcast.xml"); const laneBuildMin = 1_000_000_000; const laneFloorAdoptionDateKey = 20260227; @@ -228,6 +232,50 @@ export function collectForbiddenPackPaths(paths: Iterable): string[] { .toSorted(); } +function formatMiB(bytes: number): string { + return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`; +} + +function resolvePackResultLabel(entry: PackResult, index: number): string { + return entry.filename?.trim() || `pack result #${index + 1}`; +} + +function formatPackUnpackedSizeBudgetError(params: { + label: string; + unpackedSize: number; +}): string { + return [ + `${params.label} unpackedSize ${params.unpackedSize} bytes (${formatMiB(params.unpackedSize)}) exceeds budget ${npmPackUnpackedSizeBudgetBytes} bytes (${formatMiB(npmPackUnpackedSizeBudgetBytes)}).`, + "Investigate duplicate channel shims, copied extension trees, or other accidental pack bloat before release.", + ].join(" "); +} + +export function collectPackUnpackedSizeErrors(results: Iterable): string[] { + const entries = Array.from(results); + const errors: string[] = []; + let checkedCount = 0; + + for (const [index, entry] of entries.entries()) { + if (typeof entry.unpackedSize !== "number" || !Number.isFinite(entry.unpackedSize)) { + continue; + } + checkedCount += 1; + if (entry.unpackedSize <= npmPackUnpackedSizeBudgetBytes) { + continue; + } + const label = resolvePackResultLabel(entry, index); + errors.push(formatPackUnpackedSizeBudgetError({ label, unpackedSize: entry.unpackedSize })); + } + + if (entries.length > 0 && checkedCount === 0) { + errors.push( + "npm pack --dry-run produced no unpackedSize data; pack size budget was not verified.", + ); + } + + return errors; +} + function checkPluginVersions() { const rootPackagePath = resolve("package.json"); const rootPackage = JSON.parse(readFileSync(rootPackagePath, "utf8")) as PackageJson; @@ -433,8 +481,9 @@ function main() { }) .toSorted(); const forbidden = collectForbiddenPackPaths(paths); + const sizeErrors = collectPackUnpackedSizeErrors(results); - if (missing.length > 0 || forbidden.length > 0) { + if (missing.length > 0 || forbidden.length > 0 || sizeErrors.length > 0) { if (missing.length > 0) { console.error("release-check: missing files in npm pack:"); for (const path of missing) { @@ -447,6 +496,12 @@ function main() { console.error(` - ${path}`); } } + if (sizeErrors.length > 0) { + console.error("release-check: npm pack unpacked size budget exceeded:"); + for (const error of sizeErrors) { + console.error(` - ${error}`); + } + } process.exit(1); } diff --git a/test/release-check.test.ts b/test/release-check.test.ts index a399407aa98..5f0bcf65192 100644 --- a/test/release-check.test.ts +++ b/test/release-check.test.ts @@ -4,12 +4,17 @@ import { collectBundledExtensionManifestErrors, collectBundledExtensionRootDependencyGapErrors, collectForbiddenPackPaths, + collectPackUnpackedSizeErrors, } from "../scripts/release-check.ts"; function makeItem(shortVersion: string, sparkleVersion: string): string { return `${shortVersion}${shortVersion}${sparkleVersion}`; } +function makePackResult(filename: string, unpackedSize: number) { + return { filename, unpackedSize }; +} + describe("collectAppcastSparkleVersionErrors", () => { it("accepts legacy 9-digit calver builds before lane-floor cutover", () => { const xml = `${makeItem("2026.2.26", "202602260")}`; @@ -163,3 +168,30 @@ describe("collectForbiddenPackPaths", () => { ).toEqual(["extensions/tlon/node_modules/.bin/tlon", "node_modules/.bin/openclaw"]); }); }); + +describe("collectPackUnpackedSizeErrors", () => { + it("accepts pack results within the unpacked size budget", () => { + expect( + collectPackUnpackedSizeErrors([makePackResult("openclaw-2026.3.14.tgz", 120_354_302)]), + ).toEqual([]); + }); + + it("flags oversized pack results that risk low-memory startup failures", () => { + expect( + collectPackUnpackedSizeErrors([makePackResult("openclaw-2026.3.12.tgz", 224_002_564)]), + ).toEqual([ + "openclaw-2026.3.12.tgz unpackedSize 224002564 bytes (213.6 MiB) exceeds budget 167772160 bytes (160.0 MiB). Investigate duplicate channel shims, copied extension trees, or other accidental pack bloat before release.", + ]); + }); + + it("fails closed when npm pack output omits unpackedSize for every result", () => { + expect( + collectPackUnpackedSizeErrors([ + { filename: "openclaw-2026.3.14.tgz" }, + { filename: "openclaw-extra.tgz", unpackedSize: Number.NaN }, + ]), + ).toEqual([ + "npm pack --dry-run produced no unpackedSize data; pack size budget was not verified.", + ]); + }); +}); From 85dd0ab2f8472932a886734cb2520e1f091e0d52 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 13:33:37 -0700 Subject: [PATCH 11/16] Plugins: reserve context engine ownership (#47595) * Plugins: reserve context engine ownership * Update src/context-engine/registry.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- src/context-engine/context-engine.test.ts | 24 +++++++-- src/context-engine/registry.ts | 38 ++++++++++--- src/plugins/loader.test.ts | 65 +++++++++++++++++++++++ src/plugins/registry.ts | 22 +++++++- 4 files changed, 137 insertions(+), 12 deletions(-) diff --git a/src/context-engine/context-engine.test.ts b/src/context-engine/context-engine.test.ts index cd0f2f50439..5cdc03a7114 100644 --- a/src/context-engine/context-engine.test.ts +++ b/src/context-engine/context-engine.test.ts @@ -231,18 +231,36 @@ describe("Registry tests", () => { expect(Array.isArray(ids)).toBe(true); }); - it("registering the same id overwrites the previous factory", () => { + it("registering the same id with the same owner refreshes the factory", () => { const factory1 = () => new MockContextEngine(); const factory2 = () => new MockContextEngine(); - registerContextEngine("reg-overwrite", factory1); + expect(registerContextEngine("reg-overwrite", factory1, { owner: "owner-a" })).toEqual({ + ok: true, + }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory1); - registerContextEngine("reg-overwrite", factory2); + expect(registerContextEngine("reg-overwrite", factory2, { owner: "owner-a" })).toEqual({ + ok: true, + }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory2); expect(getContextEngineFactory("reg-overwrite")).not.toBe(factory1); }); + it("rejects context engine registrations from a different owner", () => { + const factory1 = () => new MockContextEngine(); + const factory2 = () => new MockContextEngine(); + + expect(registerContextEngine("reg-owner-guard", factory1, { owner: "owner-a" })).toEqual({ + ok: true, + }); + expect(registerContextEngine("reg-owner-guard", factory2, { owner: "owner-b" })).toEqual({ + ok: false, + existingOwner: "owner-a", + }); + expect(getContextEngineFactory("reg-owner-guard")).toBe(factory1); + }); + it("shares registered engines across duplicate module copies", async () => { const registryUrl = new URL("./registry.ts", import.meta.url).href; const suffix = Date.now().toString(36); diff --git a/src/context-engine/registry.ts b/src/context-engine/registry.ts index d73266c62de..ba04da7c51d 100644 --- a/src/context-engine/registry.ts +++ b/src/context-engine/registry.ts @@ -7,6 +7,7 @@ import type { ContextEngine } from "./types.js"; * Supports async creation for engines that need DB connections etc. */ export type ContextEngineFactory = () => ContextEngine | Promise; +export type ContextEngineRegistrationResult = { ok: true } | { ok: false; existingOwner: string }; // --------------------------------------------------------------------------- // Registry (module-level singleton) @@ -15,7 +16,13 @@ export type ContextEngineFactory = () => ContextEngine | Promise; const CONTEXT_ENGINE_REGISTRY_STATE = Symbol.for("openclaw.contextEngineRegistryState"); type ContextEngineRegistryState = { - engines: Map; + engines: Map< + string, + { + factory: ContextEngineFactory; + owner: string; + } + >; }; // Keep context-engine registrations process-global so duplicated dist chunks @@ -26,7 +33,7 @@ function getContextEngineRegistryState(): ContextEngineRegistryState { }; if (!globalState[CONTEXT_ENGINE_REGISTRY_STATE]) { globalState[CONTEXT_ENGINE_REGISTRY_STATE] = { - engines: new Map(), + engines: new Map(), }; } return globalState[CONTEXT_ENGINE_REGISTRY_STATE]; @@ -35,15 +42,30 @@ function getContextEngineRegistryState(): ContextEngineRegistryState { /** * Register a context engine implementation under the given id. */ -export function registerContextEngine(id: string, factory: ContextEngineFactory): void { - getContextEngineRegistryState().engines.set(id, factory); +export function registerContextEngine( + id: string, + factory: ContextEngineFactory, + opts?: { owner?: string }, +): ContextEngineRegistrationResult { + const rawOwner = opts?.owner?.trim(); + if (opts?.owner !== undefined && !rawOwner) { + throw new Error(`registerContextEngine: owner must be a non-empty string, got ${JSON.stringify(opts.owner)}`); + } + const owner = rawOwner || "core"; + const registry = getContextEngineRegistryState().engines; + const existing = registry.get(id); + if (existing && existing.owner !== owner) { + return { ok: false, existingOwner: existing.owner }; + } + registry.set(id, { factory, owner }); + return { ok: true }; } /** * Return the factory for a registered engine, or undefined. */ export function getContextEngineFactory(id: string): ContextEngineFactory | undefined { - return getContextEngineRegistryState().engines.get(id); + return getContextEngineRegistryState().engines.get(id)?.factory; } /** @@ -73,13 +95,13 @@ export async function resolveContextEngine(config?: OpenClawConfig): Promise { ).toBe(true); }); + it("rejects plugin context engine ids reserved by core", () => { + useNoBundledPlugins(); + const plugin = writePlugin({ + id: "context-engine-core-collision", + filename: "context-engine-core-collision.cjs", + body: `module.exports = { id: "context-engine-core-collision", register(api) { + api.registerContextEngine("legacy", () => ({})); +} };`, + }); + + const registry = loadRegistryFromSinglePlugin({ + plugin, + pluginConfig: { + allow: ["context-engine-core-collision"], + }, + }); + + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "context-engine-core-collision" && + diag.message === "context engine id reserved by core: legacy", + ), + ).toBe(true); + }); + + it("rejects duplicate plugin context engine ids", () => { + useNoBundledPlugins(); + const first = writePlugin({ + id: "context-engine-owner-a", + filename: "context-engine-owner-a.cjs", + body: `module.exports = { id: "context-engine-owner-a", register(api) { + api.registerContextEngine("shared-context-engine-loader-test", () => ({})); +} };`, + }); + const second = writePlugin({ + id: "context-engine-owner-b", + filename: "context-engine-owner-b.cjs", + body: `module.exports = { id: "context-engine-owner-b", register(api) { + api.registerContextEngine("shared-context-engine-loader-test", () => ({})); +} };`, + }); + + const registry = loadOpenClawPlugins({ + cache: false, + config: { + plugins: { + load: { paths: [first.file, second.file] }, + allow: ["context-engine-owner-a", "context-engine-owner-b"], + }, + }, + }); + + expect( + registry.diagnostics.some( + (diag) => + diag.level === "error" && + diag.pluginId === "context-engine-owner-b" && + diag.message === + "context engine already registered: shared-context-engine-loader-test (plugin:context-engine-owner-a)", + ), + ).toBe(true); + }); + it("requires plugin CLI registrars to declare explicit command roots", () => { useNoBundledPlugins(); const plugin = writePlugin({ diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index c1c63cc96cb..952c8d7744b 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -15,6 +15,7 @@ import { normalizePluginHttpPath } from "./http-path.js"; import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js"; import { normalizeRegisteredProvider } from "./provider-validation.js"; import type { PluginRuntime } from "./runtime/types.js"; +import { defaultSlotIdForKey } from "./slots.js"; import { isPluginHookName, isPromptInjectionHookName, @@ -653,7 +654,26 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { registerCli: (registrar, opts) => registerCli(record, registrar, opts), registerService: (service) => registerService(record, service), registerCommand: (command) => registerCommand(record, command), - registerContextEngine: (id, factory) => registerContextEngine(id, factory), + registerContextEngine: (id, factory) => { + if (id === defaultSlotIdForKey("contextEngine")) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `context engine id reserved by core: ${id}`, + }); + return; + } + const result = registerContextEngine(id, factory, { owner: `plugin:${record.id}` }); + if (!result.ok) { + pushDiagnostic({ + level: "error", + pluginId: record.id, + source: record.source, + message: `context engine already registered: ${id} (${result.existingOwner})`, + }); + } + }, resolvePath: (input: string) => resolveUserPath(input), on: (hookName, handler, opts) => registerTypedHook(record, hookName, handler, opts, params.hookPolicy), From 4fb01603090c9697fa18d82a7c2d99597dfd14c7 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Sun, 15 Mar 2026 20:44:03 +0000 Subject: [PATCH 12/16] Gateway: sync runtime post-build artifacts --- CHANGELOG.md | 1 + package.json | 6 +- scripts/copy-bundled-plugin-metadata.mjs | 89 +++++--- scripts/copy-plugin-sdk-root-alias.mjs | 20 +- scripts/run-node.mjs | 20 ++ scripts/runtime-postbuild-shared.mjs | 26 +++ scripts/runtime-postbuild.mjs | 12 ++ src/infra/run-node.test.ts | 245 ++++++++++++++++++++++- 8 files changed, 376 insertions(+), 43 deletions(-) create mode 100644 scripts/runtime-postbuild-shared.mjs create mode 100644 scripts/runtime-postbuild.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f77551f4f8..72069e7b364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai - CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc. - Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse. - Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) thanks @gumadeiras. +- Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/extensions/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras. ## 2026.3.13 diff --git a/package.json b/package.json index a839cdd3ec1..d8f1e530d9b 100644 --- a/package.json +++ b/package.json @@ -225,10 +225,10 @@ "android:run": "cd apps/android && ./gradlew :app:installDebug && adb shell am start -n ai.openclaw.app/.MainActivity", "android:test": "cd apps/android && ./gradlew :app:testDebugUnitTest", "android:test:integration": "OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_ANDROID_NODE=1 vitest run --config vitest.live.config.ts src/gateway/android-node.capabilities.live.test.ts", - "build": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && node scripts/copy-bundled-plugin-metadata.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", - "build:docker": "node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && node scripts/copy-bundled-plugin-metadata.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", + "build": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", + "build:docker": "node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts", "build:plugin-sdk:dts": "tsc -p tsconfig.plugin-sdk.dts.json || true", - "build:strict-smoke": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/copy-plugin-sdk-root-alias.mjs && pnpm build:plugin-sdk:dts", + "build:strict-smoke": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && pnpm build:plugin-sdk:dts", "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh", "check": "pnpm check:host-env-policy:swift && pnpm format:check && pnpm tsgo && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:plugins:no-monolithic-plugin-sdk-entry-imports && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope", "check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-i18n-glossary && pnpm docs:check-links", diff --git a/scripts/copy-bundled-plugin-metadata.mjs b/scripts/copy-bundled-plugin-metadata.mjs index 40d8baa5299..a137872d421 100644 --- a/scripts/copy-bundled-plugin-metadata.mjs +++ b/scripts/copy-bundled-plugin-metadata.mjs @@ -1,11 +1,7 @@ -#!/usr/bin/env node - import fs from "node:fs"; import path from "node:path"; - -const repoRoot = process.cwd(); -const extensionsRoot = path.join(repoRoot, "extensions"); -const distExtensionsRoot = path.join(repoRoot, "dist", "extensions"); +import { pathToFileURL } from "node:url"; +import { removeFileIfExists, writeTextFileIfChanged } from "./runtime-postbuild-shared.mjs"; function rewritePackageExtensions(entries) { if (!Array.isArray(entries)) { @@ -21,37 +17,66 @@ function rewritePackageExtensions(entries) { }); } -for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { - if (!dirent.isDirectory()) { - continue; +export function copyBundledPluginMetadata(params = {}) { + const repoRoot = params.cwd ?? process.cwd(); + const extensionsRoot = path.join(repoRoot, "extensions"); + const distExtensionsRoot = path.join(repoRoot, "dist", "extensions"); + if (!fs.existsSync(extensionsRoot)) { + return; } - const pluginDir = path.join(extensionsRoot, dirent.name); - const manifestPath = path.join(pluginDir, "openclaw.plugin.json"); - if (!fs.existsSync(manifestPath)) { - continue; + const sourcePluginDirs = new Set(); + + for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { + if (!dirent.isDirectory()) { + continue; + } + sourcePluginDirs.add(dirent.name); + + const pluginDir = path.join(extensionsRoot, dirent.name); + const manifestPath = path.join(pluginDir, "openclaw.plugin.json"); + const distPluginDir = path.join(distExtensionsRoot, dirent.name); + const distManifestPath = path.join(distPluginDir, "openclaw.plugin.json"); + const distPackageJsonPath = path.join(distPluginDir, "package.json"); + if (!fs.existsSync(manifestPath)) { + removeFileIfExists(distManifestPath); + removeFileIfExists(distPackageJsonPath); + continue; + } + + writeTextFileIfChanged(distManifestPath, fs.readFileSync(manifestPath, "utf8")); + + const packageJsonPath = path.join(pluginDir, "package.json"); + if (!fs.existsSync(packageJsonPath)) { + removeFileIfExists(distPackageJsonPath); + continue; + } + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + if (packageJson.openclaw && "extensions" in packageJson.openclaw) { + packageJson.openclaw = { + ...packageJson.openclaw, + extensions: rewritePackageExtensions(packageJson.openclaw.extensions), + }; + } + + writeTextFileIfChanged(distPackageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`); } - const distPluginDir = path.join(distExtensionsRoot, dirent.name); - fs.mkdirSync(distPluginDir, { recursive: true }); - fs.copyFileSync(manifestPath, path.join(distPluginDir, "openclaw.plugin.json")); - - const packageJsonPath = path.join(pluginDir, "package.json"); - if (!fs.existsSync(packageJsonPath)) { - continue; + if (!fs.existsSync(distExtensionsRoot)) { + return; } - const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); - if (packageJson.openclaw && "extensions" in packageJson.openclaw) { - packageJson.openclaw = { - ...packageJson.openclaw, - extensions: rewritePackageExtensions(packageJson.openclaw.extensions), - }; + for (const dirent of fs.readdirSync(distExtensionsRoot, { withFileTypes: true })) { + if (!dirent.isDirectory() || sourcePluginDirs.has(dirent.name)) { + continue; + } + const distPluginDir = path.join(distExtensionsRoot, dirent.name); + removeFileIfExists(path.join(distPluginDir, "openclaw.plugin.json")); + removeFileIfExists(path.join(distPluginDir, "package.json")); } - - fs.writeFileSync( - path.join(distPluginDir, "package.json"), - `${JSON.stringify(packageJson, null, 2)}\n`, - "utf8", - ); +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { + copyBundledPluginMetadata(); } diff --git a/scripts/copy-plugin-sdk-root-alias.mjs b/scripts/copy-plugin-sdk-root-alias.mjs index b1bf80b6312..982a5fa9eeb 100644 --- a/scripts/copy-plugin-sdk-root-alias.mjs +++ b/scripts/copy-plugin-sdk-root-alias.mjs @@ -1,10 +1,16 @@ -#!/usr/bin/env node +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { pathToFileURL } from "node:url"; +import { writeTextFileIfChanged } from "./runtime-postbuild-shared.mjs"; -import { copyFileSync, mkdirSync } from "node:fs"; -import { dirname, resolve } from "node:path"; +export function copyPluginSdkRootAlias(params = {}) { + const cwd = params.cwd ?? process.cwd(); + const source = resolve(cwd, "src/plugin-sdk/root-alias.cjs"); + const target = resolve(cwd, "dist/plugin-sdk/root-alias.cjs"); -const source = resolve("src/plugin-sdk/root-alias.cjs"); -const target = resolve("dist/plugin-sdk/root-alias.cjs"); + writeTextFileIfChanged(target, readFileSync(source, "utf8")); +} -mkdirSync(dirname(target), { recursive: true }); -copyFileSync(source, target); +if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { + copyPluginSdkRootAlias(); +} diff --git a/scripts/run-node.mjs b/scripts/run-node.mjs index 0e3acd763b9..56a63805e70 100644 --- a/scripts/run-node.mjs +++ b/scripts/run-node.mjs @@ -4,6 +4,7 @@ import fs from "node:fs"; import path from "node:path"; import process from "node:process"; import { pathToFileURL } from "node:url"; +import { runRuntimePostBuild } from "./runtime-postbuild.mjs"; const compiler = "tsdown"; const compilerArgs = ["exec", compiler, "--no-clean"]; @@ -275,6 +276,19 @@ const runOpenClaw = async (deps) => { return res.exitCode ?? 1; }; +const syncRuntimeArtifacts = (deps) => { + try { + runRuntimePostBuild({ cwd: deps.cwd }); + } catch (error) { + logRunner( + `Failed to write runtime build artifacts: ${error?.message ?? "unknown error"}`, + deps, + ); + return false; + } + return true; +}; + const writeBuildStamp = (deps) => { try { deps.fs.mkdirSync(deps.distRoot, { recursive: true }); @@ -312,6 +326,9 @@ export async function runNodeMain(params = {}) { deps.configFiles = runNodeConfigFiles.map((filePath) => path.join(deps.cwd, filePath)); if (!shouldBuild(deps)) { + if (!syncRuntimeArtifacts(deps)) { + return 1; + } return await runOpenClaw(deps); } @@ -334,6 +351,9 @@ export async function runNodeMain(params = {}) { if (buildRes.exitCode !== 0 && buildRes.exitCode !== null) { return buildRes.exitCode; } + if (!syncRuntimeArtifacts(deps)) { + return 1; + } writeBuildStamp(deps); return await runOpenClaw(deps); } diff --git a/scripts/runtime-postbuild-shared.mjs b/scripts/runtime-postbuild-shared.mjs new file mode 100644 index 00000000000..34ca6bb7930 --- /dev/null +++ b/scripts/runtime-postbuild-shared.mjs @@ -0,0 +1,26 @@ +import fs from "node:fs"; +import { dirname } from "node:path"; + +export function writeTextFileIfChanged(filePath, contents) { + const next = String(contents); + try { + const current = fs.readFileSync(filePath, "utf8"); + if (current === next) { + return false; + } + } catch { + // Write the file when it does not exist or cannot be read. + } + fs.mkdirSync(dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, next, "utf8"); + return true; +} + +export function removeFileIfExists(filePath) { + try { + fs.rmSync(filePath, { force: true }); + return true; + } catch { + return false; + } +} diff --git a/scripts/runtime-postbuild.mjs b/scripts/runtime-postbuild.mjs new file mode 100644 index 00000000000..884ba7af036 --- /dev/null +++ b/scripts/runtime-postbuild.mjs @@ -0,0 +1,12 @@ +import { pathToFileURL } from "node:url"; +import { copyBundledPluginMetadata } from "./copy-bundled-plugin-metadata.mjs"; +import { copyPluginSdkRootAlias } from "./copy-plugin-sdk-root-alias.mjs"; + +export function runRuntimePostBuild(params = {}) { + copyPluginSdkRootAlias(params); + copyBundledPluginMetadata(params); +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { + runRuntimePostBuild(); +} diff --git a/src/infra/run-node.test.ts b/src/infra/run-node.test.ts index 7ba07fdaf2d..59ac7cd0666 100644 --- a/src/infra/run-node.test.ts +++ b/src/infra/run-node.test.ts @@ -24,6 +24,15 @@ function createExitedProcess(code: number | null, signal: string | null = null) }; } +async function writeRuntimePostBuildScaffold(tmp: string): Promise { + const pluginSdkAliasPath = path.join(tmp, "src", "plugin-sdk", "root-alias.cjs"); + await fs.mkdir(path.dirname(pluginSdkAliasPath), { recursive: true }); + await fs.mkdir(path.join(tmp, "extensions"), { recursive: true }); + await fs.writeFile(pluginSdkAliasPath, "module.exports = {};\n", "utf-8"); + const baselineTime = new Date("2026-03-13T09:00:00.000Z"); + await fs.utimes(pluginSdkAliasPath, baselineTime, baselineTime); +} + function expectedBuildSpawn(platform: NodeJS.Platform = process.platform) { return platform === "win32" ? ["cmd.exe", "/d", "/s", "/c", "pnpm", "exec", "tsdown", "--no-clean"] @@ -38,6 +47,7 @@ describe("run-node script", () => { const argsPath = path.join(tmp, ".pnpm-args.txt"); const indexPath = path.join(tmp, "dist", "control-ui", "index.html"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(indexPath), { recursive: true }); await fs.writeFile(indexPath, "sentinel\n", "utf-8"); @@ -84,6 +94,73 @@ describe("run-node script", () => { }, ); + it("copies bundled plugin metadata after rebuilding from a clean dist", async () => { + await withTempDir(async (tmp) => { + const extensionManifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json"); + const extensionPackagePath = path.join(tmp, "extensions", "demo", "package.json"); + + await writeRuntimePostBuildScaffold(tmp); + await fs.mkdir(path.dirname(extensionManifestPath), { recursive: true }); + await fs.writeFile( + extensionManifestPath, + '{"id":"demo","configSchema":{"type":"object"}}\n', + "utf-8", + ); + await fs.writeFile( + extensionPackagePath, + JSON.stringify( + { + name: "demo", + openclaw: { + extensions: ["./src/index.ts", "./nested/entry.mts"], + }, + }, + null, + 2, + ) + "\n", + "utf-8", + ); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_FORCE_BUILD: "1", + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([ + expectedBuildSpawn(), + [process.execPath, "openclaw.mjs", "status"], + ]); + + await expect( + fs.readFile(path.join(tmp, "dist", "plugin-sdk", "root-alias.cjs"), "utf-8"), + ).resolves.toContain("module.exports = {};"); + await expect( + fs.readFile(path.join(tmp, "dist", "extensions", "demo", "openclaw.plugin.json"), "utf-8"), + ).resolves.toContain('"id":"demo"'); + await expect( + fs.readFile(path.join(tmp, "dist", "extensions", "demo", "package.json"), "utf-8"), + ).resolves.toContain( + '"extensions": [\n "./src/index.js",\n "./nested/entry.js"\n ]', + ); + }); + }); + it("skips rebuilding when dist is current and the source tree is clean", async () => { await withTempDir(async (tmp) => { const srcPath = path.join(tmp, "src", "index.ts"); @@ -91,6 +168,7 @@ describe("run-node script", () => { const buildStampPath = path.join(tmp, "dist", ".buildstamp"); const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(srcPath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); @@ -175,6 +253,7 @@ describe("run-node script", () => { const buildStampPath = path.join(tmp, "dist", ".buildstamp"); const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(extensionPath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); await fs.writeFile(extensionPath, "export const extensionValue = 1;\n", "utf-8"); @@ -222,14 +301,20 @@ describe("run-node script", () => { it("skips rebuilding when extension package metadata is newer than the build stamp", async () => { await withTempDir(async (tmp) => { + const manifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json"); const packagePath = path.join(tmp, "extensions", "demo", "package.json"); + const distPackagePath = path.join(tmp, "dist", "extensions", "demo", "package.json"); const distEntryPath = path.join(tmp, "dist", "entry.js"); const buildStampPath = path.join(tmp, "dist", ".buildstamp"); const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); + await fs.mkdir(path.dirname(manifestPath), { recursive: true }); await fs.mkdir(path.dirname(packagePath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.mkdir(path.dirname(distPackagePath), { recursive: true }); + await fs.writeFile(manifestPath, '{"id":"demo","configSchema":{"type":"object"}}\n', "utf-8"); await fs.writeFile( packagePath, '{"name":"demo","openclaw":{"extensions":["./index.ts"]}}\n', @@ -239,11 +324,17 @@ describe("run-node script", () => { await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile( + distPackagePath, + '{"name":"demo","openclaw":{"extensions":["./stale.js"]}}\n', + "utf-8", + ); await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); const oldTime = new Date("2026-03-13T10:00:00.000Z"); const stampTime = new Date("2026-03-13T12:00:00.000Z"); const newTime = new Date("2026-03-13T12:00:01.000Z"); + await fs.utimes(manifestPath, oldTime, oldTime); await fs.utimes(tsconfigPath, oldTime, oldTime); await fs.utimes(packageJsonPath, oldTime, oldTime); await fs.utimes(tsdownConfigPath, oldTime, oldTime); @@ -274,6 +365,7 @@ describe("run-node script", () => { expect(exitCode).toBe(0); expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + await expect(fs.readFile(distPackagePath, "utf-8")).resolves.toContain('"./index.js"'); }); }); @@ -286,6 +378,7 @@ describe("run-node script", () => { const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(srcPath), { recursive: true }); await fs.mkdir(path.dirname(readmePath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); @@ -344,20 +437,28 @@ describe("run-node script", () => { await withTempDir(async (tmp) => { const srcPath = path.join(tmp, "src", "index.ts"); const manifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json"); + const distManifestPath = path.join(tmp, "dist", "extensions", "demo", "openclaw.plugin.json"); const distEntryPath = path.join(tmp, "dist", "entry.js"); const buildStampPath = path.join(tmp, "dist", ".buildstamp"); const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(srcPath), { recursive: true }); await fs.mkdir(path.dirname(manifestPath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.mkdir(path.dirname(distManifestPath), { recursive: true }); await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); - await fs.writeFile(manifestPath, '{"id":"demo"}\n', "utf-8"); + await fs.writeFile(manifestPath, '{"id":"demo","configSchema":{"type":"object"}}\n', "utf-8"); await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile( + distManifestPath, + '{"id":"stale","configSchema":{"type":"object"}}\n', + "utf-8", + ); await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); const stampTime = new Date("2026-03-13T12:00:00.000Z"); @@ -400,6 +501,146 @@ describe("run-node script", () => { expect(exitCode).toBe(0); expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + await expect(fs.readFile(distManifestPath, "utf-8")).resolves.toContain('"id":"demo"'); + }); + }); + + it("repairs missing bundled plugin metadata without rerunning tsdown", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const manifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json"); + const distManifestPath = path.join(tmp, "dist", "extensions", "demo", "openclaw.plugin.json"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(path.dirname(manifestPath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(manifestPath, '{"id":"demo","configSchema":{"type":"object"}}\n', "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + await fs.utimes(srcPath, stampTime, stampTime); + await fs.utimes(manifestPath, stampTime, stampTime); + await fs.utimes(tsconfigPath, stampTime, stampTime); + await fs.utimes(packageJsonPath, stampTime, stampTime); + await fs.utimes(tsdownConfigPath, stampTime, stampTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = (cmd: string, args: string[]) => { + if (cmd === "git" && args[0] === "rev-parse") { + return { status: 0, stdout: "abc123\n" }; + } + if (cmd === "git" && args[0] === "status") { + return { status: 0, stdout: "" }; + } + return { status: 1, stdout: "" }; + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + await expect(fs.readFile(distManifestPath, "utf-8")).resolves.toContain('"id":"demo"'); + }); + }); + + it("removes stale bundled plugin metadata when the source manifest is gone", async () => { + await withTempDir(async (tmp) => { + const srcPath = path.join(tmp, "src", "index.ts"); + const extensionDir = path.join(tmp, "extensions", "demo"); + const distManifestPath = path.join(tmp, "dist", "extensions", "demo", "openclaw.plugin.json"); + const distPackagePath = path.join(tmp, "dist", "extensions", "demo", "package.json"); + const distEntryPath = path.join(tmp, "dist", "entry.js"); + const buildStampPath = path.join(tmp, "dist", ".buildstamp"); + const tsconfigPath = path.join(tmp, "tsconfig.json"); + const packageJsonPath = path.join(tmp, "package.json"); + const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); + await fs.mkdir(path.dirname(srcPath), { recursive: true }); + await fs.mkdir(extensionDir, { recursive: true }); + await fs.mkdir(path.dirname(distManifestPath), { recursive: true }); + await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); + await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); + await fs.writeFile(tsconfigPath, "{}\n", "utf-8"); + await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8"); + await fs.writeFile(tsdownConfigPath, "export default {};\n", "utf-8"); + await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8"); + await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8"); + await fs.writeFile( + distManifestPath, + '{"id":"stale","configSchema":{"type":"object"}}\n', + "utf-8", + ); + await fs.writeFile(distPackagePath, '{"name":"stale"}\n', "utf-8"); + + const stampTime = new Date("2026-03-13T12:00:00.000Z"); + await fs.utimes(srcPath, stampTime, stampTime); + await fs.utimes(tsconfigPath, stampTime, stampTime); + await fs.utimes(packageJsonPath, stampTime, stampTime); + await fs.utimes(tsdownConfigPath, stampTime, stampTime); + await fs.utimes(distEntryPath, stampTime, stampTime); + await fs.utimes(buildStampPath, stampTime, stampTime); + + const spawnCalls: string[][] = []; + const spawn = (cmd: string, args: string[]) => { + spawnCalls.push([cmd, ...args]); + return createExitedProcess(0); + }; + const spawnSync = (cmd: string, args: string[]) => { + if (cmd === "git" && args[0] === "rev-parse") { + return { status: 0, stdout: "abc123\n" }; + } + if (cmd === "git" && args[0] === "status") { + return { status: 0, stdout: "" }; + } + return { status: 1, stdout: "" }; + }; + + const { runNodeMain } = await import("../../scripts/run-node.mjs"); + const exitCode = await runNodeMain({ + cwd: tmp, + args: ["status"], + env: { + ...process.env, + OPENCLAW_RUNNER_LOG: "0", + }, + spawn, + spawnSync, + execPath: process.execPath, + platform: process.platform, + }); + + expect(exitCode).toBe(0); + expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]); + await expect(fs.access(distManifestPath)).rejects.toThrow(); + await expect(fs.access(distPackagePath)).rejects.toThrow(); }); }); @@ -412,6 +653,7 @@ describe("run-node script", () => { const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(srcPath), { recursive: true }); await fs.mkdir(path.dirname(readmePath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); @@ -468,6 +710,7 @@ describe("run-node script", () => { const tsconfigPath = path.join(tmp, "tsconfig.json"); const packageJsonPath = path.join(tmp, "package.json"); const tsdownConfigPath = path.join(tmp, "tsdown.config.ts"); + await writeRuntimePostBuildScaffold(tmp); await fs.mkdir(path.dirname(srcPath), { recursive: true }); await fs.mkdir(path.dirname(distEntryPath), { recursive: true }); await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8"); From 7931f06c001d900c3b6a46328129d57caa9422a7 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 13:49:48 -0700 Subject: [PATCH 13/16] Plugins: harden context engine ownership --- CHANGELOG.md | 1 + src/context-engine/context-engine.test.ts | 93 ++++++++++++++++++++--- src/context-engine/legacy.ts | 6 +- src/context-engine/registry.ts | 4 +- src/plugins/registry.ts | 6 +- 5 files changed, 95 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72069e7b364..15521744304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai - Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse. - Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) thanks @gumadeiras. - Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/extensions/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras. +- Plugins/context engines: enforce owner-aware context-engine registration on both loader and public SDK paths so plugins cannot spoof privileged ownership, claim the core `legacy` engine id, or overwrite an existing engine id through direct SDK imports. (#47595) Thanks @vincentkoc. ## 2026.3.13 diff --git a/src/context-engine/context-engine.test.ts b/src/context-engine/context-engine.test.ts index 5cdc03a7114..703ee88bf57 100644 --- a/src/context-engine/context-engine.test.ts +++ b/src/context-engine/context-engine.test.ts @@ -8,10 +8,12 @@ import { compactEmbeddedPiSessionDirect } from "../agents/pi-embedded-runner/com import { LegacyContextEngine, registerLegacyContextEngine } from "./legacy.js"; import { registerContextEngine, + registerContextEngineForOwner, getContextEngineFactory, listContextEngineIds, resolveContextEngine, } from "./registry.js"; +import type { ContextEngineFactory, ContextEngineRegistrationResult } from "./registry.js"; import type { ContextEngine, ContextEngineInfo, @@ -235,14 +237,18 @@ describe("Registry tests", () => { const factory1 = () => new MockContextEngine(); const factory2 = () => new MockContextEngine(); - expect(registerContextEngine("reg-overwrite", factory1, { owner: "owner-a" })).toEqual({ - ok: true, - }); + expect( + registerContextEngineForOwner("reg-overwrite", factory1, "owner-a", { + allowSameOwnerRefresh: true, + }), + ).toEqual({ ok: true }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory1); - expect(registerContextEngine("reg-overwrite", factory2, { owner: "owner-a" })).toEqual({ - ok: true, - }); + expect( + registerContextEngineForOwner("reg-overwrite", factory2, "owner-a", { + allowSameOwnerRefresh: true, + }), + ).toEqual({ ok: true }); expect(getContextEngineFactory("reg-overwrite")).toBe(factory2); expect(getContextEngineFactory("reg-overwrite")).not.toBe(factory1); }); @@ -251,16 +257,56 @@ describe("Registry tests", () => { const factory1 = () => new MockContextEngine(); const factory2 = () => new MockContextEngine(); - expect(registerContextEngine("reg-owner-guard", factory1, { owner: "owner-a" })).toEqual({ - ok: true, - }); - expect(registerContextEngine("reg-owner-guard", factory2, { owner: "owner-b" })).toEqual({ + expect( + registerContextEngineForOwner("reg-owner-guard", factory1, "owner-a", { + allowSameOwnerRefresh: true, + }), + ).toEqual({ ok: true }); + expect(registerContextEngineForOwner("reg-owner-guard", factory2, "owner-b")).toEqual({ ok: false, existingOwner: "owner-a", }); expect(getContextEngineFactory("reg-owner-guard")).toBe(factory1); }); + it("public registerContextEngine cannot spoof owner or refresh existing ids", () => { + const ownedFactory = () => new MockContextEngine(); + expect( + registerContextEngineForOwner("public-owner-guard", ownedFactory, "owner-a", { + allowSameOwnerRefresh: true, + }), + ).toEqual({ ok: true }); + + const spoofAttempt = ( + registerContextEngine as unknown as ( + id: string, + factory: ContextEngineFactory, + opts?: { owner?: string }, + ) => ContextEngineRegistrationResult + )("public-owner-guard", () => new MockContextEngine(), { owner: "owner-a" }); + + expect(spoofAttempt).toEqual({ + ok: false, + existingOwner: "owner-a", + }); + expect(getContextEngineFactory("public-owner-guard")).toBe(ownedFactory); + }); + + it("public registerContextEngine reserves the default legacy id", () => { + const legacyAttempt = ( + registerContextEngine as unknown as ( + id: string, + factory: ContextEngineFactory, + opts?: { owner?: string }, + ) => ContextEngineRegistrationResult + )("legacy", () => new MockContextEngine(), { owner: "core" }); + + expect(legacyAttempt).toEqual({ + ok: false, + existingOwner: "core", + }); + }); + it("shares registered engines across duplicate module copies", async () => { const registryUrl = new URL("./registry.ts", import.meta.url).href; const suffix = Date.now().toString(36); @@ -492,6 +538,33 @@ describe("Bundle chunk isolation (#40096)", () => { expect(getContextEngineFactory(sdkEngineId)).toBeDefined(); }); + it("plugin-sdk registerContextEngine cannot spoof privileged ownership", async () => { + const ts = Date.now().toString(36); + const engineId = `sdk-spoof-guard-${ts}`; + const ownedFactory = () => new MockContextEngine(); + expect( + registerContextEngineForOwner(engineId, ownedFactory, "plugin:owner-a", { + allowSameOwnerRefresh: true, + }), + ).toEqual({ ok: true }); + + const sdkUrl = new URL("../plugin-sdk/index.ts", import.meta.url).href; + const sdk = await import(/* @vite-ignore */ `${sdkUrl}?sdk-spoof-${ts}`); + const spoofAttempt = ( + sdk.registerContextEngine as unknown as ( + id: string, + factory: ContextEngineFactory, + opts?: { owner?: string }, + ) => ContextEngineRegistrationResult + )(engineId, () => new MockContextEngine(), { owner: "plugin:owner-a" }); + + expect(spoofAttempt).toEqual({ + ok: false, + existingOwner: "plugin:owner-a", + }); + expect(getContextEngineFactory(engineId)).toBe(ownedFactory); + }); + it("concurrent registration from multiple chunks does not lose entries", async () => { const ts = Date.now().toString(36); const registryUrl = new URL("./registry.ts", import.meta.url).href; diff --git a/src/context-engine/legacy.ts b/src/context-engine/legacy.ts index 0485a4feae4..3080e9aba0b 100644 --- a/src/context-engine/legacy.ts +++ b/src/context-engine/legacy.ts @@ -1,5 +1,5 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import { registerContextEngine } from "./registry.js"; +import { registerContextEngineForOwner } from "./registry.js"; import type { ContextEngine, ContextEngineInfo, @@ -124,5 +124,7 @@ export class LegacyContextEngine implements ContextEngine { } export function registerLegacyContextEngine(): void { - registerContextEngine("legacy", () => new LegacyContextEngine()); + registerContextEngineForOwner("legacy", () => new LegacyContextEngine(), "core", { + allowSameOwnerRefresh: true, + }); } diff --git a/src/context-engine/registry.ts b/src/context-engine/registry.ts index 9a186609f20..1701877790a 100644 --- a/src/context-engine/registry.ts +++ b/src/context-engine/registry.ts @@ -48,7 +48,9 @@ function getContextEngineRegistryState(): ContextEngineRegistryState { function requireContextEngineOwner(owner: string): string { const normalizedOwner = owner.trim(); if (!normalizedOwner) { - throw new Error(`registerContextEngineForOwner: owner must be a non-empty string, got ${JSON.stringify(owner)}`); + throw new Error( + `registerContextEngineForOwner: owner must be a non-empty string, got ${JSON.stringify(owner)}`, + ); } return normalizedOwner; } diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index 952c8d7744b..fe978d6a346 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -2,7 +2,7 @@ import path from "node:path"; import type { AnyAgentTool } from "../agents/tools/common.js"; import type { ChannelDock } from "../channels/dock.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; -import { registerContextEngine } from "../context-engine/registry.js"; +import { registerContextEngineForOwner } from "../context-engine/registry.js"; import type { GatewayRequestHandler, GatewayRequestHandlers, @@ -664,7 +664,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { }); return; } - const result = registerContextEngine(id, factory, { owner: `plugin:${record.id}` }); + const result = registerContextEngineForOwner(id, factory, `plugin:${record.id}`, { + allowSameOwnerRefresh: true, + }); if (!result.ok) { pushDiagnostic({ level: "error", From 47fd8558cd5a3299d27c5cd254482a8bfa476642 Mon Sep 17 00:00:00 2001 From: Nimrod Gutman Date: Sun, 15 Mar 2026 23:00:30 +0200 Subject: [PATCH 14/16] fix(plugins): fix bundled plugin roots and skill assets (#47601) * fix(acpx): resolve bundled plugin root correctly * fix(plugins): copy bundled plugin skill assets * fix(plugins): tolerate missing bundled skill paths --- CHANGELOG.md | 1 + extensions/acpx/src/config.test.ts | 31 ++++ extensions/acpx/src/config.ts | 23 ++- scripts/copy-bundled-plugin-metadata.d.mts | 3 + scripts/copy-bundled-plugin-metadata.mjs | 53 ++++++- .../copy-bundled-plugin-metadata.test.ts | 144 ++++++++++++++++++ 6 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 scripts/copy-bundled-plugin-metadata.d.mts create mode 100644 src/plugins/copy-bundled-plugin-metadata.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 15521744304..2b4546d49d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai - Zalo Personal/group gating: stop reapplying `dmPolicy.allowFrom` as a sender gate for already-allowlisted groups when `groupAllowFrom` is unset, so any member of an allowed group can trigger replies while DMs stay restricted. (#40146) - Browser/remote CDP: honor strict browser SSRF policy during remote CDP reachability and `/json/version` discovery checks, redact sensitive `cdpUrl` tokens from status output, and warn when remote CDP targets private/internal hosts. - Plugins/install precedence: keep bundled plugins ahead of auto-discovered globals by default, but let an explicitly installed plugin record win its own duplicate-id tie so installed channel plugins load from `~/.openclaw/extensions` after `openclaw plugins install`. +- ACP/acpx: resolve the bundled plugin root from the actual plugin directory so plugin-local installs stay under `dist/extensions/acpx` instead of escaping to `dist/extensions` and failing runtime setup. - Gateway/auth: ignore spoofed loopback hops in trusted forwarding chains and block device approvals that request scopes above the caller session. Thanks @vincentkoc. - Gateway/config views: strip embedded credentials from URL-based endpoint fields before returning read-only account and config snapshots. Thanks @vincentkoc. - Tools/apply-patch: revalidate workspace-only delete and directory targets immediately before mutating host paths. Thanks @vincentkoc. diff --git a/extensions/acpx/src/config.test.ts b/extensions/acpx/src/config.test.ts index 45be08e3edf..5a19d6f43e8 100644 --- a/extensions/acpx/src/config.test.ts +++ b/extensions/acpx/src/config.test.ts @@ -1,13 +1,44 @@ +import fs from "node:fs"; +import os from "node:os"; import path from "node:path"; +import { pathToFileURL } from "node:url"; import { describe, expect, it } from "vitest"; import { ACPX_BUNDLED_BIN, ACPX_PINNED_VERSION, createAcpxPluginConfigSchema, + resolveAcpxPluginRoot, resolveAcpxPluginConfig, } from "./config.js"; describe("acpx plugin config parsing", () => { + it("resolves source-layout plugin root from a file under src", () => { + const pluginRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acpx-root-source-")); + try { + fs.mkdirSync(path.join(pluginRoot, "src"), { recursive: true }); + fs.writeFileSync(path.join(pluginRoot, "package.json"), "{}\n", "utf8"); + fs.writeFileSync(path.join(pluginRoot, "openclaw.plugin.json"), "{}\n", "utf8"); + + const moduleUrl = pathToFileURL(path.join(pluginRoot, "src", "config.ts")).href; + expect(resolveAcpxPluginRoot(moduleUrl)).toBe(pluginRoot); + } finally { + fs.rmSync(pluginRoot, { recursive: true, force: true }); + } + }); + + it("resolves bundled-layout plugin root from the dist entry file", () => { + const pluginRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acpx-root-dist-")); + try { + fs.writeFileSync(path.join(pluginRoot, "package.json"), "{}\n", "utf8"); + fs.writeFileSync(path.join(pluginRoot, "openclaw.plugin.json"), "{}\n", "utf8"); + + const moduleUrl = pathToFileURL(path.join(pluginRoot, "index.js")).href; + expect(resolveAcpxPluginRoot(moduleUrl)).toBe(pluginRoot); + } finally { + fs.rmSync(pluginRoot, { recursive: true, force: true }); + } + }); + it("resolves bundled acpx with pinned version by default", () => { const resolved = resolveAcpxPluginConfig({ rawConfig: { diff --git a/extensions/acpx/src/config.ts b/extensions/acpx/src/config.ts index ef0207a1365..d6bfb3a44db 100644 --- a/extensions/acpx/src/config.ts +++ b/extensions/acpx/src/config.ts @@ -1,3 +1,4 @@ +import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import type { OpenClawPluginConfigSchema } from "openclaw/plugin-sdk/acpx"; @@ -11,7 +12,27 @@ export type AcpxNonInteractivePermissionPolicy = (typeof ACPX_NON_INTERACTIVE_PO export const ACPX_PINNED_VERSION = "0.1.16"; export const ACPX_VERSION_ANY = "any"; const ACPX_BIN_NAME = process.platform === "win32" ? "acpx.cmd" : "acpx"; -export const ACPX_PLUGIN_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): string { + let cursor = path.dirname(fileURLToPath(moduleUrl)); + for (let i = 0; i < 3; i += 1) { + // Bundled entries live at the plugin root while source files still live under src/. + if ( + fs.existsSync(path.join(cursor, "openclaw.plugin.json")) && + fs.existsSync(path.join(cursor, "package.json")) + ) { + return cursor; + } + const parent = path.dirname(cursor); + if (parent === cursor) { + break; + } + cursor = parent; + } + return path.resolve(path.dirname(fileURLToPath(moduleUrl)), ".."); +} + +export const ACPX_PLUGIN_ROOT = resolveAcpxPluginRoot(); export const ACPX_BUNDLED_BIN = path.join(ACPX_PLUGIN_ROOT, "node_modules", ".bin", ACPX_BIN_NAME); export function buildAcpxLocalInstallCommand(version: string = ACPX_PINNED_VERSION): string { return `npm install --omit=dev --no-save acpx@${version}`; diff --git a/scripts/copy-bundled-plugin-metadata.d.mts b/scripts/copy-bundled-plugin-metadata.d.mts new file mode 100644 index 00000000000..1b2d0e4836d --- /dev/null +++ b/scripts/copy-bundled-plugin-metadata.d.mts @@ -0,0 +1,3 @@ +export function rewritePackageExtensions(entries: unknown): string[] | undefined; + +export function copyBundledPluginMetadata(params?: { repoRoot?: string }): void; diff --git a/scripts/copy-bundled-plugin-metadata.mjs b/scripts/copy-bundled-plugin-metadata.mjs index a137872d421..af8612a3465 100644 --- a/scripts/copy-bundled-plugin-metadata.mjs +++ b/scripts/copy-bundled-plugin-metadata.mjs @@ -3,7 +3,7 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { removeFileIfExists, writeTextFileIfChanged } from "./runtime-postbuild-shared.mjs"; -function rewritePackageExtensions(entries) { +export function rewritePackageExtensions(entries) { if (!Array.isArray(entries)) { return undefined; } @@ -17,8 +17,50 @@ function rewritePackageExtensions(entries) { }); } +function ensurePathInsideRoot(rootDir, rawPath) { + const resolved = path.resolve(rootDir, rawPath); + const relative = path.relative(rootDir, resolved); + if ( + relative === "" || + relative === "." || + (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative)) + ) { + return resolved; + } + throw new Error(`path escapes plugin root: ${rawPath}`); +} + +function copyDeclaredPluginSkillPaths(params) { + const skills = Array.isArray(params.manifest.skills) ? params.manifest.skills : []; + const copiedSkills = []; + for (const raw of skills) { + if (typeof raw !== "string" || raw.trim().length === 0) { + continue; + } + const normalized = raw.replace(/^\.\//u, ""); + const sourcePath = ensurePathInsideRoot(params.pluginDir, raw); + if (!fs.existsSync(sourcePath)) { + // Some Docker/lightweight builds intentionally omit optional plugin-local + // dependencies. Only advertise skill paths that were actually bundled. + console.warn( + `[bundled-plugin-metadata] skipping missing skill path ${sourcePath} (plugin ${params.manifest.id ?? path.basename(params.pluginDir)})`, + ); + continue; + } + const targetPath = ensurePathInsideRoot(params.distPluginDir, normalized); + fs.mkdirSync(path.dirname(targetPath), { recursive: true }); + fs.cpSync(sourcePath, targetPath, { + dereference: true, + force: true, + recursive: true, + }); + copiedSkills.push(raw); + } + return copiedSkills; +} + export function copyBundledPluginMetadata(params = {}) { - const repoRoot = params.cwd ?? process.cwd(); + const repoRoot = params.cwd ?? params.repoRoot ?? process.cwd(); const extensionsRoot = path.join(repoRoot, "extensions"); const distExtensionsRoot = path.join(repoRoot, "dist", "extensions"); if (!fs.existsSync(extensionsRoot)) { @@ -44,7 +86,12 @@ export function copyBundledPluginMetadata(params = {}) { continue; } - writeTextFileIfChanged(distManifestPath, fs.readFileSync(manifestPath, "utf8")); + const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + const copiedSkills = copyDeclaredPluginSkillPaths({ manifest, pluginDir, distPluginDir }); + const bundledManifest = Array.isArray(manifest.skills) + ? { ...manifest, skills: copiedSkills } + : manifest; + writeTextFileIfChanged(distManifestPath, `${JSON.stringify(bundledManifest, null, 2)}\n`); const packageJsonPath = path.join(pluginDir, "package.json"); if (!fs.existsSync(packageJsonPath)) { diff --git a/src/plugins/copy-bundled-plugin-metadata.test.ts b/src/plugins/copy-bundled-plugin-metadata.test.ts new file mode 100644 index 00000000000..46036dc45d9 --- /dev/null +++ b/src/plugins/copy-bundled-plugin-metadata.test.ts @@ -0,0 +1,144 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; +import { + copyBundledPluginMetadata, + rewritePackageExtensions, +} from "../../scripts/copy-bundled-plugin-metadata.mjs"; + +const tempDirs: string[] = []; + +function makeRepoRoot(prefix: string): string { + const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), prefix)); + tempDirs.push(repoRoot); + return repoRoot; +} + +function writeJson(filePath: string, value: unknown): void { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8"); +} + +afterEach(() => { + for (const dir of tempDirs.splice(0, tempDirs.length)) { + fs.rmSync(dir, { recursive: true, force: true }); + } +}); + +describe("rewritePackageExtensions", () => { + it("rewrites TypeScript extension entries to built JS paths", () => { + expect(rewritePackageExtensions(["./index.ts", "./nested/entry.mts"])).toEqual([ + "./index.js", + "./nested/entry.js", + ]); + }); +}); + +describe("copyBundledPluginMetadata", () => { + it("copies plugin manifests, package metadata, and local skill directories", () => { + const repoRoot = makeRepoRoot("openclaw-bundled-plugin-meta-"); + const pluginDir = path.join(repoRoot, "extensions", "acpx"); + fs.mkdirSync(path.join(pluginDir, "skills", "acp-router"), { recursive: true }); + fs.writeFileSync( + path.join(pluginDir, "skills", "acp-router", "SKILL.md"), + "# ACP Router\n", + "utf8", + ); + writeJson(path.join(pluginDir, "openclaw.plugin.json"), { + id: "acpx", + configSchema: { type: "object" }, + skills: ["./skills"], + }); + writeJson(path.join(pluginDir, "package.json"), { + name: "@openclaw/acpx", + openclaw: { extensions: ["./index.ts"] }, + }); + + copyBundledPluginMetadata({ repoRoot }); + + expect( + fs.existsSync(path.join(repoRoot, "dist", "extensions", "acpx", "openclaw.plugin.json")), + ).toBe(true); + expect( + fs.readFileSync( + path.join(repoRoot, "dist", "extensions", "acpx", "skills", "acp-router", "SKILL.md"), + "utf8", + ), + ).toContain("ACP Router"); + const packageJson = JSON.parse( + fs.readFileSync(path.join(repoRoot, "dist", "extensions", "acpx", "package.json"), "utf8"), + ) as { openclaw?: { extensions?: string[] } }; + expect(packageJson.openclaw?.extensions).toEqual(["./index.js"]); + }); + + it("dereferences node_modules-backed skill paths into the bundled dist tree", () => { + const repoRoot = makeRepoRoot("openclaw-bundled-plugin-node-modules-"); + const pluginDir = path.join(repoRoot, "extensions", "tlon"); + const storeSkillDir = path.join( + repoRoot, + "node_modules", + ".pnpm", + "@tloncorp+tlon-skill@0.2.2", + "node_modules", + "@tloncorp", + "tlon-skill", + ); + fs.mkdirSync(storeSkillDir, { recursive: true }); + fs.writeFileSync(path.join(storeSkillDir, "SKILL.md"), "# Tlon Skill\n", "utf8"); + fs.mkdirSync(path.join(pluginDir, "node_modules", "@tloncorp"), { recursive: true }); + fs.symlinkSync( + storeSkillDir, + path.join(pluginDir, "node_modules", "@tloncorp", "tlon-skill"), + process.platform === "win32" ? "junction" : "dir", + ); + writeJson(path.join(pluginDir, "openclaw.plugin.json"), { + id: "tlon", + configSchema: { type: "object" }, + skills: ["node_modules/@tloncorp/tlon-skill"], + }); + writeJson(path.join(pluginDir, "package.json"), { + name: "@openclaw/tlon", + openclaw: { extensions: ["./index.ts"] }, + }); + + copyBundledPluginMetadata({ repoRoot }); + + const copiedSkillDir = path.join( + repoRoot, + "dist", + "extensions", + "tlon", + "node_modules", + "@tloncorp", + "tlon-skill", + ); + expect(fs.existsSync(path.join(copiedSkillDir, "SKILL.md"))).toBe(true); + expect(fs.lstatSync(copiedSkillDir).isSymbolicLink()).toBe(false); + }); + + it("omits missing declared skill paths from the bundled manifest", () => { + const repoRoot = makeRepoRoot("openclaw-bundled-plugin-missing-skill-"); + const pluginDir = path.join(repoRoot, "extensions", "tlon"); + fs.mkdirSync(pluginDir, { recursive: true }); + writeJson(path.join(pluginDir, "openclaw.plugin.json"), { + id: "tlon", + configSchema: { type: "object" }, + skills: ["node_modules/@tloncorp/tlon-skill"], + }); + writeJson(path.join(pluginDir, "package.json"), { + name: "@openclaw/tlon", + openclaw: { extensions: ["./index.ts"] }, + }); + + copyBundledPluginMetadata({ repoRoot }); + + const bundledManifest = JSON.parse( + fs.readFileSync( + path.join(repoRoot, "dist", "extensions", "tlon", "openclaw.plugin.json"), + "utf8", + ), + ) as { skills?: string[] }; + expect(bundledManifest.skills).toEqual([]); + }); +}); From 373515676607b285818a4b7e29eb4176680c0afc Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 14:14:30 -0700 Subject: [PATCH 15/16] fix(ci): restore config baseline release-check output (#47629) * Docs: regenerate config baseline * Chore: ignore generated config baseline * Update .prettierignore Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .prettierignore | 1 + docs/.generated/config-baseline.json | 8086 ++++++++++++++++++++------ 2 files changed, 6413 insertions(+), 1674 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..8af8b9e55d1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +docs/.generated/ diff --git a/docs/.generated/config-baseline.json b/docs/.generated/config-baseline.json index 4974f3a410a..f6f854b2946 100644 --- a/docs/.generated/config-baseline.json +++ b/docs/.generated/config-baseline.json @@ -8,7 +8,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP", "help": "ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.", "hasChildren": true @@ -20,7 +22,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "ACP Allowed Agents", "help": "Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.", "hasChildren": true @@ -42,7 +46,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Backend", "help": "Default ACP runtime backend id (for example: acpx). Must match a registered ACP runtime plugin backend.", "hasChildren": false @@ -54,7 +60,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Default Agent", "help": "Fallback ACP target agent id used when ACP spawns do not specify an explicit target.", "hasChildren": false @@ -76,7 +84,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Dispatch Enabled", "help": "Independent dispatch gate for ACP session turns (default: true). Set false to keep ACP commands available while blocking ACP turn execution.", "hasChildren": false @@ -88,7 +98,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Enabled", "help": "Global ACP feature gate. Keep disabled unless ACP runtime + policy are configured.", "hasChildren": false @@ -100,7 +112,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "ACP Max Concurrent Sessions", "help": "Maximum concurrently active ACP sessions across this gateway process.", "hasChildren": false @@ -122,7 +137,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Runtime Install Command", "help": "Optional operator install/setup command shown by `/acp install` and `/acp doctor` when ACP backend wiring is missing.", "hasChildren": false @@ -134,7 +151,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Runtime TTL (minutes)", "help": "Idle runtime TTL in minutes for ACP session workers before eligible cleanup.", "hasChildren": false @@ -146,7 +165,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream", "help": "ACP streaming projection controls for chunk sizing, metadata visibility, and deduped delivery behavior.", "hasChildren": true @@ -158,7 +179,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream Coalesce Idle (ms)", "help": "Coalescer idle flush window in milliseconds for ACP streamed text before block replies are emitted.", "hasChildren": false @@ -170,7 +193,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream Delivery Mode", "help": "ACP delivery style: live streams projected output incrementally, final_only buffers all projected ACP output until terminal turn events.", "hasChildren": false @@ -182,7 +207,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream Hidden Boundary Separator", "help": "Separator inserted before next visible assistant text when hidden ACP tool lifecycle events occurred (none|space|newline|paragraph). Default: paragraph.", "hasChildren": false @@ -194,7 +221,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "ACP Stream Max Chunk Chars", "help": "Maximum chunk size for ACP streamed block projection before splitting into multiple block replies.", "hasChildren": false @@ -206,7 +235,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "ACP Stream Max Output Chars", "help": "Maximum assistant output characters projected per ACP turn before truncation notice is emitted.", "hasChildren": false @@ -218,7 +249,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "ACP Stream Max Session Update Chars", "help": "Maximum characters for projected ACP session/update lines (tool/status updates).", "hasChildren": false @@ -230,7 +264,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream Repeat Suppression", "help": "When true (default), suppress repeated ACP status/tool projection lines in a turn while keeping raw ACP events unchanged.", "hasChildren": false @@ -242,7 +278,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Stream Tag Visibility", "help": "Per-sessionUpdate visibility overrides for ACP projection (for example usage_update, available_commands_update).", "hasChildren": true @@ -264,7 +302,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agents", "help": "Agent runtime configuration root covering defaults and explicit agent entries used for routing and execution context. Keep this section explicit so model/tool behavior stays predictable across multi-agent workflows.", "hasChildren": true @@ -276,7 +316,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent Defaults", "help": "Shared default settings inherited by agents unless overridden per entry in agents.list. Use defaults to enforce consistent baseline behavior and reduce duplicated per-agent configuration.", "hasChildren": true @@ -388,7 +430,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Bootstrap Max Chars", "help": "Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).", "hasChildren": false @@ -400,7 +444,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Bootstrap Prompt Truncation Warning", "help": "Inject agent-visible warning text when bootstrap files are truncated: \"off\", \"once\" (default), or \"always\".", "hasChildren": false @@ -412,7 +458,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Bootstrap Total Max Chars", "help": "Max total characters across all injected workspace bootstrap files (default: 150000).", "hasChildren": false @@ -424,7 +472,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "CLI Backends", "help": "Optional CLI backends for text-only fallback (claude-cli, etc.).", "hasChildren": true @@ -846,7 +896,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction", "help": "Compaction tuning for when context nears token limits, including history share, reserve headroom, and pre-compaction memory flush behavior. Use this when long-running sessions need stable continuity under tight context windows.", "hasChildren": true @@ -868,7 +920,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Identifier Instructions", "help": "Custom identifier-preservation instruction text used when identifierPolicy=\"custom\". Keep this explicit and safety-focused so compaction summaries do not rewrite opaque IDs, URLs, hosts, or ports.", "hasChildren": false @@ -880,7 +934,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Compaction Identifier Policy", "help": "Identifier-preservation policy for compaction summaries: \"strict\" prepends built-in opaque-identifier retention guidance (default), \"off\" disables this prefix, and \"custom\" uses identifierInstructions. Keep \"strict\" unless you have a specific compatibility need.", "hasChildren": false @@ -892,7 +948,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Compaction Keep Recent Tokens", "help": "Minimum token budget preserved from the most recent conversation window during compaction. Use higher values to protect immediate context continuity and lower values to keep more long-tail history.", "hasChildren": false @@ -904,7 +963,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Compaction Max History Share", "help": "Maximum fraction of total context budget allowed for retained history after compaction (range 0.1-0.9). Use lower shares for more generation headroom or higher shares for deeper historical continuity.", "hasChildren": false @@ -916,7 +977,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Memory Flush", "help": "Pre-compaction memory flush settings that run an agentic memory write before heavy compaction. Keep enabled for long sessions so salient context is persisted before aggressive trimming.", "hasChildren": true @@ -928,7 +991,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Memory Flush Enabled", "help": "Enables pre-compaction memory flush before the runtime performs stronger history reduction near token limits. Keep enabled unless you intentionally disable memory side effects in constrained environments.", "hasChildren": false @@ -936,11 +1001,16 @@ { "path": "agents.defaults.compaction.memoryFlush.forceFlushTranscriptBytes", "kind": "core", - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Memory Flush Transcript Size Threshold", "help": "Forces pre-compaction memory flush when transcript file size reaches this threshold (bytes or strings like \"2mb\"). Use this to prevent long-session hangs even when token counters are stale; set to 0 to disable.", "hasChildren": false @@ -952,7 +1022,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Memory Flush Prompt", "help": "User-prompt template used for the pre-compaction memory flush turn when generating memory candidates. Use this only when you need custom extraction instructions beyond the default memory flush behavior.", "hasChildren": false @@ -964,7 +1036,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Compaction Memory Flush Soft Threshold", "help": "Threshold distance to compaction (in tokens) that triggers pre-compaction memory flush execution. Use earlier thresholds for safer persistence, or tighter thresholds for lower flush frequency.", "hasChildren": false @@ -976,7 +1051,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Memory Flush System Prompt", "help": "System-prompt override for the pre-compaction memory flush turn to control extraction style and safety constraints. Use carefully so custom instructions do not reduce memory quality or leak sensitive context.", "hasChildren": false @@ -988,7 +1065,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Mode", "help": "Compaction strategy mode: \"default\" uses baseline behavior, while \"safeguard\" applies stricter guardrails to preserve recent context. Keep \"default\" unless you observe aggressive history loss near limit boundaries.", "hasChildren": false @@ -1000,7 +1079,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Compaction Model Override", "help": "Optional provider/model override used only for compaction summarization. Set this when you want compaction to run on a different model than the session default, and leave it unset to keep using the primary agent model.", "hasChildren": false @@ -1012,7 +1093,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Post-Compaction Context Sections", "help": "AGENTS.md H2/H3 section names re-injected after compaction so the agent reruns critical startup guidance. Leave unset to use \"Session Startup\"/\"Red Lines\" with legacy fallback to \"Every Session\"/\"Safety\"; set to [] to disable reinjection entirely.", "hasChildren": true @@ -1032,10 +1115,16 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["off", "async", "await"], + "enumValues": [ + "off", + "async", + "await" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Post-Index Sync", "help": "Controls post-compaction session memory reindex mode: \"off\", \"async\", or \"await\" (default: \"async\"). Use \"await\" for strongest freshness, \"async\" for lower compaction latency, and \"off\" only when session-memory sync is handled elsewhere.", "hasChildren": false @@ -1047,7 +1136,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Quality Guard", "help": "Optional quality-audit retry settings for safeguard compaction summaries. Leave this disabled unless you explicitly want summary audits and one-shot regeneration on failed checks.", "hasChildren": true @@ -1059,7 +1150,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Quality Guard Enabled", "help": "Enables summary quality audits and regeneration retries for safeguard compaction. Default: false, so safeguard mode alone does not turn on retry behavior.", "hasChildren": false @@ -1071,7 +1164,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Compaction Quality Guard Max Retries", "help": "Maximum number of regeneration retries after a failed safeguard summary quality audit. Use small values to bound extra latency and token cost.", "hasChildren": false @@ -1083,7 +1178,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Compaction Preserve Recent Turns", "help": "Number of most recent user/assistant turns kept verbatim outside safeguard summarization (default: 3). Raise this to preserve exact recent dialogue context, or lower it to maximize compaction savings.", "hasChildren": false @@ -1095,7 +1192,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Compaction Reserve Tokens", "help": "Token headroom reserved for reply generation and tool output after compaction runs. Use higher reserves for verbose/tool-heavy sessions, and lower reserves when maximizing retained history matters more.", "hasChildren": false @@ -1107,7 +1207,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Compaction Reserve Token Floor", "help": "Minimum floor enforced for reserveTokens in Pi compaction paths (0 disables the floor guard). Use a non-zero floor to avoid over-aggressive compression under fluctuating token estimates.", "hasChildren": false @@ -1119,7 +1222,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Compaction Timeout (Seconds)", "help": "Maximum time in seconds allowed for a single compaction operation before it is aborted (default: 900). Increase this for very large sessions that need more time to summarize, or decrease it to fail faster on unresponsive models.", "hasChildren": false @@ -1341,7 +1446,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Embedded Pi", "help": "Embedded Pi runner hardening controls for how workspace-local Pi settings are trusted and applied in OpenClaw sessions.", "hasChildren": true @@ -1353,7 +1460,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Embedded Pi Project Settings Policy", "help": "How embedded Pi handles workspace-local `.pi/config/settings.json`: \"sanitize\" (default) strips shellPath/shellCommandPrefix, \"ignore\" disables project settings entirely, and \"trusted\" applies project settings as-is.", "hasChildren": false @@ -1365,7 +1474,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Envelope Elapsed", "help": "Include elapsed time in message envelopes (\"on\" or \"off\").", "hasChildren": false @@ -1377,7 +1488,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Envelope Timestamp", "help": "Include absolute timestamps in message envelopes (\"on\" or \"off\").", "hasChildren": false @@ -1389,7 +1502,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Envelope Timezone", "help": "Timezone for message envelopes (\"utc\", \"local\", \"user\", or an IANA timezone string).", "hasChildren": false @@ -1471,7 +1586,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "automation", "storage"], + "tags": [ + "access", + "automation", + "storage" + ], "label": "Heartbeat Direct Policy", "help": "Controls whether heartbeat delivery may target direct/DM chats: \"allow\" (default) permits DM delivery and \"block\" suppresses direct-target sends.", "hasChildren": false @@ -1553,7 +1672,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Heartbeat Suppress Tool Error Warnings", "help": "Suppress tool error warning payloads during heartbeat runs.", "hasChildren": false @@ -1565,7 +1686,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, synology-chat, tlon, twitch, zalo, zalouser.", "hasChildren": false }, @@ -1596,7 +1719,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Human Delay Max (ms)", "help": "Maximum delay in ms for custom humanDelay (default: 2500).", "hasChildren": false @@ -1608,7 +1733,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Human Delay Min (ms)", "help": "Minimum delay in ms for custom humanDelay (default: 800).", "hasChildren": false @@ -1620,7 +1747,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Human Delay Mode", "help": "Delay style for block replies (\"off\", \"natural\", \"custom\").", "hasChildren": false @@ -1632,7 +1761,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance"], + "tags": [ + "media", + "performance" + ], "label": "Image Max Dimension (px)", "help": "Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).", "hasChildren": false @@ -1640,7 +1772,10 @@ { "path": "agents.defaults.imageModel", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -1654,7 +1789,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models", "reliability"], + "tags": [ + "media", + "models", + "reliability" + ], "label": "Image Model Fallbacks", "help": "Ordered fallback image models (provider/model).", "hasChildren": true @@ -1676,7 +1815,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models"], + "tags": [ + "media", + "models" + ], "label": "Image Model", "help": "Optional image model (provider/model) used when the primary model lacks image input.", "hasChildren": false @@ -1708,7 +1850,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search", "help": "Vector search over MEMORY.md and memory/*.md (per-agent overrides supported).", "hasChildren": true @@ -1730,7 +1874,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Search Embedding Cache", "help": "Caches computed chunk embeddings in SQLite so reindexing and incremental updates run faster (default: true). Keep this enabled unless investigating cache correctness or minimizing disk usage.", "hasChildren": false @@ -1742,7 +1888,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Memory Search Embedding Cache Max Entries", "help": "Sets a best-effort upper bound on cached embeddings kept in SQLite for memory search. Use this when controlling disk growth matters more than peak reindex speed.", "hasChildren": false @@ -1764,7 +1913,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Chunk Overlap Tokens", "help": "Token overlap between adjacent memory chunks to preserve context continuity near split boundaries. Use modest overlap to reduce boundary misses without inflating index size too aggressively.", "hasChildren": false @@ -1776,7 +1927,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Memory Chunk Tokens", "help": "Chunk size in tokens used when splitting memory sources before embedding/indexing. Increase for broader context per chunk, or lower to improve precision on pinpoint lookups.", "hasChildren": false @@ -1788,7 +1942,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Memory Search", "help": "Master toggle for memory search indexing and retrieval behavior on this agent profile. Keep enabled for semantic recall, and disable when you want fully stateless responses.", "hasChildren": false @@ -1810,7 +1966,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "security", "storage"], + "tags": [ + "advanced", + "security", + "storage" + ], "label": "Memory Search Session Index (Experimental)", "help": "Indexes session transcripts into memory search so responses can reference prior chat turns. Keep this off unless transcript recall is needed, because indexing cost and storage usage both increase.", "hasChildren": false @@ -1822,7 +1982,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Extra Memory Paths", "help": "Adds extra directories or .md files to the memory index beyond default memory files. Use this when key reference docs live elsewhere in your repo; when multimodal memory is enabled, matching image/audio files under these paths are also eligible for indexing.", "hasChildren": true @@ -1844,7 +2006,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["reliability"], + "tags": [ + "reliability" + ], "label": "Memory Search Fallback", "help": "Backup provider used when primary embeddings fail: \"openai\", \"gemini\", \"voyage\", \"mistral\", \"ollama\", \"local\", or \"none\". Set a real fallback for production reliability; use \"none\" only if you prefer explicit failures.", "hasChildren": false @@ -1876,7 +2040,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Local Embedding Model Path", "help": "Specifies the local embedding model source for local memory search, such as a GGUF file path or `hf:` URI. Use this only when provider is `local`, and verify model compatibility before large index rebuilds.", "hasChildren": false @@ -1888,7 +2054,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Memory Search Model", "help": "Embedding model override used by the selected memory provider when a non-default model is required. Set this only when you need explicit recall quality/cost tuning beyond provider defaults.", "hasChildren": false @@ -1900,7 +2068,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Multimodal", "help": "Optional multimodal memory settings for indexing image and audio files from configured extra paths. Keep this off unless your embedding model explicitly supports cross-modal embeddings, and set `memorySearch.fallback` to \"none\" while it is enabled. Matching files are uploaded to the configured remote embedding provider during indexing.", "hasChildren": true @@ -1912,7 +2082,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Memory Search Multimodal", "help": "Enables image/audio memory indexing from extraPaths. This currently requires Gemini embedding-2, keeps the default memory roots Markdown-only, disables memory-search fallback providers, and uploads matching binary content to the configured remote embedding provider.", "hasChildren": false @@ -1924,7 +2096,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Memory Search Multimodal Max File Bytes", "help": "Sets the maximum bytes allowed per multimodal file before it is skipped during memory indexing. Use this to cap upload cost and indexing latency, or raise it for short high-quality audio clips.", "hasChildren": false @@ -1936,7 +2111,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Multimodal Modalities", "help": "Selects which multimodal file types are indexed from extraPaths: \"image\", \"audio\", or \"all\". Keep this narrow to avoid indexing large binary corpora unintentionally.", "hasChildren": true @@ -1958,7 +2135,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Output Dimensionality", "help": "Gemini embedding-2 only: chooses the output vector size for memory embeddings. Use 768, 1536, or 3072 (default), and expect a full reindex when you change it because stored vector dimensions must stay consistent.", "hasChildren": false @@ -1970,7 +2149,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Provider", "help": "Selects the embedding backend used to build/query memory vectors: \"openai\", \"gemini\", \"voyage\", \"mistral\", \"ollama\", or \"local\". Keep your most reliable provider here and configure fallback for resilience.", "hasChildren": false @@ -2002,7 +2183,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Hybrid Candidate Multiplier", "help": "Expands the candidate pool before reranking (default: 4). Raise this for better recall on noisy corpora, but expect more compute and slightly slower searches.", "hasChildren": false @@ -2014,7 +2197,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Hybrid", "help": "Combines BM25 keyword matching with vector similarity for better recall on mixed exact + semantic queries. Keep enabled unless you are isolating ranking behavior for troubleshooting.", "hasChildren": false @@ -2036,7 +2221,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search MMR Re-ranking", "help": "Adds MMR reranking to diversify results and reduce near-duplicate snippets in a single answer window. Enable when recall looks repetitive; keep off for strict score ordering.", "hasChildren": false @@ -2048,7 +2235,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search MMR Lambda", "help": "Sets MMR relevance-vs-diversity balance (0 = most diverse, 1 = most relevant, default: 0.7). Lower values reduce repetition; higher values keep tightly relevant but may duplicate.", "hasChildren": false @@ -2070,7 +2259,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Temporal Decay", "help": "Applies recency decay so newer memory can outrank older memory when scores are close. Enable when timeliness matters; keep off for timeless reference knowledge.", "hasChildren": false @@ -2082,7 +2273,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Temporal Decay Half-life (Days)", "help": "Controls how fast older memory loses rank when temporal decay is enabled (half-life in days, default: 30). Lower values prioritize recent context more aggressively.", "hasChildren": false @@ -2094,7 +2287,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Text Weight", "help": "Controls how strongly BM25 keyword relevance influences hybrid ranking (0-1). Increase for exact-term matching; decrease when semantic matches should rank higher.", "hasChildren": false @@ -2106,7 +2301,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Vector Weight", "help": "Controls how strongly semantic similarity influences hybrid ranking (0-1). Increase when paraphrase matching matters more than exact terms; decrease for stricter keyword emphasis.", "hasChildren": false @@ -2118,7 +2315,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Memory Search Max Results", "help": "Maximum number of memory hits returned from search before downstream reranking and prompt injection. Raise for broader recall, or lower for tighter prompts and faster responses.", "hasChildren": false @@ -2130,7 +2329,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Min Score", "help": "Minimum relevance score threshold for including memory results in final recall output. Increase to reduce weak/noisy matches, or lower when you need more permissive retrieval.", "hasChildren": false @@ -2148,11 +2349,17 @@ { "path": "agents.defaults.memorySearch.remote.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Remote Embedding API Key", "help": "Supplies a dedicated API key for remote embedding calls used by memory indexing and query-time embeddings. Use this when memory embeddings should use different credentials than global defaults or environment variables.", "hasChildren": true @@ -2194,7 +2401,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Remote Embedding Base URL", "help": "Overrides the embedding API endpoint, such as an OpenAI-compatible proxy or custom Gemini base URL. Use this only when routing through your own gateway or vendor endpoint; keep provider defaults otherwise.", "hasChildren": false @@ -2216,7 +2425,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Remote Batch Concurrency", "help": "Limits how many embedding batch jobs run at the same time during indexing (default: 2). Increase carefully for faster bulk indexing, but watch provider rate limits and queue errors.", "hasChildren": false @@ -2228,7 +2439,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Remote Batch Embedding Enabled", "help": "Enables provider batch APIs for embedding jobs when supported (OpenAI/Gemini), improving throughput on larger index runs. Keep this enabled unless debugging provider batch failures or running very small workloads.", "hasChildren": false @@ -2240,7 +2453,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Remote Batch Poll Interval (ms)", "help": "Controls how often the system polls provider APIs for batch job status in milliseconds (default: 2000). Use longer intervals to reduce API chatter, or shorter intervals for faster completion detection.", "hasChildren": false @@ -2252,7 +2467,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Remote Batch Timeout (min)", "help": "Sets the maximum wait time for a full embedding batch operation in minutes (default: 60). Increase for very large corpora or slower providers, and lower it to fail fast in automation-heavy flows.", "hasChildren": false @@ -2264,7 +2481,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Remote Batch Wait for Completion", "help": "Waits for batch embedding jobs to fully finish before the indexing operation completes. Keep this enabled for deterministic indexing state; disable only if you accept delayed consistency.", "hasChildren": false @@ -2276,7 +2495,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Remote Embedding Headers", "help": "Adds custom HTTP headers to remote embedding requests, merged with provider defaults. Use this for proxy auth and tenant routing headers, and keep values minimal to avoid leaking sensitive metadata.", "hasChildren": true @@ -2298,7 +2519,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Search Sources", "help": "Chooses which sources are indexed: \"memory\" reads MEMORY.md + memory files, and \"sessions\" includes transcript history. Keep [\"memory\"] unless you need recall from prior chat transcripts.", "hasChildren": true @@ -2340,7 +2563,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Search Index Path", "help": "Sets where the SQLite memory index is stored on disk for each agent. Keep the default `~/.openclaw/memory/{agentId}.sqlite` unless you need custom storage placement or backup policy alignment.", "hasChildren": false @@ -2362,7 +2587,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Search Vector Index", "help": "Enables the sqlite-vec extension used for vector similarity queries in memory search (default: true). Keep this enabled for normal semantic recall; disable only for debugging or fallback-only operation.", "hasChildren": false @@ -2374,7 +2601,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Search Vector Extension Path", "help": "Overrides the auto-discovered sqlite-vec extension library path (`.dylib`, `.so`, or `.dll`). Use this when your runtime cannot find sqlite-vec automatically or you pin a known-good build.", "hasChildren": false @@ -2406,7 +2635,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Index on Search (Lazy)", "help": "Uses lazy sync by scheduling reindex on search after content changes are detected. Keep enabled for lower idle overhead, or disable if you require pre-synced indexes before any query.", "hasChildren": false @@ -2418,7 +2649,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "storage"], + "tags": [ + "automation", + "storage" + ], "label": "Index on Session Start", "help": "Triggers a memory index sync when a session starts so early turns see fresh memory content. Keep enabled when startup freshness matters more than initial turn latency.", "hasChildren": false @@ -2440,7 +2674,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Delta Bytes", "help": "Requires at least this many newly appended bytes before session transcript changes trigger reindex (default: 100000). Increase to reduce frequent small reindexes, or lower for faster transcript freshness.", "hasChildren": false @@ -2452,7 +2688,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Delta Messages", "help": "Requires at least this many appended transcript messages before reindex is triggered (default: 50). Lower this for near-real-time transcript recall, or raise it to reduce indexing churn.", "hasChildren": false @@ -2464,7 +2702,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Force Reindex After Compaction", "help": "Forces a session memory-search reindex after compaction-triggered transcript updates (default: true). Keep enabled when compacted summaries must be immediately searchable, or disable to reduce write-time indexing pressure.", "hasChildren": false @@ -2476,7 +2716,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Watch Memory Files", "help": "Watches memory files and schedules index updates from file-change events (chokidar). Enable for near-real-time freshness; disable on very large workspaces if watch churn is too noisy.", "hasChildren": false @@ -2488,7 +2730,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "performance"], + "tags": [ + "automation", + "performance" + ], "label": "Memory Watch Debounce (ms)", "help": "Debounce window in milliseconds for coalescing rapid file-watch events before reindex runs. Increase to reduce churn on frequently-written files, or lower for faster freshness.", "hasChildren": false @@ -2496,7 +2741,10 @@ { "path": "agents.defaults.model", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -2510,7 +2758,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "reliability"], + "tags": [ + "models", + "reliability" + ], "label": "Model Fallbacks", "help": "Ordered fallback models (provider/model). Used when the primary model fails.", "hasChildren": true @@ -2532,7 +2783,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Primary Model", "help": "Primary model (provider/model).", "hasChildren": false @@ -2544,7 +2797,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Models", "help": "Configured model catalog (keys are full provider/model IDs).", "hasChildren": true @@ -2605,7 +2860,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "PDF Max Size (MB)", "help": "Maximum PDF file size in megabytes for the PDF tool (default: 10).", "hasChildren": false @@ -2617,7 +2874,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "PDF Max Pages", "help": "Maximum number of PDF pages to process for the PDF tool (default: 20).", "hasChildren": false @@ -2625,7 +2884,10 @@ { "path": "agents.defaults.pdfModel", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -2639,7 +2901,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["reliability"], + "tags": [ + "reliability" + ], "label": "PDF Model Fallbacks", "help": "Ordered fallback PDF models (provider/model).", "hasChildren": true @@ -2661,7 +2925,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "PDF Model", "help": "Optional PDF model (provider/model) for the PDF analysis tool. Defaults to imageModel, then session model.", "hasChildren": false @@ -2673,7 +2939,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Repo Root", "help": "Optional repository root shown in the system prompt runtime line (overrides auto-detect).", "hasChildren": false @@ -2765,7 +3033,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Sandbox Browser CDP Source Port Range", "help": "Optional CIDR allowlist for container-edge CDP ingress (for example 172.21.0.1/32).", "hasChildren": false @@ -2827,7 +3097,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Sandbox Browser Network", "help": "Docker network for sandbox browser containers (default: openclaw-sandbox-browser). Avoid bridge if you need stricter isolation.", "hasChildren": false @@ -2939,7 +3211,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "security", "storage"], + "tags": [ + "access", + "advanced", + "security", + "storage" + ], "label": "Sandbox Docker Allow Container Namespace Join", "help": "DANGEROUS break-glass override that allows sandbox Docker network mode container:. This joins another container namespace and weakens sandbox isolation.", "hasChildren": false @@ -3037,7 +3314,10 @@ { "path": "agents.defaults.sandbox.docker.memory", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -3047,7 +3327,10 @@ { "path": "agents.defaults.sandbox.docker.memorySwap", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -3136,7 +3419,11 @@ { "path": "agents.defaults.sandbox.docker.ulimits.*", "kind": "core", - "type": ["number", "object", "string"], + "type": [ + "number", + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -3346,7 +3633,10 @@ { "path": "agents.defaults.subagents.model", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -3480,7 +3770,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Workspace", "help": "Default workspace path exposed to agent runtime tools for filesystem context and repo-aware behavior. Set this explicitly when running from wrappers so path resolution stays deterministic.", "hasChildren": false @@ -3492,7 +3784,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent List", "help": "Explicit list of configured agents with IDs and optional overrides for model, tools, identity, and workspace. Keep IDs stable over time so bindings, approvals, and session routing remain deterministic.", "hasChildren": true @@ -3644,7 +3938,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "automation", "storage"], + "tags": [ + "access", + "automation", + "storage" + ], "label": "Heartbeat Direct Policy", "help": "Per-agent override for heartbeat direct/DM delivery policy; use \"block\" for agents that should only send heartbeat alerts to non-DM destinations.", "hasChildren": false @@ -3726,7 +4024,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Agent Heartbeat Suppress Tool Error Warnings", "help": "Suppress tool error warning payloads during heartbeat runs.", "hasChildren": false @@ -3738,7 +4038,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, synology-chat, tlon, twitch, zalo, zalouser.", "hasChildren": false }, @@ -3819,7 +4121,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Identity Avatar", "help": "Agent avatar (workspace-relative path, http(s) URL, or data URI).", "hasChildren": false @@ -4247,11 +4551,17 @@ { "path": "agents.list.*.memorySearch.remote.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "hasChildren": true }, { @@ -4557,7 +4867,10 @@ { "path": "agents.list.*.model", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -4630,7 +4943,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent Runtime", "help": "Optional runtime descriptor for this agent. Use embedded for default OpenClaw execution or acp for external ACP harness defaults.", "hasChildren": true @@ -4642,7 +4957,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent ACP Runtime", "help": "ACP runtime defaults for this agent when runtime.type=acp. Binding-level ACP overrides still take precedence per conversation.", "hasChildren": true @@ -4654,7 +4971,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent ACP Harness Agent", "help": "Optional ACP harness agent id to use for this OpenClaw agent (for example codex, claude).", "hasChildren": false @@ -4666,7 +4985,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent ACP Backend", "help": "Optional ACP backend override for this agent's ACP sessions (falls back to global acp.backend).", "hasChildren": false @@ -4678,7 +4999,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent ACP Working Directory", "help": "Optional default working directory for this agent's ACP sessions.", "hasChildren": false @@ -4688,10 +5011,15 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["persistent", "oneshot"], + "enumValues": [ + "persistent", + "oneshot" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent ACP Mode", "help": "Optional ACP session mode default for this agent (persistent or oneshot).", "hasChildren": false @@ -4703,7 +5031,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent Runtime Type", "help": "Runtime type for this agent: \"embedded\" (default OpenClaw runtime) or \"acp\" (ACP harness defaults).", "hasChildren": false @@ -4795,7 +5125,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Agent Sandbox Browser CDP Source Port Range", "help": "Per-agent override for CDP source CIDR allowlist.", "hasChildren": false @@ -4857,7 +5189,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Agent Sandbox Browser Network", "help": "Per-agent override for sandbox browser Docker network.", "hasChildren": false @@ -4969,7 +5303,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "security", "storage"], + "tags": [ + "access", + "advanced", + "security", + "storage" + ], "label": "Agent Sandbox Docker Allow Container Namespace Join", "help": "Per-agent DANGEROUS override for container namespace joins in sandbox Docker network mode.", "hasChildren": false @@ -5067,7 +5406,10 @@ { "path": "agents.list.*.sandbox.docker.memory", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -5077,7 +5419,10 @@ { "path": "agents.list.*.sandbox.docker.memorySwap", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -5166,7 +5511,11 @@ { "path": "agents.list.*.sandbox.docker.ulimits.*", "kind": "core", - "type": ["number", "object", "string"], + "type": [ + "number", + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -5310,7 +5659,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent Skill Filter", "help": "Optional allowlist of skills for this agent (omit = all skills; empty = no skills).", "hasChildren": true @@ -5358,7 +5709,10 @@ { "path": "agents.list.*.subagents.model", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -5442,7 +5796,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Agent Tool Allowlist Additions", "help": "Per-agent additive allowlist for tools on top of global and profile policy. Keep narrow to avoid accidental privilege expansion on specialized agents.", "hasChildren": true @@ -5464,7 +5820,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Agent Tool Policy by Provider", "help": "Per-agent provider-specific tool policy overrides for channel-scoped capability control. Use this when a single agent needs tighter restrictions on one provider than others.", "hasChildren": true @@ -5602,7 +5960,10 @@ { "path": "agents.list.*.tools.elevated.allowFrom.*.*", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -5694,7 +6055,11 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["off", "on-miss", "always"], + "enumValues": [ + "off", + "on-miss", + "always" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -5725,7 +6090,11 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["sandbox", "gateway", "node"], + "enumValues": [ + "sandbox", + "gateway", + "node" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -5906,7 +6275,11 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["deny", "allowlist", "full"], + "enumValues": [ + "deny", + "allowlist", + "full" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -6049,7 +6422,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Agent Tool Profile", "help": "Per-agent override for tool profile selection when one agent needs a different capability baseline. Use this sparingly so policy differences across agents stay intentional and reviewable.", "hasChildren": false @@ -6151,7 +6526,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approvals", "help": "Approval routing controls for forwarding exec approval requests to chat destinations outside the originating session. Keep this disabled unless operators need explicit out-of-band approval visibility.", "hasChildren": true @@ -6163,7 +6540,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Exec Approval Forwarding", "help": "Groups exec-approval forwarding behavior including enablement, routing mode, filters, and explicit targets. Configure here when approval prompts must reach operational channels instead of only the origin thread.", "hasChildren": true @@ -6175,7 +6554,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Agent Filter", "help": "Optional allowlist of agent IDs eligible for forwarded approvals, for example `[\"primary\", \"ops-agent\"]`. Use this to limit forwarding blast radius and avoid notifying channels for unrelated agents.", "hasChildren": true @@ -6197,7 +6578,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Forward Exec Approvals", "help": "Enables forwarding of exec approval requests to configured delivery destinations (default: false). Keep disabled in low-risk setups and enable only when human approval responders need channel-visible prompts.", "hasChildren": false @@ -6209,7 +6592,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Forwarding Mode", "help": "Controls where approval prompts are sent: \"session\" uses origin chat, \"targets\" uses configured targets, and \"both\" sends to both paths. Use \"session\" as baseline and expand only when operational workflow requires redundancy.", "hasChildren": false @@ -6221,7 +6606,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Approval Session Filter", "help": "Optional session-key filters matched as substring or regex-style patterns, for example `[\"discord:\", \"^agent:ops:\"]`. Use narrow patterns so only intended approval contexts are forwarded to shared destinations.", "hasChildren": true @@ -6243,7 +6630,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Forwarding Targets", "help": "Explicit delivery targets used when forwarding mode includes targets, each with channel and destination details. Keep target lists least-privilege and validate each destination before enabling broad forwarding.", "hasChildren": true @@ -6265,7 +6654,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Target Account ID", "help": "Optional account selector for multi-account channel setups when approvals must route through a specific account context. Use this only when the target channel has multiple configured identities.", "hasChildren": false @@ -6277,7 +6668,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Target Channel", "help": "Channel/provider ID used for forwarded approval delivery, such as discord, slack, or a plugin channel id. Use valid channel IDs only so approvals do not silently fail due to unknown routes.", "hasChildren": false @@ -6285,11 +6678,16 @@ { "path": "approvals.exec.targets.*.threadId", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Target Thread ID", "help": "Optional thread/topic target for channels that support threaded delivery of forwarded approvals. Use this to keep approval traffic contained in operational threads instead of main channels.", "hasChildren": false @@ -6301,7 +6699,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Approval Target Destination", "help": "Destination identifier inside the target channel (channel ID, user ID, or thread root depending on provider). Verify semantics per provider because destination format differs across channel integrations.", "hasChildren": false @@ -6313,7 +6713,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Audio", "help": "Global audio ingestion settings used before higher-level tools process speech or media content. Configure this when you need deterministic transcription behavior for voice notes and clips.", "hasChildren": true @@ -6325,7 +6727,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Audio Transcription", "help": "Command-based transcription settings for converting audio files into text before agent handling. Keep a simple, deterministic command path here so failures are easy to diagnose in logs.", "hasChildren": true @@ -6337,7 +6741,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Audio Transcription Command", "help": "Executable + args used to transcribe audio (first token must be a safe binary/path), for example `[\"whisper-cli\", \"--model\", \"small\", \"{input}\"]`. Prefer a pinned command so runtime environments behave consistently.", "hasChildren": true @@ -6359,7 +6765,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance"], + "tags": [ + "media", + "performance" + ], "label": "Audio Transcription Timeout (sec)", "help": "Maximum time allowed for the transcription command to finish before it is aborted. Increase this for longer recordings, and keep it tight in latency-sensitive deployments.", "hasChildren": false @@ -6371,7 +6780,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Auth", "help": "Authentication profile root used for multi-profile provider credentials and cooldown-based failover ordering. Keep profiles minimal and explicit so automatic failover behavior stays auditable.", "hasChildren": true @@ -6383,7 +6794,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth"], + "tags": [ + "access", + "auth" + ], "label": "Auth Cooldowns", "help": "Cooldown/backoff controls for temporary profile suppression after billing-related failures and retry windows. Use these to prevent rapid re-selection of profiles that are still blocked.", "hasChildren": true @@ -6395,7 +6809,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth", "reliability"], + "tags": [ + "access", + "auth", + "reliability" + ], "label": "Billing Backoff (hours)", "help": "Base backoff (hours) when a profile fails due to billing/insufficient credits (default: 5).", "hasChildren": false @@ -6407,7 +6825,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth", "reliability"], + "tags": [ + "access", + "auth", + "reliability" + ], "label": "Billing Backoff Overrides", "help": "Optional per-provider overrides for billing backoff (hours).", "hasChildren": true @@ -6429,7 +6851,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth", "performance"], + "tags": [ + "access", + "auth", + "performance" + ], "label": "Billing Backoff Cap (hours)", "help": "Cap (hours) for billing backoff (default: 24).", "hasChildren": false @@ -6441,7 +6867,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth"], + "tags": [ + "access", + "auth" + ], "label": "Failover Window (hours)", "help": "Failure window (hours) for backoff counters (default: 24).", "hasChildren": false @@ -6453,7 +6882,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth"], + "tags": [ + "access", + "auth" + ], "label": "Auth Profile Order", "help": "Ordered auth profile IDs per provider (used for automatic failover).", "hasChildren": true @@ -6485,7 +6917,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "auth", "storage"], + "tags": [ + "access", + "auth", + "storage" + ], "label": "Auth Profiles", "help": "Named auth profiles (provider + mode + optional email).", "hasChildren": true @@ -6537,7 +6973,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Bindings", "help": "Top-level binding rules for routing and persistent ACP conversation ownership. Use type=route for normal routing and type=acp for persistent ACP harness bindings.", "hasChildren": true @@ -6559,7 +6997,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Binding Overrides", "help": "Optional per-binding ACP overrides for bindings[].type=acp. This layer overrides agents.list[].runtime.acp defaults for the matched conversation.", "hasChildren": true @@ -6571,7 +7011,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Binding Backend", "help": "ACP backend override for this binding (falls back to agent runtime ACP backend, then global acp.backend).", "hasChildren": false @@ -6583,7 +7025,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Binding Working Directory", "help": "Working directory override for ACP sessions created from this binding.", "hasChildren": false @@ -6595,7 +7039,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Binding Label", "help": "Human-friendly label for ACP status/diagnostics in this bound conversation.", "hasChildren": false @@ -6605,10 +7051,15 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["persistent", "oneshot"], + "enumValues": [ + "persistent", + "oneshot" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACP Binding Mode", "help": "ACP session mode override for this binding (persistent or oneshot).", "hasChildren": false @@ -6620,7 +7071,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Agent ID", "help": "Target agent ID that receives traffic when the corresponding binding match rule is satisfied. Use valid configured agent IDs only so routing does not fail at runtime.", "hasChildren": false @@ -6642,7 +7095,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Match Rule", "help": "Match rule object for deciding when a binding applies, including channel and optional account/peer constraints. Keep rules narrow to avoid accidental agent takeover across contexts.", "hasChildren": true @@ -6654,7 +7109,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Account ID", "help": "Optional account selector for multi-account channel setups so the binding applies only to one identity. Use this when account scoping is required for the route and leave unset otherwise.", "hasChildren": false @@ -6666,7 +7123,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Channel", "help": "Channel/provider identifier this binding applies to, such as `telegram`, `discord`, or a plugin channel ID. Use the configured channel key exactly so binding evaluation works reliably.", "hasChildren": false @@ -6678,7 +7137,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Guild ID", "help": "Optional Discord-style guild/server ID constraint for binding evaluation in multi-server deployments. Use this when the same peer identifiers can appear across different guilds.", "hasChildren": false @@ -6690,7 +7151,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Peer Match", "help": "Optional peer matcher for specific conversations including peer kind and peer id. Use this when only one direct/group/channel target should be pinned to an agent.", "hasChildren": true @@ -6702,7 +7165,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Peer ID", "help": "Conversation identifier used with peer matching, such as a chat ID, channel ID, or group ID from the provider. Keep this exact to avoid silent non-matches.", "hasChildren": false @@ -6714,7 +7179,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Peer Kind", "help": "Peer conversation type: \"direct\", \"group\", \"channel\", or legacy \"dm\" (deprecated alias for direct). Prefer \"direct\" for new configs and keep kind aligned with channel semantics.", "hasChildren": false @@ -6726,7 +7193,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Roles", "help": "Optional role-based filter list used by providers that attach roles to chat context. Use this to route privileged or operational role traffic to specialized agents.", "hasChildren": true @@ -6748,7 +7217,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Team ID", "help": "Optional team/workspace ID constraint used by providers that scope chats under teams. Add this when you need bindings isolated to one workspace context.", "hasChildren": false @@ -6760,7 +7231,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Binding Type", "help": "Binding kind. Use \"route\" (or omit for legacy route entries) for normal routing, and \"acp\" for persistent ACP conversation bindings.", "hasChildren": false @@ -6772,7 +7245,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Broadcast", "help": "Broadcast routing map for sending the same outbound message to multiple peer IDs per source conversation. Keep this minimal and audited because one source can fan out to many destinations.", "hasChildren": true @@ -6784,7 +7259,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Broadcast Destination List", "help": "Per-source broadcast destination list where each key is a source peer ID and the value is an array of destination peer IDs. Keep lists intentional to avoid accidental message amplification.", "hasChildren": true @@ -6804,10 +7281,15 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["parallel", "sequential"], + "enumValues": [ + "parallel", + "sequential" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Broadcast Strategy", "help": "Delivery order for broadcast fan-out: \"parallel\" sends to all targets concurrently, while \"sequential\" sends one-by-one. Use \"parallel\" for speed and \"sequential\" for stricter ordering/backpressure control.", "hasChildren": false @@ -6819,7 +7301,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser", "help": "Browser runtime controls for local or remote CDP attachment, profile routing, and screenshot/snapshot behavior. Keep defaults unless your automation workflow requires custom browser transport settings.", "hasChildren": true @@ -6831,7 +7315,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Attach-only Mode", "help": "Restricts browser mode to attach-only behavior without starting local browser processes. Use this when all browser sessions are externally managed by a remote CDP provider.", "hasChildren": false @@ -6843,7 +7329,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser CDP Port Range Start", "help": "Starting local CDP port used for auto-allocated browser profile ports. Increase this when host-level port defaults conflict with other local services.", "hasChildren": false @@ -6855,7 +7343,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser CDP URL", "help": "Remote CDP websocket URL used to attach to an externally managed browser instance. Use this for centralized browser hosts and keep URL access restricted to trusted network paths.", "hasChildren": false @@ -6867,7 +7357,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Accent Color", "help": "Default accent color used for browser profile/UI cues where colored identity hints are displayed. Use consistent colors to help operators identify active browser profile context quickly.", "hasChildren": false @@ -6879,7 +7371,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Default Profile", "help": "Default browser profile name selected when callers do not explicitly choose a profile. Use a stable low-privilege profile as the default to reduce accidental cross-context state use.", "hasChildren": false @@ -6891,7 +7385,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Enabled", "help": "Enables browser capability wiring in the gateway so browser tools and CDP-driven workflows can run. Disable when browser automation is not needed to reduce surface area and startup work.", "hasChildren": false @@ -6903,7 +7399,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Evaluate Enabled", "help": "Enables browser-side evaluate helpers for runtime script evaluation capabilities where supported. Keep disabled unless your workflows require evaluate semantics beyond snapshots/navigation.", "hasChildren": false @@ -6915,7 +7413,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Executable Path", "help": "Explicit browser executable path when auto-discovery is insufficient for your host environment. Use absolute stable paths so launch behavior stays deterministic across restarts.", "hasChildren": false @@ -6947,7 +7447,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Headless Mode", "help": "Forces browser launch in headless mode when the local launcher starts browser instances. Keep headless enabled for server environments and disable only when visible UI debugging is required.", "hasChildren": false @@ -6959,7 +7461,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser No-Sandbox Mode", "help": "Disables Chromium sandbox isolation flags for environments where sandboxing fails at runtime. Keep this off whenever possible because process isolation protections are reduced.", "hasChildren": false @@ -6971,7 +7475,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profiles", "help": "Named browser profile connection map used for explicit routing to CDP ports or URLs with optional metadata. Keep profile names consistent and avoid overlapping endpoint definitions.", "hasChildren": true @@ -6993,7 +7499,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profile Attach-only Mode", "help": "Per-profile attach-only override that skips local browser launch and only attaches to an existing CDP endpoint. Useful when one profile is externally managed but others are locally launched.", "hasChildren": false @@ -7005,7 +7513,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profile CDP Port", "help": "Per-profile local CDP port used when connecting to browser instances by port instead of URL. Use unique ports per profile to avoid connection collisions.", "hasChildren": false @@ -7017,7 +7527,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profile CDP URL", "help": "Per-profile CDP websocket URL used for explicit remote browser routing by profile name. Use this when profile connections terminate on remote hosts or tunnels.", "hasChildren": false @@ -7029,7 +7541,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profile Accent Color", "help": "Per-profile accent color for visual differentiation in dashboards and browser-related UI hints. Use distinct colors for high-signal operator recognition of active profiles.", "hasChildren": false @@ -7041,7 +7555,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Browser Profile Driver", "help": "Per-profile browser driver mode: \"openclaw\" (or legacy \"clawd\") or \"extension\" depending on connection/runtime strategy. Use the driver that matches your browser control stack to avoid protocol mismatches.", "hasChildren": false @@ -7053,7 +7569,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Relay Bind Address", "help": "Bind IP address for the Chrome extension relay listener. Leave unset for loopback-only access, or set an explicit non-loopback IP such as 0.0.0.0 only when the relay must be reachable across network namespaces (for example WSL2) and the surrounding network is already trusted.", "hasChildren": false @@ -7065,7 +7583,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Remote CDP Handshake Timeout (ms)", "help": "Timeout in milliseconds for post-connect CDP handshake readiness checks against remote browser targets. Raise this for slow-start remote browsers and lower to fail fast in automation loops.", "hasChildren": false @@ -7077,7 +7597,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Remote CDP Timeout (ms)", "help": "Timeout in milliseconds for connecting to a remote CDP endpoint before failing the browser attach attempt. Increase for high-latency tunnels, or lower for faster failure detection.", "hasChildren": false @@ -7089,7 +7611,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Snapshot Defaults", "help": "Default snapshot capture configuration used when callers do not provide explicit snapshot options. Tune this for consistent capture behavior across channels and automation paths.", "hasChildren": true @@ -7101,7 +7625,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Browser Snapshot Mode", "help": "Default snapshot extraction mode controlling how page content is transformed for agent consumption. Choose the mode that balances readability, fidelity, and token footprint for your workflows.", "hasChildren": false @@ -7113,7 +7639,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Browser SSRF Policy", "help": "Server-side request forgery guardrail settings for browser/network fetch paths that could reach internal hosts. Keep restrictive defaults in production and open only explicitly approved targets.", "hasChildren": true @@ -7125,7 +7653,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Browser Allowed Hostnames", "help": "Explicit hostname allowlist exceptions for SSRF policy checks on browser/network requests. Keep this list minimal and review entries regularly to avoid stale broad access.", "hasChildren": true @@ -7147,7 +7677,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Browser Allow Private Network", "help": "Legacy alias for browser.ssrfPolicy.dangerouslyAllowPrivateNetwork. Prefer the dangerously-named key so risk intent is explicit.", "hasChildren": false @@ -7159,7 +7691,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "security"], + "tags": [ + "access", + "advanced", + "security" + ], "label": "Browser Dangerously Allow Private Network", "help": "Allows access to private-network address ranges from browser tooling. Default is enabled for trusted-network operator setups; disable to enforce strict public-only resolution checks.", "hasChildren": false @@ -7171,7 +7707,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Browser Hostname Allowlist", "help": "Legacy/alternate hostname allowlist field used by SSRF policy consumers for explicit host exceptions. Use stable exact hostnames and avoid wildcard-like broad patterns.", "hasChildren": true @@ -7193,7 +7731,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Canvas Host", "help": "Canvas host settings for serving canvas assets and local live-reload behavior used by canvas-enabled workflows. Keep disabled unless canvas-hosted assets are actively used.", "hasChildren": true @@ -7205,7 +7745,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Canvas Host Enabled", "help": "Enables the canvas host server process and routes for serving canvas files. Keep disabled when canvas workflows are inactive to reduce exposed local services.", "hasChildren": false @@ -7217,7 +7759,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["reliability"], + "tags": [ + "reliability" + ], "label": "Canvas Host Live Reload", "help": "Enables automatic live-reload behavior for canvas assets during development workflows. Keep disabled in production-like environments where deterministic output is preferred.", "hasChildren": false @@ -7229,7 +7773,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Canvas Host Port", "help": "TCP port used by the canvas host HTTP server when canvas hosting is enabled. Choose a non-conflicting port and align firewall/proxy policy accordingly.", "hasChildren": false @@ -7241,7 +7787,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Canvas Host Root Directory", "help": "Filesystem root directory served by canvas host for canvas content and static assets. Use a dedicated directory and avoid broad repo roots for least-privilege file exposure.", "hasChildren": false @@ -7253,7 +7801,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Channels", "help": "Channel provider configurations plus shared defaults that control access policies, heartbeat visibility, and per-surface behavior. Keep defaults centralized and override per provider only where required.", "hasChildren": true @@ -7265,7 +7815,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "BlueBubbles", "help": "iMessage via the BlueBubbles mac app + REST API.", "hasChildren": true @@ -7303,7 +7856,10 @@ { "path": "channels.bluebubbles.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -7335,7 +7891,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -7356,7 +7915,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -7385,7 +7949,10 @@ { "path": "channels.bluebubbles.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -7397,7 +7964,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -7528,7 +8099,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -7577,11 +8152,19 @@ { "path": "channels.bluebubbles.accounts.*.password", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -7798,7 +8381,10 @@ { "path": "channels.bluebubbles.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -7830,7 +8416,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -7861,10 +8450,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "BlueBubbles DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.bluebubbles.allowFrom=[\"*\"].", "hasChildren": false @@ -7892,7 +8490,10 @@ { "path": "channels.bluebubbles.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -7904,7 +8505,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8035,7 +8640,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8084,11 +8693,19 @@ { "path": "channels.bluebubbles.password", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -8168,7 +8785,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord", "help": "very well supported right now.", "hasChildren": true @@ -8208,7 +8828,14 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], + "enumValues": [ + "group-mentions", + "group-all", + "direct", + "all", + "off", + "none" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8467,7 +9094,10 @@ { "path": "channels.discord.accounts.*.allowBots", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8487,7 +9117,10 @@ { "path": "channels.discord.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8639,7 +9272,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8658,7 +9294,10 @@ { "path": "channels.discord.accounts.*.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8668,7 +9307,10 @@ { "path": "channels.discord.accounts.*.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8728,7 +9370,10 @@ { "path": "channels.discord.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8758,7 +9403,10 @@ { "path": "channels.discord.accounts.*.dm.groupChannels.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -8780,7 +9428,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8801,7 +9454,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -8970,7 +9628,10 @@ { "path": "channels.discord.accounts.*.execApprovals.approvers.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -9022,7 +9683,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["dm", "channel", "both"], + "enumValues": [ + "dm", + "channel", + "both" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9033,7 +9698,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -9093,9 +9762,17 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.autoArchiveDuration", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, - "enumValues": ["60", "1440", "4320", "10080"], + "enumValues": [ + "60", + "1440", + "4320", + "10080" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9164,7 +9841,10 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.roles.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -9364,7 +10044,10 @@ { "path": "channels.discord.accounts.*.guilds.*.channels.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -9386,7 +10069,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9415,7 +10103,10 @@ { "path": "channels.discord.accounts.*.guilds.*.roles.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -9595,7 +10286,10 @@ { "path": "channels.discord.accounts.*.guilds.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -9737,7 +10431,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9796,11 +10494,19 @@ { "path": "channels.discord.accounts.*.pluralkit.token", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -9938,7 +10644,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["online", "dnd", "idle", "invisible"], + "enumValues": [ + "online", + "dnd", + "idle", + "invisible" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9947,9 +10658,17 @@ { "path": "channels.discord.accounts.*.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -9960,7 +10679,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["partial", "block", "off"], + "enumValues": [ + "partial", + "block", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10039,11 +10762,19 @@ { "path": "channels.discord.accounts.*.token", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -10201,7 +10932,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "always", "inbound", "tagged"], + "enumValues": [ + "off", + "always", + "inbound", + "tagged" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10330,11 +11066,20 @@ { "path": "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "media", "network", "security"], + "tags": [ + "auth", + "channels", + "media", + "network", + "security" + ], "hasChildren": true }, { @@ -10372,7 +11117,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["auto", "on", "off"], + "enumValues": [ + "auto", + "on", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10513,7 +11262,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["final", "all"], + "enumValues": [ + "final", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10622,11 +11374,20 @@ { "path": "channels.discord.accounts.*.voice.tts.openai.apiKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "media", "network", "security"], + "tags": [ + "auth", + "channels", + "media", + "network", + "security" + ], "hasChildren": true }, { @@ -10724,7 +11485,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["elevenlabs", "openai", "edge"], + "enumValues": [ + "elevenlabs", + "openai", + "edge" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10765,7 +11530,14 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], + "enumValues": [ + "group-mentions", + "group-all", + "direct", + "all", + "off", + "none" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -10978,7 +11750,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Presence Activity", "help": "Discord presence activity text (defaults to custom status).", "hasChildren": false @@ -10990,7 +11765,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Presence Activity Type", "help": "Discord presence activity type (0=Playing,1=Streaming,2=Listening,3=Watching,4=Custom,5=Competing).", "hasChildren": false @@ -11002,7 +11780,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Presence Activity URL", "help": "Discord presence streaming URL (required for activityType=1).", "hasChildren": false @@ -11030,11 +11811,18 @@ { "path": "channels.discord.allowBots", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Discord Allow Bot Messages", "help": "Allow bot-authored messages to trigger Discord replies (default: false). Set \"mentions\" to only accept bot messages that mention the bot.", "hasChildren": false @@ -11052,7 +11840,10 @@ { "path": "channels.discord.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11076,7 +11867,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Auto Presence Degraded Text", "help": "Optional custom status text while runtime/model availability is degraded or unknown (idle).", "hasChildren": false @@ -11088,7 +11882,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Auto Presence Enabled", "help": "Enable automatic Discord bot presence updates based on runtime/model availability signals. When enabled: healthy=>online, degraded/unknown=>idle, exhausted/unavailable=>dnd.", "hasChildren": false @@ -11100,7 +11897,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Auto Presence Exhausted Text", "help": "Optional custom status text while runtime detects exhausted/unavailable model quota (dnd). Supports {reason} template placeholder.", "hasChildren": false @@ -11112,7 +11912,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Discord Auto Presence Healthy Text", "help": "Optional custom status text while runtime is healthy (online). If omitted, falls back to static channels.discord.activity when set.", "hasChildren": false @@ -11124,7 +11928,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord Auto Presence Check Interval (ms)", "help": "How often to evaluate Discord auto-presence state in milliseconds (default: 30000).", "hasChildren": false @@ -11136,7 +11944,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord Auto Presence Min Update Interval (ms)", "help": "Minimum time between actual Discord presence update calls in milliseconds (default: 15000). Prevents status spam on noisy state changes.", "hasChildren": false @@ -11216,7 +12028,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -11235,11 +12050,17 @@ { "path": "channels.discord.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Native Commands", "help": "Override native commands for Discord (bool or \"auto\").", "hasChildren": false @@ -11247,11 +12068,17 @@ { "path": "channels.discord.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Native Skill Commands", "help": "Override native skill commands for Discord (bool or \"auto\").", "hasChildren": false @@ -11263,7 +12090,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Config Writes", "help": "Allow Discord to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -11321,7 +12151,10 @@ { "path": "channels.discord.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11351,7 +12184,10 @@ { "path": "channels.discord.dm.groupChannels.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11373,10 +12209,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Discord DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.discord.allowFrom=[\"*\"] (legacy: channels.discord.dm.allowFrom).", "hasChildren": false @@ -11396,10 +12241,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Discord DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.discord.allowFrom=[\"*\"].", "hasChildren": false @@ -11451,7 +12305,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Draft Chunk Break Preference", "help": "Preferred breakpoints for Discord draft chunks (paragraph | newline | sentence). Default: paragraph.", "hasChildren": false @@ -11463,7 +12320,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord Draft Chunk Max Chars", "help": "Target max size for a Discord stream preview chunk when channels.discord.streaming=\"block\" (default: 800; clamped to channels.discord.textChunkLimit).", "hasChildren": false @@ -11475,7 +12336,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Draft Chunk Min Chars", "help": "Minimum chars before emitting a Discord stream preview update when channels.discord.streaming=\"block\" (default: 200).", "hasChildren": false @@ -11507,7 +12371,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord EventQueue Listener Timeout (ms)", "help": "Canonical Discord listener timeout control in ms for gateway normalization/enqueue handlers. Default is 120000 in OpenClaw; set per account via channels.discord.accounts..eventQueue.listenerTimeout.", "hasChildren": false @@ -11519,7 +12387,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord EventQueue Max Concurrency", "help": "Optional Discord EventQueue concurrency override (max concurrent handler executions). Set per account via channels.discord.accounts..eventQueue.maxConcurrency.", "hasChildren": false @@ -11531,7 +12403,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord EventQueue Max Queue Size", "help": "Optional Discord EventQueue capacity override (max queued events before backpressure). Set per account via channels.discord.accounts..eventQueue.maxQueueSize.", "hasChildren": false @@ -11579,7 +12455,10 @@ { "path": "channels.discord.execApprovals.approvers.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11631,7 +12510,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["dm", "channel", "both"], + "enumValues": [ + "dm", + "channel", + "both" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -11642,7 +12525,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -11702,9 +12589,17 @@ { "path": "channels.discord.guilds.*.channels.*.autoArchiveDuration", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, - "enumValues": ["60", "1440", "4320", "10080"], + "enumValues": [ + "60", + "1440", + "4320", + "10080" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -11773,7 +12668,10 @@ { "path": "channels.discord.guilds.*.channels.*.roles.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11973,7 +12871,10 @@ { "path": "channels.discord.guilds.*.channels.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -11995,7 +12896,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -12024,7 +12930,10 @@ { "path": "channels.discord.guilds.*.roles.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -12204,7 +13113,10 @@ { "path": "channels.discord.guilds.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -12298,7 +13210,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord Inbound Worker Timeout (ms)", "help": "Optional queued Discord inbound worker timeout in ms. This is separate from Carbon listener timeouts; defaults to 1800000 and can be disabled with 0. Set per account via channels.discord.accounts..inboundWorker.runTimeoutMs.", "hasChildren": false @@ -12320,7 +13236,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Guild Members Intent", "help": "Enable the Guild Members privileged intent. Must also be enabled in the Discord Developer Portal. Default: false.", "hasChildren": false @@ -12332,7 +13251,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Presence Intent", "help": "Enable the Guild Presences privileged intent. Must also be enabled in the Discord Developer Portal. Allows tracking user activities (e.g. Spotify). Default: false.", "hasChildren": false @@ -12352,7 +13274,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -12365,7 +13291,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Discord Max Lines Per Message", "help": "Soft max line count per Discord message (default: 17).", "hasChildren": false @@ -12407,7 +13337,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord PluralKit Enabled", "help": "Resolve PluralKit proxied messages and treat system members as distinct senders.", "hasChildren": false @@ -12415,11 +13348,19 @@ { "path": "channels.discord.pluralkit.token", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Discord PluralKit Token", "help": "Optional PluralKit token for resolving private systems or members.", "hasChildren": true @@ -12461,7 +13402,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Proxy URL", "help": "Proxy URL for Discord gateway + API requests (app-id lookup and allowlist resolution). Set per account via channels.discord.accounts..proxy.", "hasChildren": false @@ -12503,7 +13447,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Discord Retry Attempts", "help": "Max retry attempts for outbound Discord API calls (default: 3).", "hasChildren": false @@ -12515,7 +13463,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Discord Retry Jitter", "help": "Jitter factor (0-1) applied to Discord retry delays.", "hasChildren": false @@ -12527,7 +13479,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance", "reliability"], + "tags": [ + "channels", + "network", + "performance", + "reliability" + ], "label": "Discord Retry Max Delay (ms)", "help": "Maximum retry delay cap in ms for Discord outbound calls.", "hasChildren": false @@ -12539,7 +13496,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Discord Retry Min Delay (ms)", "help": "Minimum retry delay in ms for Discord outbound calls.", "hasChildren": false @@ -12569,10 +13530,18 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["online", "dnd", "idle", "invisible"], + "enumValues": [ + "online", + "dnd", + "idle", + "invisible" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Presence Status", "help": "Discord presence status (online, dnd, idle, invisible).", "hasChildren": false @@ -12580,12 +13549,23 @@ { "path": "channels.discord.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Streaming Mode", "help": "Unified Discord stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". \"progress\" maps to \"partial\" on Discord. Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -12595,10 +13575,17 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["partial", "block", "off"], + "enumValues": [ + "partial", + "block", + "off" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Stream Mode (Legacy)", "help": "Legacy Discord preview mode alias (off | partial | block); auto-migrated to channels.discord.streaming.", "hasChildren": false @@ -12630,7 +13617,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Discord Thread Binding Enabled", "help": "Enable Discord thread binding features (/focus, bound-thread routing/delivery, and thread-bound subagent sessions). Overrides session.threadBindings.enabled when set.", "hasChildren": false @@ -12642,7 +13633,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Discord Thread Binding Idle Timeout (hours)", "help": "Inactivity window in hours for Discord thread-bound sessions (/focus and spawned thread sessions). Set 0 to disable idle auto-unfocus (default: 24). Overrides session.threadBindings.idleHours when set.", "hasChildren": false @@ -12654,7 +13649,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance", "storage"], + "tags": [ + "channels", + "network", + "performance", + "storage" + ], "label": "Discord Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for Discord thread-bound sessions. Set 0 to disable hard cap (default: 0). Overrides session.threadBindings.maxAgeHours when set.", "hasChildren": false @@ -12666,7 +13666,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Discord Thread-Bound ACP Spawn", "help": "Allow /acp spawn to auto-create and bind Discord threads for ACP sessions (default: false; opt-in). Set true to enable thread-bound ACP spawns for this account/channel.", "hasChildren": false @@ -12678,7 +13682,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Discord Thread-Bound Subagent Spawn", "help": "Allow subagent spawns with thread=true to auto-create and bind Discord threads (default: false; opt-in). Set true to enable thread-bound subagent spawns for this account/channel.", "hasChildren": false @@ -12686,11 +13694,19 @@ { "path": "channels.discord.token", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Discord Bot Token", "help": "Discord bot token used for gateway and REST API authentication for this provider account. Keep this secret out of committed config and rotate immediately after any leak.", "hasChildren": true @@ -12752,7 +13768,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Component Accent Color", "help": "Accent color for Discord component containers (hex). Set per account via channels.discord.accounts..ui.components.accentColor.", "hasChildren": false @@ -12774,7 +13793,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Voice Auto-Join", "help": "Voice channels to auto-join on startup (list of guildId/channelId entries).", "hasChildren": true @@ -12816,7 +13838,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Voice DAVE Encryption", "help": "Toggle DAVE end-to-end encryption for Discord voice joins (default: true in @discordjs/voice; Discord may require this).", "hasChildren": false @@ -12828,7 +13853,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Voice Decrypt Failure Tolerance", "help": "Consecutive decrypt failures before DAVE attempts session recovery (passed to @discordjs/voice; default: 24).", "hasChildren": false @@ -12840,7 +13868,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Discord Voice Enabled", "help": "Enable Discord voice channel conversations (default: true). Omit channels.discord.voice to keep voice support disabled for the account.", "hasChildren": false @@ -12852,7 +13883,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "media", "network"], + "tags": [ + "channels", + "media", + "network" + ], "label": "Discord Voice Text-to-Speech", "help": "Optional TTS overrides for Discord voice playback (merged with messages.tts).", "hasChildren": true @@ -12862,7 +13897,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "always", "inbound", "tagged"], + "enumValues": [ + "off", + "always", + "inbound", + "tagged" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -12991,11 +14031,20 @@ { "path": "channels.discord.voice.tts.elevenlabs.apiKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "media", "network", "security"], + "tags": [ + "auth", + "channels", + "media", + "network", + "security" + ], "hasChildren": true }, { @@ -13033,7 +14082,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["auto", "on", "off"], + "enumValues": [ + "auto", + "on", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13174,7 +14227,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["final", "all"], + "enumValues": [ + "final", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13283,11 +14339,20 @@ { "path": "channels.discord.voice.tts.openai.apiKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "media", "network", "security"], + "tags": [ + "auth", + "channels", + "media", + "network", + "security" + ], "hasChildren": true }, { @@ -13385,7 +14450,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["elevenlabs", "openai", "edge"], + "enumValues": [ + "elevenlabs", + "openai", + "edge" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13418,7 +14487,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Feishu", "help": "飞书/Lark enterprise messaging.", "hasChildren": true @@ -13476,7 +14548,10 @@ { "path": "channels.feishu.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13496,7 +14571,10 @@ { "path": "channels.feishu.accounts.*.appSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13598,7 +14676,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13619,7 +14700,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["websocket", "webhook"], + "enumValues": [ + "websocket", + "webhook" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13640,7 +14724,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "pairing", "allowlist"], + "enumValues": [ + "open", + "pairing", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13691,7 +14779,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["feishu", "lark"], + "enumValues": [ + "feishu", + "lark" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13710,7 +14801,10 @@ { "path": "channels.feishu.accounts.*.encryptKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13760,7 +14854,10 @@ { "path": "channels.feishu.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13772,7 +14869,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "allowlist", "disabled"], + "enumValues": [ + "open", + "allowlist", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13811,7 +14912,10 @@ { "path": "channels.feishu.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13833,7 +14937,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], + "enumValues": [ + "group", + "group_sender", + "group_topic", + "group_topic_sender" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13844,7 +14953,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13945,7 +15057,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -13964,7 +15079,10 @@ { "path": "channels.feishu.accounts.*.groupSenderAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -13976,7 +15094,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], + "enumValues": [ + "group", + "group_sender", + "group_topic", + "group_topic_sender" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14007,7 +15130,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["visible", "hidden"], + "enumValues": [ + "visible", + "hidden" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14048,7 +15174,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["native", "escape", "strip"], + "enumValues": [ + "native", + "escape", + "strip" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14059,7 +15189,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["native", "ascii", "simple"], + "enumValues": [ + "native", + "ascii", + "simple" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14090,7 +15224,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all"], + "enumValues": [ + "off", + "own", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14101,7 +15239,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["auto", "raw", "card"], + "enumValues": [ + "auto", + "raw", + "card" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14112,7 +15254,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14233,7 +15378,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14252,7 +15400,10 @@ { "path": "channels.feishu.accounts.*.verificationToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14352,7 +15503,10 @@ { "path": "channels.feishu.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14372,7 +15526,10 @@ { "path": "channels.feishu.appSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14474,7 +15631,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14495,7 +15655,10 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["websocket", "webhook"], + "enumValues": [ + "websocket", + "webhook" + ], "defaultValue": "websocket", "deprecated": false, "sensitive": false, @@ -14527,7 +15690,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "pairing", "allowlist"], + "enumValues": [ + "open", + "pairing", + "allowlist" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -14579,7 +15746,10 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["feishu", "lark"], + "enumValues": [ + "feishu", + "lark" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14648,7 +15818,10 @@ { "path": "channels.feishu.encryptKey", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14698,7 +15871,10 @@ { "path": "channels.feishu.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14710,7 +15886,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "allowlist", "disabled"], + "enumValues": [ + "open", + "allowlist", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14749,7 +15929,10 @@ { "path": "channels.feishu.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14771,7 +15954,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], + "enumValues": [ + "group", + "group_sender", + "group_topic", + "group_topic_sender" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14782,7 +15970,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14883,7 +16074,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14902,7 +16096,10 @@ { "path": "channels.feishu.groupSenderAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -14914,7 +16111,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["group", "group_sender", "group_topic", "group_topic_sender"], + "enumValues": [ + "group", + "group_sender", + "group_topic", + "group_topic_sender" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14945,7 +16147,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["visible", "hidden"], + "enumValues": [ + "visible", + "hidden" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14986,7 +16191,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["native", "escape", "strip"], + "enumValues": [ + "native", + "escape", + "strip" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -14997,7 +16206,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["native", "ascii", "simple"], + "enumValues": [ + "native", + "ascii", + "simple" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15018,7 +16231,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["off", "own", "all"], + "enumValues": [ + "off", + "own", + "all" + ], "defaultValue": "own", "deprecated": false, "sensitive": false, @@ -15030,7 +16247,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["auto", "raw", "card"], + "enumValues": [ + "auto", + "raw", + "card" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15041,7 +16262,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15164,7 +16388,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["disabled", "enabled"], + "enumValues": [ + "disabled", + "enabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15184,7 +16411,10 @@ { "path": "channels.feishu.verificationToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -15259,7 +16489,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Google Chat", "help": "Google Workspace Chat app with HTTP webhook.", "hasChildren": true @@ -15339,7 +16572,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["app-url", "project-number"], + "enumValues": [ + "app-url", + "project-number" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15430,7 +16666,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15489,7 +16728,10 @@ { "path": "channels.googlechat.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -15511,7 +16753,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -15581,7 +16828,10 @@ { "path": "channels.googlechat.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -15593,7 +16843,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -15673,7 +16927,10 @@ { "path": "channels.googlechat.accounts.*.groups.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -15763,11 +17020,18 @@ { "path": "channels.googlechat.accounts.*.serviceAccount", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["channels", "network", "security"], + "tags": [ + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -15826,7 +17090,11 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["channels", "network", "security"], + "tags": [ + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -15864,7 +17132,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["replace", "status_final", "append"], + "enumValues": [ + "replace", + "status_final", + "append" + ], "defaultValue": "replace", "deprecated": false, "sensitive": false, @@ -15886,7 +17158,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["none", "message", "reaction"], + "enumValues": [ + "none", + "message", + "reaction" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -15967,7 +17243,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["app-url", "project-number"], + "enumValues": [ + "app-url", + "project-number" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -16058,7 +17337,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -16127,7 +17409,10 @@ { "path": "channels.googlechat.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -16149,7 +17434,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -16219,7 +17509,10 @@ { "path": "channels.googlechat.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -16231,7 +17524,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -16311,7 +17608,10 @@ { "path": "channels.googlechat.groups.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -16401,11 +17701,18 @@ { "path": "channels.googlechat.serviceAccount", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["channels", "network", "security"], + "tags": [ + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -16464,7 +17771,11 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["channels", "network", "security"], + "tags": [ + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -16502,7 +17813,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["replace", "status_final", "append"], + "enumValues": [ + "replace", + "status_final", + "append" + ], "defaultValue": "replace", "deprecated": false, "sensitive": false, @@ -16524,7 +17839,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["none", "message", "reaction"], + "enumValues": [ + "none", + "message", + "reaction" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -16557,7 +17876,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "iMessage", "help": "this is still a work in progress.", "hasChildren": true @@ -16595,7 +17917,10 @@ { "path": "channels.imessage.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -16697,7 +18022,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -16758,7 +18086,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -16818,7 +18151,10 @@ { "path": "channels.imessage.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -16830,7 +18166,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -17112,7 +18452,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -17221,7 +18565,10 @@ { "path": "channels.imessage.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -17323,7 +18670,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -17336,7 +18686,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "iMessage CLI Path", "help": "Filesystem path to the iMessage bridge CLI binary used for send/receive operations. Set explicitly when the binary is not on PATH in service runtime environments.", "hasChildren": false @@ -17348,7 +18702,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "iMessage Config Writes", "help": "Allow iMessage to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -17398,11 +18755,20 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "iMessage DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.imessage.allowFrom=[\"*\"].", "hasChildren": false @@ -17460,7 +18826,10 @@ { "path": "channels.imessage.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -17472,7 +18841,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -17754,7 +19127,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -17857,7 +19234,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "IRC", "help": "classic IRC networks with DM/channel routing and pairing controls.", "hasChildren": true @@ -17895,7 +19275,10 @@ { "path": "channels.irc.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -17977,7 +19360,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -18008,7 +19394,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -18068,7 +19459,10 @@ { "path": "channels.irc.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -18080,7 +19474,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -18120,7 +19518,10 @@ { "path": "channels.irc.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -18362,7 +19763,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -18445,7 +19850,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": false }, { @@ -18495,7 +19905,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": false }, { @@ -18581,7 +19996,10 @@ { "path": "channels.irc.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -18663,7 +20081,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -18704,11 +20125,20 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "IRC DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.irc.allowFrom=[\"*\"].", "hasChildren": false @@ -18766,7 +20196,10 @@ { "path": "channels.irc.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -18778,7 +20211,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -18818,7 +20255,10 @@ { "path": "channels.irc.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19060,7 +20500,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -19133,7 +20577,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "IRC NickServ Enabled", "help": "Enable NickServ identify/register after connect (defaults to enabled when password is configured).", "hasChildren": false @@ -19145,7 +20592,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "IRC NickServ Password", "help": "NickServ password used for IDENTIFY/REGISTER (sensitive).", "hasChildren": false @@ -19157,7 +20609,13 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "channels", "network", "security", "storage"], + "tags": [ + "auth", + "channels", + "network", + "security", + "storage" + ], "label": "IRC NickServ Password File", "help": "Optional file path containing NickServ password.", "hasChildren": false @@ -19169,7 +20627,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "IRC NickServ Register", "help": "If true, send NickServ REGISTER on every connect. Use once for initial registration, then disable.", "hasChildren": false @@ -19181,7 +20642,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "IRC NickServ Register Email", "help": "Email used with NickServ REGISTER (required when register=true).", "hasChildren": false @@ -19193,7 +20657,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "IRC NickServ Service", "help": "NickServ service nick (default: NickServ).", "hasChildren": false @@ -19205,7 +20672,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": false }, { @@ -19285,7 +20757,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "LINE", "help": "LINE Messaging API bot for Japan/Taiwan/Thailand markets.", "hasChildren": true @@ -19323,7 +20798,10 @@ { "path": "channels.line.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19355,7 +20833,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "allowlist", "pairing", "disabled"], + "enumValues": [ + "open", + "allowlist", + "pairing", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -19385,7 +20868,10 @@ { "path": "channels.line.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19397,7 +20883,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "allowlist", "disabled"], + "enumValues": [ + "open", + "allowlist", + "disabled" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -19437,7 +20927,10 @@ { "path": "channels.line.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19567,7 +21060,10 @@ { "path": "channels.line.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19609,7 +21105,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "allowlist", "pairing", "disabled"], + "enumValues": [ + "open", + "allowlist", + "pairing", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -19639,7 +21140,10 @@ { "path": "channels.line.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19651,7 +21155,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "allowlist", "disabled"], + "enumValues": [ + "open", + "allowlist", + "disabled" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -19691,7 +21199,10 @@ { "path": "channels.line.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19815,7 +21326,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Matrix", "help": "open protocol; configure a homeserver + access token.", "hasChildren": true @@ -19924,7 +21438,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["always", "allowlist", "off"], + "enumValues": [ + "always", + "allowlist", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -19943,7 +21461,10 @@ { "path": "channels.matrix.autoJoinAllowlist.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -19955,7 +21476,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20004,7 +21528,10 @@ { "path": "channels.matrix.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20026,7 +21553,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20065,7 +21597,10 @@ { "path": "channels.matrix.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20077,7 +21612,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20256,7 +21795,10 @@ { "path": "channels.matrix.groups.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20298,7 +21840,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20327,7 +21873,10 @@ { "path": "channels.matrix.password", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20369,7 +21918,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "first", "all"], + "enumValues": [ + "off", + "first", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20558,7 +22111,10 @@ { "path": "channels.matrix.rooms.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20580,7 +22136,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "inbound", "always"], + "enumValues": [ + "off", + "inbound", + "always" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20603,7 +22163,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost", "help": "self-hosted Slack-style chat; install the plugin to enable.", "hasChildren": true @@ -20661,7 +22224,10 @@ { "path": "channels.mattermost.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20731,7 +22297,10 @@ { "path": "channels.mattermost.accounts.*.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20793,7 +22362,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["oncall", "onmessage", "onchar"], + "enumValues": [ + "oncall", + "onmessage", + "onchar" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20804,7 +22377,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -20843,7 +22419,10 @@ { "path": "channels.mattermost.accounts.*.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20853,7 +22432,10 @@ { "path": "channels.mattermost.accounts.*.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20885,7 +22467,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -20915,7 +22502,10 @@ { "path": "channels.mattermost.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -20927,7 +22517,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -20989,7 +22583,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21030,7 +22628,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "first", "all"], + "enumValues": [ + "off", + "first", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21099,7 +22701,10 @@ { "path": "channels.mattermost.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -21113,7 +22718,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost Base URL", "help": "Base URL for your Mattermost server (e.g., https://chat.example.com).", "hasChildren": false @@ -21171,11 +22779,19 @@ { "path": "channels.mattermost.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Mattermost Bot Token", "help": "Bot token from Mattermost System Console -> Integrations -> Bot Accounts.", "hasChildren": true @@ -21235,10 +22851,17 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["oncall", "onmessage", "onchar"], + "enumValues": [ + "oncall", + "onmessage", + "onchar" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost Chat Mode", "help": "Reply to channel messages on mention (\"oncall\"), on trigger chars (\">\" or \"!\") (\"onchar\"), or on every message (\"onmessage\").", "hasChildren": false @@ -21248,7 +22871,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21287,7 +22913,10 @@ { "path": "channels.mattermost.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -21297,7 +22926,10 @@ { "path": "channels.mattermost.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -21311,7 +22943,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost Config Writes", "help": "Allow Mattermost to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -21341,7 +22976,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -21371,7 +23011,10 @@ { "path": "channels.mattermost.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -21383,7 +23026,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -21445,7 +23092,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21468,7 +23119,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost Onchar Prefixes", "help": "Trigger prefixes for onchar mode (default: [\">\", \"!\"]).", "hasChildren": true @@ -21488,7 +23142,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "first", "all"], + "enumValues": [ + "off", + "first", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21501,7 +23159,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Mattermost Require Mention", "help": "Require @mention in channels before responding (default: true).", "hasChildren": false @@ -21533,7 +23194,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Microsoft Teams", "help": "Bot Framework; enterprise support.", "hasChildren": true @@ -21571,11 +23235,19 @@ { "path": "channels.msteams.appPassword", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -21673,7 +23345,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21686,7 +23361,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "MS Teams Config Writes", "help": "Allow Microsoft Teams to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -21726,7 +23404,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -21798,7 +23481,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -21890,7 +23577,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -21951,7 +23642,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["thread", "top-level"], + "enumValues": [ + "thread", + "top-level" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -22032,7 +23726,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["thread", "top-level"], + "enumValues": [ + "thread", + "top-level" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -22203,7 +23900,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["thread", "top-level"], + "enumValues": [ + "thread", + "top-level" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -22426,7 +24126,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Nextcloud Talk", "help": "Self-hosted chat via Nextcloud Talk webhook bots.", "hasChildren": true @@ -22474,7 +24177,10 @@ { "path": "channels.nextcloud-talk.accounts.*.apiPassword", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -22594,7 +24300,10 @@ { "path": "channels.nextcloud-talk.accounts.*.botSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -22646,7 +24355,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -22667,7 +24379,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -22739,7 +24456,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -22771,7 +24492,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -23040,7 +24765,10 @@ { "path": "channels.nextcloud-talk.apiPassword", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -23160,7 +24888,10 @@ { "path": "channels.nextcloud-talk.botSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -23212,7 +24943,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -23243,7 +24977,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -23315,7 +25054,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -23347,7 +25090,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -23600,7 +25347,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Nostr", "help": "Decentralized DMs via Nostr relays (NIP-04)", "hasChildren": true @@ -23618,7 +25368,10 @@ { "path": "channels.nostr.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -23640,7 +25393,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -23671,7 +25429,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -23814,7 +25576,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Signal", "help": "signal-cli linked device; more setup (David Reagans: \"Hop on Discord.\").", "hasChildren": true @@ -23826,7 +25591,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Signal Account", "help": "Signal account identifier (phone/number handle) used to bind this channel config to a specific Signal identity. Keep this aligned with your linked device/session state.", "hasChildren": false @@ -23904,7 +25672,10 @@ { "path": "channels.signal.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -23996,7 +25767,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -24047,7 +25821,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -24107,7 +25886,10 @@ { "path": "channels.signal.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -24119,7 +25901,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -24441,7 +26227,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -24480,7 +26270,10 @@ { "path": "channels.signal.accounts.*.reactionAllowlist.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -24492,7 +26285,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "ack", "minimal", "extensive"], + "enumValues": [ + "off", + "ack", + "minimal", + "extensive" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -24503,7 +26301,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -24602,7 +26405,10 @@ { "path": "channels.signal.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -24694,7 +26500,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -24717,7 +26526,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Signal Config Writes", "help": "Allow Signal to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -24757,11 +26569,20 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Signal DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.signal.allowFrom=[\"*\"].", "hasChildren": false @@ -24819,7 +26640,10 @@ { "path": "channels.signal.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -24831,7 +26655,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -25153,7 +26981,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -25192,7 +27024,10 @@ { "path": "channels.signal.reactionAllowlist.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25204,7 +27039,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "ack", "minimal", "extensive"], + "enumValues": [ + "off", + "ack", + "minimal", + "extensive" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -25215,7 +27055,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -25278,7 +27123,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack", "help": "supported (Socket Mode).", "hasChildren": true @@ -25426,7 +27274,10 @@ { "path": "channels.slack.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25436,11 +27287,19 @@ { "path": "channels.slack.accounts.*.appToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -25526,11 +27385,19 @@ { "path": "channels.slack.accounts.*.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -25566,7 +27433,10 @@ { "path": "channels.slack.accounts.*.capabilities", "kind": "channel", - "type": ["array", "object"], + "type": [ + "array", + "object" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25846,7 +27716,10 @@ { "path": "channels.slack.accounts.*.channels.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25858,7 +27731,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -25877,7 +27753,10 @@ { "path": "channels.slack.accounts.*.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25887,7 +27766,10 @@ { "path": "channels.slack.accounts.*.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25947,7 +27829,10 @@ { "path": "channels.slack.accounts.*.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25977,7 +27862,10 @@ { "path": "channels.slack.accounts.*.dm.groupChannels.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -25999,7 +27887,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26030,7 +27923,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26081,7 +27979,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26172,7 +28074,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26193,7 +28099,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["socket", "http"], + "enumValues": [ + "socket", + "http" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26232,7 +28141,10 @@ { "path": "channels.slack.accounts.*.reactionAllowlist.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -26244,7 +28156,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26323,11 +28240,19 @@ { "path": "channels.slack.accounts.*.signingSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -26413,9 +28338,17 @@ { "path": "channels.slack.accounts.*.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26426,7 +28359,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["replace", "status_final", "append"], + "enumValues": [ + "replace", + "status_final", + "append" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26457,7 +28394,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["thread", "channel"], + "enumValues": [ + "thread", + "channel" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -26496,11 +28436,19 @@ { "path": "channels.slack.accounts.*.userToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -26661,7 +28609,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Slack Allow Bot Messages", "help": "Allow bot-authored messages to trigger Slack replies (default: false).", "hasChildren": false @@ -26679,7 +28631,10 @@ { "path": "channels.slack.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -26689,11 +28644,19 @@ { "path": "channels.slack.appToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Slack App Token", "help": "Slack app-level token used for Socket Mode connections and event transport when enabled. Use least-privilege app scopes and store this token as a secret.", "hasChildren": true @@ -26781,11 +28744,19 @@ { "path": "channels.slack.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Slack Bot Token", "help": "Slack bot token used for standard chat actions in the configured workspace. Keep this credential scoped and rotate if workspace app permissions change.", "hasChildren": true @@ -26823,7 +28794,10 @@ { "path": "channels.slack.capabilities", "kind": "channel", - "type": ["array", "object"], + "type": [ + "array", + "object" + ], "required": false, "deprecated": false, "sensitive": false, @@ -26847,7 +28821,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Interactive Replies", "help": "Enable agent-authored Slack interactive reply directives (`[[slack_buttons: ...]]`, `[[slack_select: ...]]`). Default: false.", "hasChildren": false @@ -27105,7 +29082,10 @@ { "path": "channels.slack.channels.*.users.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -27117,7 +29097,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -27136,11 +29119,17 @@ { "path": "channels.slack.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Native Commands", "help": "Override native commands for Slack (bool or \"auto\").", "hasChildren": false @@ -27148,11 +29137,17 @@ { "path": "channels.slack.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Native Skill Commands", "help": "Override native skill commands for Slack (bool or \"auto\").", "hasChildren": false @@ -27164,7 +29159,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Config Writes", "help": "Allow Slack to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -27222,7 +29220,10 @@ { "path": "channels.slack.dm.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -27252,7 +29253,10 @@ { "path": "channels.slack.dm.groupChannels.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -27274,10 +29278,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Slack DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.slack.allowFrom=[\"*\"] (legacy: channels.slack.dm.allowFrom).", "hasChildren": false @@ -27307,10 +29320,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Slack DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.slack.allowFrom=[\"*\"].", "hasChildren": false @@ -27360,7 +29382,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -27452,7 +29478,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -27473,7 +29503,10 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["socket", "http"], + "enumValues": [ + "socket", + "http" + ], "defaultValue": "socket", "deprecated": false, "sensitive": false, @@ -27497,7 +29530,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Native Streaming", "help": "Enable native Slack text streaming (chat.startStream/chat.appendStream/chat.stopStream) when channels.slack.streaming is partial (default: true).", "hasChildren": false @@ -27515,7 +29551,10 @@ { "path": "channels.slack.reactionAllowlist.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -27527,7 +29566,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all", "allowlist"], + "enumValues": [ + "off", + "own", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -27606,11 +29650,19 @@ { "path": "channels.slack.signingSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -27696,12 +29748,23 @@ { "path": "channels.slack.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Streaming Mode", "help": "Unified Slack stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -27711,10 +29774,17 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["replace", "status_final", "append"], + "enumValues": [ + "replace", + "status_final", + "append" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Stream Mode (Legacy)", "help": "Legacy Slack preview mode alias (replace | status_final | append); auto-migrated to channels.slack.streaming.", "hasChildren": false @@ -27744,10 +29814,16 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["thread", "channel"], + "enumValues": [ + "thread", + "channel" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Thread History Scope", "help": "Scope for Slack thread history context (\"thread\" isolates per thread; \"channel\" reuses channel history).", "hasChildren": false @@ -27759,7 +29835,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Slack Thread Parent Inheritance", "help": "If true, Slack thread sessions inherit the parent channel transcript (default: false).", "hasChildren": false @@ -27771,7 +29850,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Slack Thread Initial History Limit", "help": "Maximum number of existing Slack thread messages to fetch when starting a new thread session (default: 20, set to 0 to disable).", "hasChildren": false @@ -27789,11 +29872,19 @@ { "path": "channels.slack.userToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Slack User Token", "help": "Optional Slack user token for workflows requiring user-context API access beyond bot permissions. Use sparingly and audit scopes because this token can carry broader authority.", "hasChildren": true @@ -27836,7 +29927,12 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Slack User Token Read Only", "help": "When true, treat configured Slack user token usage as read-only helper behavior where possible. Keep enabled if you only need supplemental reads without user-context writes.", "hasChildren": false @@ -27859,7 +29955,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Synology Chat", "help": "Connect your Synology NAS Chat to OpenClaw", "hasChildren": true @@ -27880,7 +29979,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram", "help": "simplest way to get started — register a bot with @BotFather and get going.", "hasChildren": true @@ -28008,7 +30110,10 @@ { "path": "channels.telegram.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28068,11 +30173,19 @@ { "path": "channels.telegram.accounts.*.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -28108,7 +30221,10 @@ { "path": "channels.telegram.accounts.*.capabilities", "kind": "channel", - "type": ["array", "object"], + "type": [ + "array", + "object" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28130,7 +30246,13 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "dm", "group", "all", "allowlist"], + "enumValues": [ + "off", + "dm", + "group", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -28141,7 +30263,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -28160,7 +30285,10 @@ { "path": "channels.telegram.accounts.*.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28170,7 +30298,10 @@ { "path": "channels.telegram.accounts.*.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28230,7 +30361,10 @@ { "path": "channels.telegram.accounts.*.defaultTo", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28270,7 +30404,10 @@ { "path": "channels.telegram.accounts.*.direct.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28282,7 +30419,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -28531,7 +30673,10 @@ { "path": "channels.telegram.accounts.*.direct.*.topics.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28563,7 +30708,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -28624,7 +30773,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -28754,7 +30908,10 @@ { "path": "channels.telegram.accounts.*.execApprovals.approvers.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28796,7 +30953,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["dm", "channel", "both"], + "enumValues": [ + "dm", + "channel", + "both" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -28815,7 +30976,10 @@ { "path": "channels.telegram.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28827,7 +30991,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -28867,7 +31035,10 @@ { "path": "channels.telegram.accounts.*.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -28899,7 +31070,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29138,7 +31313,10 @@ { "path": "channels.telegram.accounts.*.groups.*.topics.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -29170,7 +31348,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29311,7 +31493,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29362,7 +31548,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["ipv4first", "verbatim"], + "enumValues": [ + "ipv4first", + "verbatim" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29383,7 +31572,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "ack", "minimal", "extensive"], + "enumValues": [ + "off", + "ack", + "minimal", + "extensive" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29394,7 +31588,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all"], + "enumValues": [ + "off", + "own", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29473,9 +31671,17 @@ { "path": "channels.telegram.accounts.*.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29486,7 +31692,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "partial", "block"], + "enumValues": [ + "off", + "partial", + "block" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29625,11 +31835,19 @@ { "path": "channels.telegram.accounts.*.webhookSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -29775,7 +31993,10 @@ { "path": "channels.telegram.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -29835,11 +32056,19 @@ { "path": "channels.telegram.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "label": "Telegram Bot Token", "help": "Telegram bot token used to authenticate Bot API requests for this account/provider config. Use secret/env substitution and rotate tokens if exposure is suspected.", "hasChildren": true @@ -29877,7 +32106,10 @@ { "path": "channels.telegram.capabilities", "kind": "channel", - "type": ["array", "object"], + "type": [ + "array", + "object" + ], "required": false, "deprecated": false, "sensitive": false, @@ -29899,10 +32131,19 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "dm", "group", "all", "allowlist"], + "enumValues": [ + "off", + "dm", + "group", + "all", + "allowlist" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Inline Buttons", "help": "Enable Telegram inline button components for supported command and interaction surfaces. Disable if your deployment needs plain-text-only compatibility behavior.", "hasChildren": false @@ -29912,7 +32153,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -29931,11 +32175,17 @@ { "path": "channels.telegram.commands.native", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Native Commands", "help": "Override native commands for Telegram (bool or \"auto\").", "hasChildren": false @@ -29943,11 +32193,17 @@ { "path": "channels.telegram.commands.nativeSkills", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Native Skill Commands", "help": "Override native skill commands for Telegram (bool or \"auto\").", "hasChildren": false @@ -29959,7 +32215,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Config Writes", "help": "Allow Telegram to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -29971,7 +32230,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Custom Commands", "help": "Additional Telegram bot menu commands (merged with native; conflicts ignored).", "hasChildren": true @@ -30019,7 +32281,10 @@ { "path": "channels.telegram.defaultTo", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30059,7 +32324,10 @@ { "path": "channels.telegram.direct.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30071,7 +32339,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -30320,7 +32593,10 @@ { "path": "channels.telegram.direct.*.topics.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30352,7 +32628,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -30413,11 +32693,20 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "Telegram DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.telegram.allowFrom=[\"*\"].", "hasChildren": false @@ -30509,7 +32798,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Exec Approvals", "help": "Telegram-native exec approval routing and approver authorization. Enable this only when Telegram should act as an explicit exec-approval client for the selected bot account.", "hasChildren": true @@ -30521,7 +32813,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Exec Approval Agent Filter", "help": "Optional allowlist of agent IDs eligible for Telegram exec approvals, for example `[\"main\", \"ops-agent\"]`. Use this to keep approval prompts scoped to the agents you actually operate from Telegram.", "hasChildren": true @@ -30543,7 +32838,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Exec Approval Approvers", "help": "Telegram user IDs allowed to approve exec requests for this bot account. Use numeric Telegram user IDs; prompts are only delivered to these approvers when target includes dm.", "hasChildren": true @@ -30551,7 +32849,10 @@ { "path": "channels.telegram.execApprovals.approvers.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30565,7 +32866,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Exec Approvals Enabled", "help": "Enable Telegram exec approvals for this account. When false or unset, Telegram messages/buttons cannot approve exec requests.", "hasChildren": false @@ -30577,7 +32881,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Telegram Exec Approval Session Filter", "help": "Optional session-key filters matched as substring or regex-style patterns before Telegram approval routing is used. Use narrow patterns so Telegram approvals only appear for intended sessions.", "hasChildren": true @@ -30597,10 +32905,17 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["dm", "channel", "both"], + "enumValues": [ + "dm", + "channel", + "both" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Exec Approval Target", "help": "Controls where Telegram approval prompts are sent: \"dm\" sends to approver DMs (default), \"channel\" sends to the originating Telegram chat/topic, and \"both\" sends to both. Channel delivery exposes the command text to the chat, so only use it in trusted groups/topics.", "hasChildren": false @@ -30618,7 +32933,10 @@ { "path": "channels.telegram.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30630,7 +32948,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -30670,7 +32992,10 @@ { "path": "channels.telegram.groups.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30702,7 +33027,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -30941,7 +33270,10 @@ { "path": "channels.telegram.groups.*.topics.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -30973,7 +33305,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31114,7 +33450,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31157,7 +33497,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram autoSelectFamily", "help": "Override Node autoSelectFamily for Telegram (true=enable, false=disable).", "hasChildren": false @@ -31167,7 +33510,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["ipv4first", "verbatim"], + "enumValues": [ + "ipv4first", + "verbatim" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31188,7 +33534,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "ack", "minimal", "extensive"], + "enumValues": [ + "off", + "ack", + "minimal", + "extensive" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31199,7 +33550,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "own", "all"], + "enumValues": [ + "off", + "own", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31242,7 +33597,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Telegram Retry Attempts", "help": "Max retry attempts for outbound Telegram API calls (default: 3).", "hasChildren": false @@ -31254,7 +33613,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Telegram Retry Jitter", "help": "Jitter factor (0-1) applied to Telegram retry delays.", "hasChildren": false @@ -31266,7 +33629,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance", "reliability"], + "tags": [ + "channels", + "network", + "performance", + "reliability" + ], "label": "Telegram Retry Max Delay (ms)", "help": "Maximum retry delay cap in ms for Telegram outbound calls.", "hasChildren": false @@ -31278,7 +33646,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "reliability"], + "tags": [ + "channels", + "network", + "reliability" + ], "label": "Telegram Retry Min Delay (ms)", "help": "Minimum retry delay in ms for Telegram outbound calls.", "hasChildren": false @@ -31286,12 +33658,23 @@ { "path": "channels.telegram.streaming", "kind": "channel", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, - "enumValues": ["off", "partial", "block", "progress"], + "enumValues": [ + "off", + "partial", + "block", + "progress" + ], "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Telegram Streaming Mode", "help": "Unified Telegram stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\" (default: \"partial\"). \"progress\" maps to \"partial\" on Telegram. Legacy boolean/streamMode keys are auto-mapped.", "hasChildren": false @@ -31301,7 +33684,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "partial", "block"], + "enumValues": [ + "off", + "partial", + "block" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31334,7 +33721,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Telegram Thread Binding Enabled", "help": "Enable Telegram conversation binding features (/focus, /unfocus, /agents, and /session idle|max-age). Overrides session.threadBindings.enabled when set.", "hasChildren": false @@ -31346,7 +33737,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Telegram Thread Binding Idle Timeout (hours)", "help": "Inactivity window in hours for Telegram bound sessions. Set 0 to disable idle auto-unfocus (default: 24). Overrides session.threadBindings.idleHours when set.", "hasChildren": false @@ -31358,7 +33753,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance", "storage"], + "tags": [ + "channels", + "network", + "performance", + "storage" + ], "label": "Telegram Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for Telegram bound sessions. Set 0 to disable hard cap (default: 0). Overrides session.threadBindings.maxAgeHours when set.", "hasChildren": false @@ -31370,7 +33770,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Telegram Thread-Bound ACP Spawn", "help": "Allow ACP spawns with thread=true to auto-bind Telegram current conversations when supported.", "hasChildren": false @@ -31382,7 +33786,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "storage"], + "tags": [ + "channels", + "network", + "storage" + ], "label": "Telegram Thread-Bound Subagent Spawn", "help": "Allow subagent spawns with thread=true to auto-bind Telegram current conversations when supported.", "hasChildren": false @@ -31394,7 +33802,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "Telegram API Timeout (seconds)", "help": "Max seconds before Telegram API requests are aborted (default: 500 per grammY).", "hasChildren": false @@ -31452,11 +33864,19 @@ { "path": "channels.telegram.webhookSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "channels", "network", "security"], + "tags": [ + "auth", + "channels", + "network", + "security" + ], "hasChildren": true }, { @@ -31506,7 +33926,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Tlon", "help": "Decentralized messaging on Urbit", "hasChildren": true @@ -31756,7 +34179,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["restricted", "open"], + "enumValues": [ + "restricted", + "open" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -31939,7 +34365,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Twitch", "help": "Twitch chat integration", "hasChildren": true @@ -31999,7 +34428,13 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["moderator", "owner", "vip", "subscriber", "all"], + "enumValues": [ + "moderator", + "owner", + "vip", + "subscriber", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -32068,7 +34503,10 @@ { "path": "channels.twitch.accounts.*.expiresIn", "kind": "channel", - "type": ["null", "number"], + "type": [ + "null", + "number" + ], "required": false, "deprecated": false, "sensitive": false, @@ -32140,7 +34578,13 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["moderator", "owner", "vip", "subscriber", "all"], + "enumValues": [ + "moderator", + "owner", + "vip", + "subscriber", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -32209,7 +34653,10 @@ { "path": "channels.twitch.expiresIn", "kind": "channel", - "type": ["null", "number"], + "type": [ + "null", + "number" + ], "required": false, "deprecated": false, "sensitive": false, @@ -32231,7 +34678,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["bullets", "code", "off"], + "enumValues": [ + "bullets", + "code", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -32304,7 +34755,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "WhatsApp", "help": "works with your own number; recommend a separate phone + eSIM.", "hasChildren": true @@ -32365,7 +34819,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["always", "mentions", "never"], + "enumValues": [ + "always", + "mentions", + "never" + ], "defaultValue": "mentions", "deprecated": false, "sensitive": false, @@ -32477,7 +34935,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -32529,7 +34990,12 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, @@ -32601,7 +35067,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -32873,7 +35343,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -32985,7 +35459,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["always", "mentions", "never"], + "enumValues": [ + "always", + "mentions", + "never" + ], "defaultValue": "mentions", "deprecated": false, "sensitive": false, @@ -33127,7 +35605,10 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["length", "newline"], + "enumValues": [ + "length", + "newline" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33140,7 +35621,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "WhatsApp Config Writes", "help": "Allow WhatsApp to write config in response to channel events/commands (default: true).", "hasChildren": false @@ -33153,7 +35637,11 @@ "defaultValue": 0, "deprecated": false, "sensitive": false, - "tags": ["channels", "network", "performance"], + "tags": [ + "channels", + "network", + "performance" + ], "label": "WhatsApp Message Debounce (ms)", "help": "Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable).", "hasChildren": false @@ -33193,11 +35681,20 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "defaultValue": "pairing", "deprecated": false, "sensitive": false, - "tags": ["access", "channels", "network"], + "tags": [ + "access", + "channels", + "network" + ], "label": "WhatsApp DM Policy", "help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.whatsapp.allowFrom=[\"*\"].", "hasChildren": false @@ -33267,7 +35764,11 @@ "kind": "channel", "type": "string", "required": true, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "defaultValue": "allowlist", "deprecated": false, "sensitive": false, @@ -33539,7 +36040,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33583,7 +36088,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "WhatsApp Self-Phone Mode", "help": "Same-phone setup (bot uses your personal WhatsApp number).", "hasChildren": false @@ -33615,7 +36123,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Zalo", "help": "Vietnam-focused messaging platform with Bot API.", "hasChildren": true @@ -33653,7 +36164,10 @@ { "path": "channels.zalo.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33663,7 +36177,10 @@ { "path": "channels.zalo.accounts.*.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33705,7 +36222,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33734,7 +36256,10 @@ { "path": "channels.zalo.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33746,7 +36271,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33767,7 +36296,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33836,7 +36369,10 @@ { "path": "channels.zalo.accounts.*.webhookSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33896,7 +36432,10 @@ { "path": "channels.zalo.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33906,7 +36445,10 @@ { "path": "channels.zalo.botToken", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33958,7 +36500,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -33987,7 +36534,10 @@ { "path": "channels.zalo.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -33999,7 +36549,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34020,7 +36574,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34089,7 +36647,10 @@ { "path": "channels.zalo.webhookSecret", "kind": "channel", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34143,7 +36704,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["channels", "network"], + "tags": [ + "channels", + "network" + ], "label": "Zalo Personal", "help": "Zalo personal account via QR code login.", "hasChildren": true @@ -34181,7 +36745,10 @@ { "path": "channels.zalouser.accounts.*.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34203,7 +36770,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34232,7 +36804,10 @@ { "path": "channels.zalouser.accounts.*.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34244,7 +36819,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34395,7 +36974,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34454,7 +37037,10 @@ { "path": "channels.zalouser.allowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34486,7 +37072,12 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["pairing", "allowlist", "open", "disabled"], + "enumValues": [ + "pairing", + "allowlist", + "open", + "disabled" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34515,7 +37106,10 @@ { "path": "channels.zalouser.groupAllowFrom.*", "kind": "channel", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34527,7 +37121,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["open", "disabled", "allowlist"], + "enumValues": [ + "open", + "disabled", + "allowlist" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34678,7 +37276,11 @@ "kind": "channel", "type": "string", "required": false, - "enumValues": ["off", "bullets", "code"], + "enumValues": [ + "off", + "bullets", + "code" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -34731,7 +37333,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "CLI", "help": "CLI presentation controls for local command output behavior such as banner and tagline style. Use this section to keep startup output aligned with operator preference without changing runtime behavior.", "hasChildren": true @@ -34743,7 +37347,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "CLI Banner", "help": "CLI startup banner controls for title/version line and tagline style behavior. Keep banner enabled for fast version/context checks, then tune tagline mode to your preferred noise level.", "hasChildren": true @@ -34755,7 +37361,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "CLI Banner Tagline Mode", "help": "Controls tagline style in the CLI startup banner: \"random\" (default) picks from the rotating tagline pool, \"default\" always shows the neutral default tagline, and \"off\" hides tagline text while keeping the banner version line.", "hasChildren": false @@ -34773,7 +37381,9 @@ }, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Commands", "help": "Controls chat command surfaces, owner gating, and elevated command access behavior across providers. Keep defaults unless you need stricter operator controls or broader command availability.", "hasChildren": true @@ -34785,7 +37395,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Command Elevated Access Rules", "help": "Defines elevated command allow rules by channel and sender for owner-level command surfaces. Use narrow provider-specific identities so privileged commands are not exposed to broad chat audiences.", "hasChildren": true @@ -34803,7 +37415,10 @@ { "path": "commands.allowFrom.*.*", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34817,7 +37432,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Allow Bash Chat Command", "help": "Allow bash chat command (`!`; `/bash` alias) to run host shell commands (default: false; requires tools.elevated).", "hasChildren": false @@ -34829,7 +37446,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Bash Foreground Window (ms)", "help": "How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately).", "hasChildren": false @@ -34841,7 +37460,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Allow /config", "help": "Allow /config chat command to read/write config on disk (default: false).", "hasChildren": false @@ -34853,7 +37474,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Allow /debug", "help": "Allow /debug chat command for runtime-only overrides (default: false).", "hasChildren": false @@ -34861,11 +37484,16 @@ { "path": "commands.native", "kind": "core", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Native Commands", "help": "Registers native slash/menu commands with channels that support command registration (Discord, Slack, Telegram). Keep enabled for discoverability unless you intentionally run text-only command workflows.", "hasChildren": false @@ -34873,11 +37501,16 @@ { "path": "commands.nativeSkills", "kind": "core", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Native Skill Commands", "help": "Registers native skill commands so users can invoke skills directly from provider command menus where supported. Keep aligned with your skill policy so exposed commands match what operators expect.", "hasChildren": false @@ -34889,7 +37522,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Command Owners", "help": "Explicit owner allowlist for owner-only tools/commands. Use channel-native IDs (optionally prefixed like \"whatsapp:+15551234567\"). '*' is ignored.", "hasChildren": true @@ -34897,7 +37532,10 @@ { "path": "commands.ownerAllowFrom.*", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -34909,11 +37547,16 @@ "kind": "core", "type": "string", "required": true, - "enumValues": ["raw", "hash"], + "enumValues": [ + "raw", + "hash" + ], "defaultValue": "raw", "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Owner ID Display", "help": "Controls how owner IDs are rendered in the system prompt. Allowed values: raw, hash. Default: raw.", "hasChildren": false @@ -34925,7 +37568,11 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["access", "auth", "security"], + "tags": [ + "access", + "auth", + "security" + ], "label": "Owner ID Hash Secret", "help": "Optional secret used to HMAC hash owner IDs when ownerDisplay=hash. Prefer env substitution.", "hasChildren": false @@ -34938,7 +37585,9 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Allow Restart", "help": "Allow /restart and gateway restart tool actions (default: true).", "hasChildren": false @@ -34950,7 +37599,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Text Commands", "help": "Enables text-command parsing in chat input in addition to native command surfaces where available. Keep this enabled for compatibility across channels that do not support native command registration.", "hasChildren": false @@ -34962,7 +37613,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Use Access Groups", "help": "Enforce access-group allowlists/policies for commands.", "hasChildren": false @@ -34974,7 +37627,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Cron", "help": "Global scheduler settings for stored cron jobs, run concurrency, delivery fallback, and run-session retention. Keep defaults unless you are scaling job volume or integrating external webhook receivers.", "hasChildren": true @@ -34986,7 +37641,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Cron Enabled", "help": "Enables cron job execution for stored schedules managed by the gateway. Keep enabled for normal reminder/automation flows, and disable only to pause all cron execution without deleting jobs.", "hasChildren": false @@ -35046,7 +37703,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["announce", "webhook"], + "enumValues": [ + "announce", + "webhook" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -35087,7 +37747,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["announce", "webhook"], + "enumValues": [ + "announce", + "webhook" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -35110,7 +37773,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "performance"], + "tags": [ + "automation", + "performance" + ], "label": "Cron Max Concurrent Runs", "help": "Limits how many cron jobs can execute at the same time when multiple schedules fire together. Use lower values to protect CPU/memory under heavy automation load, or raise carefully for higher throughput.", "hasChildren": false @@ -35122,7 +37788,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "reliability"], + "tags": [ + "automation", + "reliability" + ], "label": "Cron Retry Policy", "help": "Overrides the default retry policy for one-shot jobs when they fail with transient errors (rate limit, overloaded, network, server_error). Omit to use defaults: maxAttempts 3, backoffMs [30000, 60000, 300000], retry all transient types.", "hasChildren": true @@ -35134,7 +37803,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "reliability"], + "tags": [ + "automation", + "reliability" + ], "label": "Cron Retry Backoff (ms)", "help": "Backoff delays in ms for each retry attempt (default: [30000, 60000, 300000]). Use shorter values for faster retries.", "hasChildren": true @@ -35156,7 +37828,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "performance", "reliability"], + "tags": [ + "automation", + "performance", + "reliability" + ], "label": "Cron Retry Max Attempts", "help": "Max retries for one-shot jobs on transient errors before permanent disable (default: 3).", "hasChildren": false @@ -35168,7 +37844,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "reliability"], + "tags": [ + "automation", + "reliability" + ], "label": "Cron Retry Error Types", "help": "Error types to retry: rate_limit, overloaded, network, timeout, server_error. Use to restrict which errors trigger retries; omit to retry all transient types.", "hasChildren": true @@ -35178,7 +37857,13 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["rate_limit", "overloaded", "network", "timeout", "server_error"], + "enumValues": [ + "rate_limit", + "overloaded", + "network", + "timeout", + "server_error" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -35191,7 +37876,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Cron Run Log Pruning", "help": "Pruning controls for per-job cron run history files under `cron/runs/.jsonl`, including size and line retention.", "hasChildren": true @@ -35203,7 +37890,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Cron Run Log Keep Lines", "help": "How many trailing run-log lines to retain when a file exceeds maxBytes (default `2000`). Increase for longer forensic history or lower for smaller disks.", "hasChildren": false @@ -35211,11 +37900,17 @@ { "path": "cron.runLog.maxBytes", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "performance"], + "tags": [ + "automation", + "performance" + ], "label": "Cron Run Log Max Bytes", "help": "Maximum bytes per cron run-log file before pruning rewrites to the last keepLines entries (for example `2mb`, default `2000000`).", "hasChildren": false @@ -35223,11 +37918,17 @@ { "path": "cron.sessionRetention", "kind": "core", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "storage"], + "tags": [ + "automation", + "storage" + ], "label": "Cron Session Retention", "help": "Controls how long completed cron run sessions are kept before pruning (`24h`, `7d`, `1h30m`, or `false` to disable pruning; default: `24h`). Use shorter retention to reduce storage growth on high-frequency schedules.", "hasChildren": false @@ -35239,7 +37940,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "storage"], + "tags": [ + "automation", + "storage" + ], "label": "Cron Store Path", "help": "Path to the cron job store file used to persist scheduled jobs across restarts. Set an explicit path only when you need custom storage layout, backups, or mounted volumes.", "hasChildren": false @@ -35251,7 +37955,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Cron Legacy Webhook (Deprecated)", "help": "Deprecated legacy fallback webhook URL used only for old jobs with `notify=true`. Migrate to per-job delivery using `delivery.mode=\"webhook\"` plus `delivery.to`, and avoid relying on this global field.", "hasChildren": false @@ -35259,11 +37965,18 @@ { "path": "cron.webhookToken", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "automation", "security"], + "tags": [ + "auth", + "automation", + "security" + ], "label": "Cron Webhook Bearer Token", "help": "Bearer token attached to cron webhook POST deliveries when webhook mode is used. Prefer secret/env substitution and rotate this token regularly if shared webhook endpoints are internet-reachable.", "hasChildren": true @@ -35305,7 +38018,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Diagnostics", "help": "Diagnostics controls for targeted tracing, telemetry export, and cache inspection during debugging. Keep baseline diagnostics minimal in production and enable deeper signals only when investigating issues.", "hasChildren": true @@ -35317,7 +38032,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace", "help": "Cache-trace logging settings for observing cache decisions and payload context in embedded runs. Enable this temporarily for debugging and disable afterward to reduce sensitive log footprint.", "hasChildren": true @@ -35329,7 +38047,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace Enabled", "help": "Log cache trace snapshots for embedded agent runs (default: false).", "hasChildren": false @@ -35341,7 +38062,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace File Path", "help": "JSONL output path for cache trace logs (default: $OPENCLAW_STATE_DIR/logs/cache-trace.jsonl).", "hasChildren": false @@ -35353,7 +38077,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace Include Messages", "help": "Include full message payloads in trace output (default: true).", "hasChildren": false @@ -35365,7 +38092,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace Include Prompt", "help": "Include prompt text in trace output (default: true).", "hasChildren": false @@ -35377,7 +38107,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Cache Trace Include System", "help": "Include system prompt in trace output (default: true).", "hasChildren": false @@ -35389,7 +38122,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Diagnostics Enabled", "help": "Master toggle for diagnostics instrumentation output in logs and telemetry wiring paths. Keep enabled for normal observability, and disable only in tightly constrained environments.", "hasChildren": false @@ -35401,7 +38136,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Diagnostics Flags", "help": "Enable targeted diagnostics logs by flag (e.g. [\"telegram.http\"]). Supports wildcards like \"telegram.*\" or \"*\".", "hasChildren": true @@ -35423,7 +38160,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry", "help": "OpenTelemetry export settings for traces, metrics, and logs emitted by gateway components. Use this when integrating with centralized observability backends and distributed tracing pipelines.", "hasChildren": true @@ -35435,7 +38174,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Enabled", "help": "Enables OpenTelemetry export pipeline for traces, metrics, and logs based on configured endpoint/protocol settings. Keep disabled unless your collector endpoint and auth are fully configured.", "hasChildren": false @@ -35447,7 +38188,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Endpoint", "help": "Collector endpoint URL used for OpenTelemetry export transport, including scheme and port. Use a reachable, trusted collector endpoint and monitor ingestion errors after rollout.", "hasChildren": false @@ -35459,7 +38202,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "performance"], + "tags": [ + "observability", + "performance" + ], "label": "OpenTelemetry Flush Interval (ms)", "help": "Interval in milliseconds for periodic telemetry flush from buffers to the collector. Increase to reduce export chatter, or lower for faster visibility during active incident response.", "hasChildren": false @@ -35471,7 +38217,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Headers", "help": "Additional HTTP/gRPC metadata headers sent with OpenTelemetry export requests, often used for tenant auth or routing. Keep secrets in env-backed values and avoid unnecessary header sprawl.", "hasChildren": true @@ -35493,7 +38241,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Logs Enabled", "help": "Enable log signal export through OpenTelemetry in addition to local logging sinks. Use this when centralized log correlation is required across services and agents.", "hasChildren": false @@ -35505,7 +38255,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Metrics Enabled", "help": "Enable metrics signal export to the configured OpenTelemetry collector endpoint. Keep enabled for runtime health dashboards, and disable only if metric volume must be minimized.", "hasChildren": false @@ -35517,7 +38269,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Protocol", "help": "OTel transport protocol for telemetry export: \"http/protobuf\" or \"grpc\" depending on collector support. Use the protocol your observability backend expects to avoid dropped telemetry payloads.", "hasChildren": false @@ -35529,7 +38283,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Trace Sample Rate", "help": "Trace sampling rate (0-1) controlling how much trace traffic is exported to observability backends. Lower rates reduce overhead/cost, while higher rates improve debugging fidelity.", "hasChildren": false @@ -35541,7 +38297,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Service Name", "help": "Service name reported in telemetry resource attributes to identify this gateway instance in observability backends. Use stable names so dashboards and alerts remain consistent over deployments.", "hasChildren": false @@ -35553,7 +38311,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "OpenTelemetry Traces Enabled", "help": "Enable trace signal export to the configured OpenTelemetry collector endpoint. Keep enabled when latency/debug tracing is needed, and disable if you only want metrics/logs.", "hasChildren": false @@ -35565,7 +38325,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Stuck Session Warning Threshold (ms)", "help": "Age threshold in milliseconds for emitting stuck-session warnings while a session remains in processing state. Increase for long multi-tool turns to reduce false positives; decrease for faster hang detection.", "hasChildren": false @@ -35577,7 +38340,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Discovery", "help": "Service discovery settings for local mDNS advertisement and optional wide-area presence signaling. Keep discovery scoped to expected networks to avoid leaking service metadata.", "hasChildren": true @@ -35589,7 +38354,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "mDNS Discovery", "help": "mDNS discovery configuration group for local network advertisement and discovery behavior tuning. Keep minimal mode for routine LAN discovery unless extra metadata is required.", "hasChildren": true @@ -35599,10 +38366,16 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["off", "minimal", "full"], + "enumValues": [ + "off", + "minimal", + "full" + ], "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "mDNS Discovery Mode", "help": "mDNS broadcast mode (\"minimal\" default, \"full\" includes cliPath/sshPort, \"off\" disables mDNS).", "hasChildren": false @@ -35614,7 +38387,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Wide-area Discovery", "help": "Wide-area discovery configuration group for exposing discovery signals beyond local-link scopes. Enable only in deployments that intentionally aggregate gateway presence across sites.", "hasChildren": true @@ -35626,7 +38401,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Wide-area Discovery Domain", "help": "Optional unicast DNS-SD domain for wide-area discovery, such as openclaw.internal. Use this when you intentionally publish gateway discovery beyond local mDNS scopes.", "hasChildren": false @@ -35638,7 +38415,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Wide-area Discovery Enabled", "help": "Enables wide-area discovery signaling when your environment needs non-local gateway discovery. Keep disabled unless cross-network discovery is operationally required.", "hasChildren": false @@ -35650,7 +38429,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Environment", "help": "Environment import and override settings used to supply runtime variables to the gateway process. Use this section to control shell-env loading and explicit variable injection behavior.", "hasChildren": true @@ -35672,7 +38453,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Shell Environment Import", "help": "Shell environment import controls for loading variables from your login shell during startup. Keep this enabled when you depend on profile-defined secrets or PATH customizations.", "hasChildren": true @@ -35684,7 +38467,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Shell Environment Import Enabled", "help": "Enables loading environment variables from the user shell profile during startup initialization. Keep enabled for developer machines, or disable in locked-down service environments with explicit env management.", "hasChildren": false @@ -35696,7 +38481,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Shell Environment Import Timeout (ms)", "help": "Maximum time in milliseconds allowed for shell environment resolution before fallback behavior applies. Use tighter timeouts for faster startup, or increase when shell initialization is heavy.", "hasChildren": false @@ -35708,7 +38495,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Environment Variable Overrides", "help": "Explicit key/value environment variable overrides merged into runtime process environment for OpenClaw. Use this for deterministic env configuration instead of relying only on shell profile side effects.", "hasChildren": true @@ -35730,7 +38519,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gateway", "help": "Gateway runtime surface for bind mode, auth, control UI, remote transport, and operational safety controls. Keep conservative defaults unless you intentionally expose the gateway beyond trusted local interfaces.", "hasChildren": true @@ -35742,7 +38533,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network", "reliability"], + "tags": [ + "access", + "network", + "reliability" + ], "label": "Gateway Allow x-real-ip Fallback", "help": "Enables x-real-ip fallback when x-forwarded-for is missing in proxy scenarios. Keep disabled unless your ingress stack requires this compatibility behavior.", "hasChildren": false @@ -35754,7 +38549,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Auth", "help": "Authentication policy for gateway HTTP/WebSocket access including mode, credentials, trusted-proxy behavior, and rate limiting. Keep auth enabled for every non-loopback deployment.", "hasChildren": true @@ -35766,7 +38563,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Gateway Auth Allow Tailscale Identity", "help": "Allows trusted Tailscale identity paths to satisfy gateway auth checks when configured. Use this only when your tailnet identity posture is strong and operator workflows depend on it.", "hasChildren": false @@ -35778,7 +38578,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Auth Mode", "help": "Gateway auth mode: \"none\", \"token\", \"password\", or \"trusted-proxy\" depending on your edge architecture. Use token/password for direct exposure, and trusted-proxy only behind hardened identity-aware proxies.", "hasChildren": false @@ -35786,11 +38588,19 @@ { "path": "gateway.auth.password", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["access", "auth", "network", "security"], + "tags": [ + "access", + "auth", + "network", + "security" + ], "label": "Gateway Password", "help": "Required for Tailscale funnel.", "hasChildren": true @@ -35832,7 +38642,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "performance"], + "tags": [ + "network", + "performance" + ], "label": "Gateway Auth Rate Limit", "help": "Login/auth attempt throttling controls to reduce credential brute-force risk at the gateway boundary. Keep enabled in exposed environments and tune thresholds to your traffic baseline.", "hasChildren": true @@ -35880,11 +38693,19 @@ { "path": "gateway.auth.token", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["access", "auth", "network", "security"], + "tags": [ + "access", + "auth", + "network", + "security" + ], "label": "Gateway Token", "help": "Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.", "hasChildren": true @@ -35926,7 +38747,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Trusted Proxy Auth", "help": "Trusted-proxy auth header mapping for upstream identity providers that inject user claims. Use only with known proxy CIDRs and strict header allowlists to prevent spoofed identity headers.", "hasChildren": true @@ -35988,7 +38811,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Bind Mode", "help": "Network bind profile: \"auto\", \"lan\", \"loopback\", \"custom\", or \"tailnet\" to control interface exposure. Keep \"loopback\" or \"auto\" for safest local operation unless external clients must connect.", "hasChildren": false @@ -36000,7 +38825,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "reliability"], + "tags": [ + "network", + "reliability" + ], "label": "Gateway Channel Health Check Interval (min)", "help": "Interval in minutes for automatic channel health probing and status updates. Use lower intervals for faster detection, or higher intervals to reduce periodic probe noise.", "hasChildren": false @@ -36012,7 +38840,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "performance"], + "tags": [ + "network", + "performance" + ], "label": "Gateway Channel Max Restarts Per Hour", "help": "Maximum number of health-monitor-initiated channel restarts allowed within a rolling one-hour window. Once hit, further restarts are skipped until the window expires. Default: 10.", "hasChildren": false @@ -36024,7 +38855,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Channel Stale Event Threshold (min)", "help": "How many minutes a connected channel can go without receiving any event before the health monitor treats it as a stale socket and triggers a restart. Default: 30.", "hasChildren": false @@ -36036,7 +38869,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Control UI", "help": "Control UI hosting settings including enablement, pathing, and browser-origin/auth hardening behavior. Keep UI exposure minimal and pair with strong auth controls before internet-facing deployments.", "hasChildren": true @@ -36048,7 +38883,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Control UI Allowed Origins", "help": "Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com). Required for non-loopback Control UI deployments unless dangerous Host-header fallback is explicitly enabled.", "hasChildren": true @@ -36070,7 +38908,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "network", "security"], + "tags": [ + "access", + "advanced", + "network", + "security" + ], "label": "Insecure Control UI Auth Toggle", "help": "Loosens strict browser auth checks for Control UI when you must run a non-standard setup. Keep this off unless you trust your network and proxy path, because impersonation risk is higher.", "hasChildren": false @@ -36082,7 +38925,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "storage"], + "tags": [ + "network", + "storage" + ], "label": "Control UI Base Path", "help": "Optional URL prefix where the Control UI is served (e.g. /openclaw).", "hasChildren": false @@ -36094,7 +38940,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "network", "security"], + "tags": [ + "access", + "advanced", + "network", + "security" + ], "label": "Dangerously Allow Host-Header Origin Fallback", "help": "DANGEROUS toggle that enables Host-header based origin fallback for Control UI/WebChat websocket checks. This mode is supported when your deployment intentionally relies on Host-header origin policy; explicit gateway.controlUi.allowedOrigins remains the recommended hardened default.", "hasChildren": false @@ -36106,7 +38957,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "network", "security"], + "tags": [ + "access", + "advanced", + "network", + "security" + ], "label": "Dangerously Disable Control UI Device Auth", "help": "Disables Control UI device identity checks and relies on token/password only. Use only for short-lived debugging on trusted networks, then turn it off immediately.", "hasChildren": false @@ -36118,7 +38974,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Control UI Enabled", "help": "Enables serving the gateway Control UI from the gateway HTTP process when true. Keep enabled for local administration, and disable when an external control surface replaces it.", "hasChildren": false @@ -36130,7 +38988,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Control UI Assets Root", "help": "Optional filesystem root for Control UI assets (defaults to dist/control-ui).", "hasChildren": false @@ -36142,7 +39002,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Custom Bind Host", "help": "Explicit bind host/IP used when gateway.bind is set to custom for manual interface targeting. Use a precise address and avoid wildcard binds unless external exposure is required.", "hasChildren": false @@ -36154,7 +39016,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway HTTP API", "help": "Gateway HTTP API configuration grouping endpoint toggles and transport-facing API exposure controls. Keep only required endpoints enabled to reduce attack surface.", "hasChildren": true @@ -36166,7 +39030,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway HTTP Endpoints", "help": "HTTP endpoint feature toggles under the gateway API surface for compatibility routes and optional integrations. Enable endpoints intentionally and monitor access patterns after rollout.", "hasChildren": true @@ -36188,7 +39054,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "OpenAI Chat Completions Endpoint", "help": "Enable the OpenAI-compatible `POST /v1/chat/completions` endpoint (default: false).", "hasChildren": false @@ -36200,7 +39068,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network"], + "tags": [ + "media", + "network" + ], "label": "OpenAI Chat Completions Image Limits", "help": "Image fetch/validation controls for OpenAI-compatible `image_url` parts.", "hasChildren": true @@ -36212,7 +39083,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "media", "network"], + "tags": [ + "access", + "media", + "network" + ], "label": "OpenAI Chat Completions Image MIME Allowlist", "help": "Allowed MIME types for `image_url` parts (case-insensitive list).", "hasChildren": true @@ -36234,7 +39109,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "media", "network"], + "tags": [ + "access", + "media", + "network" + ], "label": "OpenAI Chat Completions Allow Image URLs", "help": "Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported).", "hasChildren": false @@ -36246,7 +39125,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network", "performance"], + "tags": [ + "media", + "network", + "performance" + ], "label": "OpenAI Chat Completions Image Max Bytes", "help": "Max bytes per fetched/decoded `image_url` image (default: 10MB).", "hasChildren": false @@ -36258,7 +39141,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network", "performance", "storage"], + "tags": [ + "media", + "network", + "performance", + "storage" + ], "label": "OpenAI Chat Completions Image Max Redirects", "help": "Max HTTP redirects allowed when fetching `image_url` URLs (default: 3).", "hasChildren": false @@ -36270,7 +39158,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network", "performance"], + "tags": [ + "media", + "network", + "performance" + ], "label": "OpenAI Chat Completions Image Timeout (ms)", "help": "Timeout in milliseconds for `image_url` URL fetches (default: 10000).", "hasChildren": false @@ -36282,7 +39174,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "media", "network"], + "tags": [ + "access", + "media", + "network" + ], "label": "OpenAI Chat Completions Image URL Allowlist", "help": "Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards.", "hasChildren": true @@ -36304,7 +39200,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "performance"], + "tags": [ + "network", + "performance" + ], "label": "OpenAI Chat Completions Max Body Bytes", "help": "Max request body size in bytes for `/v1/chat/completions` (default: 20MB).", "hasChildren": false @@ -36316,7 +39215,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network", "performance"], + "tags": [ + "media", + "network", + "performance" + ], "label": "OpenAI Chat Completions Max Image Parts", "help": "Max number of `image_url` parts accepted from the latest user message (default: 8).", "hasChildren": false @@ -36328,7 +39231,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "network", "performance"], + "tags": [ + "media", + "network", + "performance" + ], "label": "OpenAI Chat Completions Max Total Image Bytes", "help": "Max cumulative decoded bytes across all `image_url` parts in one request (default: 20MB).", "hasChildren": false @@ -36610,7 +39517,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway HTTP Security Headers", "help": "Optional HTTP response security headers applied by the gateway process itself. Prefer setting these at your reverse proxy when TLS terminates there.", "hasChildren": true @@ -36618,11 +39527,16 @@ { "path": "gateway.http.securityHeaders.strictTransportSecurity", "kind": "core", - "type": ["boolean", "string"], + "type": [ + "boolean", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Strict Transport Security Header", "help": "Value for the Strict-Transport-Security response header. Set only on HTTPS origins that you fully control; use false to explicitly disable.", "hasChildren": false @@ -36634,7 +39548,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Mode", "help": "Gateway operation mode: \"local\" runs channels and agent runtime on this host, while \"remote\" connects through remote transport. Keep \"local\" unless you intentionally run a split remote gateway topology.", "hasChildren": false @@ -36656,7 +39572,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Gateway Node Allowlist (Extra Commands)", "help": "Extra node.invoke commands to allow beyond the gateway defaults (array of command strings). Enabling dangerous commands here is a security-sensitive override and is flagged by `openclaw security audit`.", "hasChildren": true @@ -36688,7 +39607,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Node Browser Mode", "help": "Node browser routing (\"auto\" = pick single connected browser node, \"manual\" = require node param, \"off\" = disable).", "hasChildren": false @@ -36700,7 +39621,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Node Browser Pin", "help": "Pin browser routing to a specific node id or name (optional).", "hasChildren": false @@ -36712,7 +39635,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Gateway Node Denylist", "help": "Node command names to block even if present in node claims or default allowlist (exact command-name matching only, e.g. `system.run`; does not inspect shell text inside that command).", "hasChildren": true @@ -36734,7 +39660,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Port", "help": "TCP port used by the gateway listener for API, control UI, and channel-facing ingress paths. Use a dedicated port and avoid collisions with reverse proxies or local developer services.", "hasChildren": false @@ -36746,7 +39674,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Push Delivery", "help": "Push-delivery settings used by the gateway when it needs to wake or notify paired devices. Configure relay-backed APNs here for official iOS builds; direct APNs auth remains env-based for local/manual builds.", "hasChildren": true @@ -36758,7 +39688,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway APNs Delivery", "help": "APNs delivery settings for iOS devices paired to this gateway. Use relay settings for official/TestFlight builds that register through the external push relay.", "hasChildren": true @@ -36770,7 +39702,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway APNs Relay", "help": "External relay settings for relay-backed APNs sends. The gateway uses this relay for push.test, wake nudges, and reconnect wakes after a paired official iOS build publishes a relay-backed registration.", "hasChildren": true @@ -36782,7 +39716,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "network"], + "tags": [ + "advanced", + "network" + ], "label": "Gateway APNs Relay Base URL", "help": "Base HTTPS URL for the external APNs relay service used by official/TestFlight iOS builds. Keep this aligned with the relay URL baked into the iOS build so registration and send traffic hit the same deployment.", "hasChildren": false @@ -36794,7 +39731,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "performance"], + "tags": [ + "network", + "performance" + ], "label": "Gateway APNs Relay Timeout (ms)", "help": "Timeout in milliseconds for relay send requests from the gateway to the APNs relay (default: 10000). Increase for slower relays or networks, or lower to fail wake attempts faster.", "hasChildren": false @@ -36806,7 +39746,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "reliability"], + "tags": [ + "network", + "reliability" + ], "label": "Config Reload", "help": "Live config-reload policy for how edits are applied and when full restarts are triggered. Keep hybrid behavior for safest operational updates unless debugging reload internals.", "hasChildren": true @@ -36818,7 +39761,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "performance", "reliability"], + "tags": [ + "network", + "performance", + "reliability" + ], "label": "Config Reload Debounce (ms)", "help": "Debounce window (ms) before applying config changes.", "hasChildren": false @@ -36830,7 +39777,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "reliability"], + "tags": [ + "network", + "reliability" + ], "label": "Config Reload Mode", "help": "Controls how config edits are applied: \"off\" ignores live edits, \"restart\" always restarts, \"hot\" applies in-process, and \"hybrid\" tries hot then restarts if required. Keep \"hybrid\" for safest routine updates.", "hasChildren": false @@ -36842,7 +39792,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Remote Gateway", "help": "Remote gateway connection settings for direct or SSH transport when this instance proxies to another runtime host. Use remote mode only when split-host operation is intentionally configured.", "hasChildren": true @@ -36850,11 +39802,18 @@ { "path": "gateway.remote.password", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "network", "security"], + "tags": [ + "auth", + "network", + "security" + ], "label": "Remote Gateway Password", "help": "Password credential used for remote gateway authentication when password mode is enabled. Keep this secret managed externally and avoid plaintext values in committed config.", "hasChildren": true @@ -36896,7 +39855,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Remote Gateway SSH Identity", "help": "Optional SSH identity file path (passed to ssh -i).", "hasChildren": false @@ -36908,7 +39869,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Remote Gateway SSH Target", "help": "Remote gateway over SSH (tunnels the gateway port to localhost). Format: user@host or user@host:port.", "hasChildren": false @@ -36920,7 +39883,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "network", "security"], + "tags": [ + "auth", + "network", + "security" + ], "label": "Remote Gateway TLS Fingerprint", "help": "Expected sha256 TLS fingerprint for the remote gateway (pin to avoid MITM).", "hasChildren": false @@ -36928,11 +39895,18 @@ { "path": "gateway.remote.token", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "network", "security"], + "tags": [ + "auth", + "network", + "security" + ], "label": "Remote Gateway Token", "help": "Bearer token used to authenticate this client to a remote gateway in token-auth deployments. Store via secret/env substitution and rotate alongside remote gateway auth changes.", "hasChildren": true @@ -36974,7 +39948,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Remote Gateway Transport", "help": "Remote connection transport: \"direct\" uses configured URL connectivity, while \"ssh\" tunnels through SSH. Use SSH when you need encrypted tunnel semantics without exposing remote ports.", "hasChildren": false @@ -36986,7 +39962,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Remote Gateway URL", "help": "Remote Gateway WebSocket URL (ws:// or wss://).", "hasChildren": false @@ -36998,7 +39976,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Tailscale", "help": "Tailscale integration settings for Serve/Funnel exposure and lifecycle handling on gateway start/exit. Keep off unless your deployment intentionally relies on Tailscale ingress.", "hasChildren": true @@ -37010,7 +39990,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Tailscale Mode", "help": "Tailscale publish mode: \"off\", \"serve\", or \"funnel\" for private or public exposure paths. Use \"serve\" for tailnet-only access and \"funnel\" only when public internet reachability is required.", "hasChildren": false @@ -37022,7 +40004,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Tailscale Reset on Exit", "help": "Resets Tailscale Serve/Funnel state on gateway exit to avoid stale published routes after shutdown. Keep enabled unless another controller manages publish lifecycle outside the gateway.", "hasChildren": false @@ -37034,7 +40018,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway TLS", "help": "TLS certificate and key settings for terminating HTTPS directly in the gateway process. Use explicit certificates in production and avoid plaintext exposure on untrusted networks.", "hasChildren": true @@ -37046,7 +40032,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway TLS Auto-Generate Cert", "help": "Auto-generates a local TLS certificate/key pair when explicit files are not configured. Use only for local/dev setups and replace with real certificates for production traffic.", "hasChildren": false @@ -37058,7 +40046,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "storage"], + "tags": [ + "network", + "storage" + ], "label": "Gateway TLS CA Path", "help": "Optional CA bundle path for client verification or custom trust-chain requirements at the gateway edge. Use this when private PKI or custom certificate chains are part of deployment.", "hasChildren": false @@ -37070,7 +40061,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "storage"], + "tags": [ + "network", + "storage" + ], "label": "Gateway TLS Certificate Path", "help": "Filesystem path to the TLS certificate file used by the gateway when TLS is enabled. Use managed certificate paths and keep renewal automation aligned with this location.", "hasChildren": false @@ -37082,7 +40076,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway TLS Enabled", "help": "Enables TLS termination at the gateway listener so clients connect over HTTPS/WSS directly. Keep enabled for direct internet exposure or any untrusted network boundary.", "hasChildren": false @@ -37094,7 +40090,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network", "storage"], + "tags": [ + "network", + "storage" + ], "label": "Gateway TLS Key Path", "help": "Filesystem path to the TLS private key file used by the gateway when TLS is enabled. Keep this key file permission-restricted and rotate per your security policy.", "hasChildren": false @@ -37106,7 +40105,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Tool Exposure Policy", "help": "Gateway-level tool exposure allow/deny policy that can restrict runtime tool availability independent of agent/tool profiles. Use this for coarse emergency controls and production hardening.", "hasChildren": true @@ -37118,7 +40119,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Gateway Tool Allowlist", "help": "Explicit gateway-level tool allowlist when you want a narrow set of tools available at runtime. Use this for locked-down environments where tool scope must be tightly controlled.", "hasChildren": true @@ -37140,7 +40144,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network"], + "tags": [ + "access", + "network" + ], "label": "Gateway Tool Denylist", "help": "Explicit gateway-level tool denylist to block risky tools even if lower-level policies allow them. Use deny rules for emergency response and defense-in-depth hardening.", "hasChildren": true @@ -37162,7 +40169,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Gateway Trusted Proxy CIDRs", "help": "CIDR/IP allowlist of upstream proxies permitted to provide forwarded client identity headers. Keep this list narrow so untrusted hops cannot impersonate users.", "hasChildren": true @@ -37184,7 +40193,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hooks", "help": "Inbound webhook automation surface for mapping external events into wake or agent actions in OpenClaw. Keep this locked down with explicit token/session/agent controls before exposing it beyond trusted networks.", "hasChildren": true @@ -37196,7 +40207,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Hooks Allowed Agent IDs", "help": "Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents.", "hasChildren": true @@ -37218,7 +40231,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Hooks Allowed Session Key Prefixes", "help": "Allowlist of accepted session-key prefixes for inbound hook requests when caller-provided keys are enabled. Use narrow prefixes to prevent arbitrary session-key injection.", "hasChildren": true @@ -37240,7 +40256,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Hooks Allow Request Session Key", "help": "Allows callers to supply a session key in hook requests when true, enabling caller-controlled routing. Keep false unless trusted integrators explicitly need custom session threading.", "hasChildren": false @@ -37252,7 +40271,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Hooks Default Session Key", "help": "Fallback session key used for hook deliveries when a request does not provide one through allowed channels. Use a stable but scoped key to avoid mixing unrelated automation conversations.", "hasChildren": false @@ -37264,7 +40285,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hooks Enabled", "help": "Enables the hooks endpoint and mapping execution pipeline for inbound webhook requests. Keep disabled unless you are actively routing external events into the gateway.", "hasChildren": false @@ -37276,7 +40299,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook", "help": "Gmail push integration settings used for Pub/Sub notifications and optional local callback serving. Keep this scoped to dedicated Gmail automation accounts where possible.", "hasChildren": true @@ -37288,7 +40313,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Account", "help": "Google account identifier used for Gmail watch/subscription operations in this hook integration. Use a dedicated automation mailbox account to isolate operational permissions.", "hasChildren": false @@ -37300,7 +40327,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Gmail Hook Allow Unsafe External Content", "help": "Allows less-sanitized external Gmail content to pass into processing when enabled. Keep disabled for safer defaults, and enable only for trusted mail streams with controlled transforms.", "hasChildren": false @@ -37312,7 +40341,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Callback URL", "help": "Public callback URL Gmail or intermediaries invoke to deliver notifications into this hook pipeline. Keep this URL protected with token validation and restricted network exposure.", "hasChildren": false @@ -37324,7 +40355,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Include Body", "help": "When true, fetch and include email body content for downstream mapping/agent processing. Keep false unless body text is required, because this increases payload size and sensitivity.", "hasChildren": false @@ -37336,7 +40369,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Label", "help": "Optional Gmail label filter limiting which labeled messages trigger hook events. Keep filters narrow to avoid flooding automations with unrelated inbox traffic.", "hasChildren": false @@ -37348,7 +40383,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Gmail Hook Max Body Bytes", "help": "Maximum Gmail payload bytes processed per event when includeBody is enabled. Keep conservative limits to reduce oversized message processing cost and risk.", "hasChildren": false @@ -37360,7 +40397,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Gmail Hook Model Override", "help": "Optional model override for Gmail-triggered runs when mailbox automations should use dedicated model behavior. Keep unset to inherit agent defaults unless mailbox tasks need specialization.", "hasChildren": false @@ -37372,7 +40411,10 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Gmail Hook Push Token", "help": "Shared secret token required on Gmail push hook callbacks before processing notifications. Use env substitution and rotate if callback endpoints are exposed externally.", "hasChildren": false @@ -37384,7 +40426,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Renew Interval (min)", "help": "Renewal cadence in minutes for Gmail watch subscriptions to prevent expiration. Set below provider expiration windows and monitor renew failures in logs.", "hasChildren": false @@ -37396,7 +40440,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Local Server", "help": "Local callback server settings block for directly receiving Gmail notifications without a separate ingress layer. Enable only when this process should terminate webhook traffic itself.", "hasChildren": true @@ -37408,7 +40454,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Server Bind Address", "help": "Bind address for the local Gmail callback HTTP server used when serving hooks directly. Keep loopback-only unless external ingress is intentionally required.", "hasChildren": false @@ -37420,7 +40468,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Gmail Hook Server Path", "help": "HTTP path on the local Gmail callback server where push notifications are accepted. Keep this consistent with subscription configuration to avoid dropped events.", "hasChildren": false @@ -37432,7 +40482,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Server Port", "help": "Port for the local Gmail callback HTTP server when serve mode is enabled. Use a dedicated port to avoid collisions with gateway/control interfaces.", "hasChildren": false @@ -37444,7 +40496,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Subscription", "help": "Pub/Sub subscription consumed by the gateway to receive Gmail change notifications from the configured topic. Keep subscription ownership clear so multiple consumers do not race unexpectedly.", "hasChildren": false @@ -37456,7 +40510,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Tailscale", "help": "Tailscale exposure configuration block for publishing Gmail callbacks through Serve/Funnel routes. Use private tailnet modes before enabling any public ingress path.", "hasChildren": true @@ -37468,7 +40524,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Tailscale Mode", "help": "Tailscale exposure mode for Gmail callbacks: \"off\", \"serve\", or \"funnel\". Use \"serve\" for private tailnet delivery and \"funnel\" only when public internet ingress is required.", "hasChildren": false @@ -37480,7 +40538,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Gmail Hook Tailscale Path", "help": "Path published by Tailscale Serve/Funnel for Gmail callback forwarding when enabled. Keep it aligned with Gmail webhook config so requests reach the expected handler.", "hasChildren": false @@ -37492,7 +40552,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Tailscale Target", "help": "Local service target forwarded by Tailscale Serve/Funnel (for example http://127.0.0.1:8787). Use explicit loopback targets to avoid ambiguous routing.", "hasChildren": false @@ -37504,7 +40566,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Thinking Override", "help": "Thinking effort override for Gmail-driven agent runs: \"off\", \"minimal\", \"low\", \"medium\", or \"high\". Keep modest defaults for routine inbox automations to control cost and latency.", "hasChildren": false @@ -37516,7 +40580,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gmail Hook Pub/Sub Topic", "help": "Google Pub/Sub topic name used by Gmail watch to publish change notifications for this account. Ensure the topic IAM grants Gmail publish access before enabling watches.", "hasChildren": false @@ -37528,7 +40594,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hooks", "help": "Internal hook runtime settings for bundled/custom event handlers loaded from module paths. Use this for trusted in-process automations and keep handler loading tightly scoped.", "hasChildren": true @@ -37540,7 +40608,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hooks Enabled", "help": "Enables processing for internal hook handlers and configured entries in the internal hook runtime. Keep disabled unless internal hook handlers are intentionally configured.", "hasChildren": false @@ -37552,7 +40622,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Entries", "help": "Configured internal hook entry records used to register concrete runtime handlers and metadata. Keep entries explicit and versioned so production behavior is auditable.", "hasChildren": true @@ -37613,7 +40685,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Handlers", "help": "List of internal event handlers mapping event names to modules and optional exports. Keep handler definitions explicit so event-to-code routing is auditable.", "hasChildren": true @@ -37635,7 +40709,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Event", "help": "Internal event name that triggers this handler module when emitted by the runtime. Use stable event naming conventions to avoid accidental overlap across handlers.", "hasChildren": false @@ -37647,7 +40723,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Export", "help": "Optional named export for the internal hook handler function when module default export is not used. Set this when one module ships multiple handler entrypoints.", "hasChildren": false @@ -37659,7 +40737,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Module", "help": "Safe relative module path for the internal hook handler implementation loaded at runtime. Keep module files in reviewed directories and avoid dynamic path composition.", "hasChildren": false @@ -37671,7 +40751,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Install Records", "help": "Install metadata for internal hook modules, including source and resolved artifacts for repeatable deployments. Use this as operational provenance and avoid manual drift edits.", "hasChildren": true @@ -37833,7 +40915,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Internal Hook Loader", "help": "Internal hook loader settings controlling where handler modules are discovered at startup. Use constrained load roots to reduce accidental module conflicts or shadowing.", "hasChildren": true @@ -37845,7 +40929,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Internal Hook Extra Directories", "help": "Additional directories searched for internal hook modules beyond default load paths. Keep this minimal and controlled to reduce accidental module shadowing.", "hasChildren": true @@ -37867,7 +40953,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mappings", "help": "Ordered mapping rules that match inbound hook requests and choose wake or agent actions with optional delivery routing. Use specific mappings first to avoid broad pattern rules capturing everything.", "hasChildren": true @@ -37889,7 +40977,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Action", "help": "Mapping action type: \"wake\" triggers agent wake flow, while \"agent\" sends directly to agent handling. Use \"agent\" for immediate execution and \"wake\" when heartbeat-driven processing is preferred.", "hasChildren": false @@ -37901,7 +40991,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Agent ID", "help": "Target agent ID for mapping execution when action routing should not use defaults. Use dedicated automation agents to isolate webhook behavior from interactive operator sessions.", "hasChildren": false @@ -37913,7 +41005,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Hook Mapping Allow Unsafe External Content", "help": "When true, mapping content may include less-sanitized external payload data in generated messages. Keep false by default and enable only for trusted sources with reviewed transform logic.", "hasChildren": false @@ -37925,7 +41019,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Delivery Channel", "help": "Delivery channel override for mapping outputs (for example \"last\", \"telegram\", \"discord\", \"slack\", \"signal\", \"imessage\", or \"msteams\"). Keep channel overrides explicit to avoid accidental cross-channel sends.", "hasChildren": false @@ -37937,7 +41033,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Deliver Reply", "help": "Controls whether mapping execution results are delivered back to a channel destination versus being processed silently. Disable delivery for background automations that should not post user-facing output.", "hasChildren": false @@ -37949,7 +41047,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping ID", "help": "Optional stable identifier for a hook mapping entry used for auditing, troubleshooting, and targeted updates. Use unique IDs so logs and config diffs can reference mappings unambiguously.", "hasChildren": false @@ -37961,7 +41061,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Match", "help": "Grouping object for mapping match predicates such as path and source before action routing is applied. Keep match criteria specific so unrelated webhook traffic does not trigger automations.", "hasChildren": true @@ -37973,7 +41075,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Hook Mapping Match Path", "help": "Path match condition for a hook mapping, usually compared against the inbound request path. Use this to split automation behavior by webhook endpoint path families.", "hasChildren": false @@ -37985,7 +41089,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Match Source", "help": "Source match condition for a hook mapping, typically set by trusted upstream metadata or adapter logic. Use stable source identifiers so routing remains deterministic across retries.", "hasChildren": false @@ -37997,7 +41103,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Message Template", "help": "Template for synthesizing structured mapping input into the final message content sent to the target action path. Keep templates deterministic so downstream parsing and behavior remain stable.", "hasChildren": false @@ -38009,7 +41117,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Hook Mapping Model Override", "help": "Optional model override for mapping-triggered runs when automation should use a different model than agent defaults. Use this sparingly so behavior remains predictable across mapping executions.", "hasChildren": false @@ -38021,7 +41131,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Name", "help": "Human-readable mapping display name used in diagnostics and operator-facing config UIs. Keep names concise and descriptive so routing intent is obvious during incident review.", "hasChildren": false @@ -38033,7 +41145,10 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["security", "storage"], + "tags": [ + "security", + "storage" + ], "label": "Hook Mapping Session Key", "help": "Explicit session key override for mapping-delivered messages to control thread continuity. Use stable scoped keys so repeated events correlate without leaking into unrelated conversations.", "hasChildren": false @@ -38045,7 +41160,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Text Template", "help": "Text-only fallback template used when rich payload rendering is not desired or not supported. Use this to provide a concise, consistent summary string for chat delivery surfaces.", "hasChildren": false @@ -38057,7 +41174,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Thinking Override", "help": "Optional thinking-effort override for mapping-triggered runs to tune latency versus reasoning depth. Keep low or minimal for high-volume hooks unless deeper reasoning is clearly required.", "hasChildren": false @@ -38069,7 +41188,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Hook Mapping Timeout (sec)", "help": "Maximum runtime allowed for mapping action execution before timeout handling applies. Use tighter limits for high-volume webhook sources to prevent queue pileups.", "hasChildren": false @@ -38081,7 +41202,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Delivery Destination", "help": "Destination identifier inside the selected channel when mapping replies should route to a fixed target. Verify provider-specific destination formats before enabling production mappings.", "hasChildren": false @@ -38093,7 +41216,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Transform", "help": "Transform configuration block defining module/export preprocessing before mapping action handling. Use transforms only from reviewed code paths and keep behavior deterministic for repeatable automation.", "hasChildren": true @@ -38105,7 +41230,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Transform Export", "help": "Named export to invoke from the transform module; defaults to module default export when omitted. Set this when one file hosts multiple transform handlers.", "hasChildren": false @@ -38117,7 +41244,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Transform Module", "help": "Relative transform module path loaded from hooks.transformsDir to rewrite incoming payloads before delivery. Keep modules local, reviewed, and free of path traversal patterns.", "hasChildren": false @@ -38129,7 +41258,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hook Mapping Wake Mode", "help": "Wake scheduling mode: \"now\" wakes immediately, while \"next-heartbeat\" defers until the next heartbeat cycle. Use deferred mode for lower-priority automations that can tolerate slight delay.", "hasChildren": false @@ -38141,7 +41272,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Hooks Max Body Bytes", "help": "Maximum accepted webhook payload size in bytes before the request is rejected. Keep this bounded to reduce abuse risk and protect memory usage under bursty integrations.", "hasChildren": false @@ -38153,7 +41286,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Hooks Endpoint Path", "help": "HTTP path used by the hooks endpoint (for example `/hooks`) on the gateway control server. Use a non-guessable path and combine it with token validation for defense in depth.", "hasChildren": false @@ -38165,7 +41300,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Hooks Presets", "help": "Named hook preset bundles applied at load time to seed standard mappings and behavior defaults. Keep preset usage explicit so operators can audit which automations are active.", "hasChildren": true @@ -38187,7 +41324,10 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Hooks Auth Token", "help": "Shared bearer token checked by hooks ingress for request authentication before mappings run. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.", "hasChildren": false @@ -38199,7 +41339,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Hooks Transforms Directory", "help": "Base directory for hook transform modules referenced by mapping transform.module paths. Use a controlled repo directory so dynamic imports remain reviewable and predictable.", "hasChildren": false @@ -38211,7 +41353,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Logging", "help": "Logging behavior controls for severity, output destinations, formatting, and sensitive-data redaction. Keep levels and redaction strict enough for production while preserving useful diagnostics.", "hasChildren": true @@ -38223,7 +41367,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Console Log Level", "help": "Console-specific log threshold: \"silent\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", or \"trace\" for terminal output control. Use this to keep local console quieter while retaining richer file logging if needed.", "hasChildren": false @@ -38235,7 +41381,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Console Log Style", "help": "Console output format style: \"pretty\", \"compact\", or \"json\" based on operator and ingestion needs. Use json for machine parsing pipelines and pretty/compact for human-first terminal workflows.", "hasChildren": false @@ -38247,7 +41395,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "storage"], + "tags": [ + "observability", + "storage" + ], "label": "Log File Path", "help": "Optional file path for persisted log output in addition to or instead of console logging. Use a managed writable path and align retention/rotation with your operational policy.", "hasChildren": false @@ -38259,7 +41410,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Log Level", "help": "Primary log level threshold for runtime logger output: \"silent\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", or \"trace\". Keep \"info\" or \"warn\" for production, and use debug/trace only during investigation.", "hasChildren": false @@ -38281,7 +41434,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "privacy"], + "tags": [ + "observability", + "privacy" + ], "label": "Custom Redaction Patterns", "help": "Additional custom redact regex patterns applied to log output before emission/storage. Use this to mask org-specific tokens and identifiers not covered by built-in redaction rules.", "hasChildren": true @@ -38303,7 +41459,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability", "privacy"], + "tags": [ + "observability", + "privacy" + ], "label": "Sensitive Data Redaction Mode", "help": "Sensitive redaction mode: \"off\" disables built-in masking, while \"tools\" redacts sensitive tool/config payload fields. Keep \"tools\" in shared logs unless you have isolated secure log sinks.", "hasChildren": false @@ -38315,7 +41474,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Media", "help": "Top-level media behavior shared across providers and tools that handle inbound files. Keep defaults unless you need stable filenames for external processing pipelines or longer-lived inbound media retention.", "hasChildren": true @@ -38327,7 +41488,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Preserve Media Filenames", "help": "When enabled, uploaded media keeps its original filename instead of a generated temp-safe name. Turn this on when downstream automations depend on stable names, and leave off to reduce accidental filename leakage.", "hasChildren": false @@ -38339,7 +41502,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Media Retention TTL (hours)", "help": "Optional retention window in hours for persisted inbound media cleanup across the full media tree. Leave unset to preserve legacy behavior, or set values like 24 (1 day) or 168 (7 days) when you want automatic cleanup.", "hasChildren": false @@ -38351,7 +41516,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory", "help": "Memory backend configuration (global).", "hasChildren": true @@ -38363,7 +41530,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Backend", "help": "Selects the global memory engine: \"builtin\" uses OpenClaw memory internals, while \"qmd\" uses the QMD sidecar pipeline. Keep \"builtin\" unless you intentionally operate QMD.", "hasChildren": false @@ -38375,7 +41544,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Memory Citations Mode", "help": "Controls citation visibility in replies: \"auto\" shows citations when useful, \"on\" always shows them, and \"off\" hides them. Keep \"auto\" for a balanced signal-to-noise default.", "hasChildren": false @@ -38397,7 +41568,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Binary", "help": "Sets the executable path for the `qmd` binary used by the QMD backend (default: resolved from PATH). Use an explicit absolute path when multiple qmd installs exist or PATH differs across environments.", "hasChildren": false @@ -38409,7 +41582,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Include Default Memory", "help": "Automatically indexes default memory files (MEMORY.md and memory/**/*.md) into QMD collections. Keep enabled unless you want indexing controlled only through explicit custom paths.", "hasChildren": false @@ -38431,7 +41606,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Max Injected Chars", "help": "Caps how much QMD text can be injected into one turn across all hits. Use lower values to control prompt bloat and latency; raise only when context is consistently truncated.", "hasChildren": false @@ -38443,7 +41621,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Max Results", "help": "Limits how many QMD hits are returned into the agent loop for each recall request (default: 6). Increase for broader recall context, or lower to keep prompts tighter and faster.", "hasChildren": false @@ -38455,7 +41636,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Max Snippet Chars", "help": "Caps per-result snippet length extracted from QMD hits in characters (default: 700). Lower this when prompts bloat quickly, and raise only if answers consistently miss key details.", "hasChildren": false @@ -38467,7 +41651,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Search Timeout (ms)", "help": "Sets per-query QMD search timeout in milliseconds (default: 4000). Increase for larger indexes or slower environments, and lower to keep request latency bounded.", "hasChildren": false @@ -38479,7 +41666,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD MCPorter", "help": "Routes QMD work through mcporter (MCP runtime) instead of spawning `qmd` for each call. Use this when cold starts are expensive on large models; keep direct process mode for simpler local setups.", "hasChildren": true @@ -38491,7 +41680,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD MCPorter Enabled", "help": "Routes QMD through an mcporter daemon instead of spawning qmd per request, reducing cold-start overhead for larger models. Keep disabled unless mcporter is installed and configured.", "hasChildren": false @@ -38503,7 +41694,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD MCPorter Server Name", "help": "Names the mcporter server target used for QMD calls (default: qmd). Change only when your mcporter setup uses a custom server name for qmd mcp keep-alive.", "hasChildren": false @@ -38515,7 +41708,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD MCPorter Start Daemon", "help": "Automatically starts the mcporter daemon when mcporter-backed QMD mode is enabled (default: true). Keep enabled unless process lifecycle is managed externally by your service supervisor.", "hasChildren": false @@ -38527,7 +41722,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Extra Paths", "help": "Adds custom directories or files to include in QMD indexing, each with an optional name and glob pattern. Use this for project-specific knowledge locations that are outside default memory paths.", "hasChildren": true @@ -38579,7 +41776,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Surface Scope", "help": "Defines which sessions/channels are eligible for QMD recall using session.sendPolicy-style rules. Keep default direct-only scope unless you intentionally want cross-chat memory sharing.", "hasChildren": true @@ -38681,7 +41880,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Search Mode", "help": "Selects the QMD retrieval path: \"query\" uses standard query flow, \"search\" uses search-oriented retrieval, and \"vsearch\" emphasizes vector retrieval. Keep default unless tuning relevance quality.", "hasChildren": false @@ -38703,7 +41904,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Session Indexing", "help": "Indexes session transcripts into QMD so recall can include prior conversation content (experimental, default: false). Enable only when transcript memory is required and you accept larger index churn.", "hasChildren": false @@ -38715,7 +41918,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Session Export Directory", "help": "Overrides where sanitized session exports are written before QMD indexing. Use this when default state storage is constrained or when exports must land on a managed volume.", "hasChildren": false @@ -38727,7 +41932,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Session Retention (days)", "help": "Defines how long exported session files are kept before automatic pruning, in days (default: unlimited). Set a finite value for storage hygiene or compliance retention policies.", "hasChildren": false @@ -38749,7 +41956,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Command Timeout (ms)", "help": "Sets timeout for QMD maintenance commands such as collection list/add in milliseconds (default: 30000). Increase when running on slower disks or remote filesystems that delay command completion.", "hasChildren": false @@ -38761,7 +41971,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Update Debounce (ms)", "help": "Sets the minimum delay between consecutive QMD refresh attempts in milliseconds (default: 15000). Increase this if frequent file changes cause update thrash or unnecessary background load.", "hasChildren": false @@ -38773,7 +41986,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Embed Interval", "help": "Sets how often QMD recomputes embeddings (duration string, default: 60m; set 0 to disable periodic embeds). Lower intervals improve freshness but increase embedding workload and cost.", "hasChildren": false @@ -38785,7 +42001,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Embed Timeout (ms)", "help": "Sets maximum runtime for each `qmd embed` cycle in milliseconds (default: 120000). Increase for heavier embedding workloads or slower hardware, and lower to fail fast under tight SLAs.", "hasChildren": false @@ -38797,7 +42016,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Update Interval", "help": "Sets how often QMD refreshes indexes from source content (duration string, default: 5m). Shorter intervals improve freshness but increase background CPU and I/O.", "hasChildren": false @@ -38809,7 +42031,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Update on Startup", "help": "Runs an initial QMD update once during gateway startup (default: true). Keep enabled so recall starts from a fresh baseline; disable only when startup speed is more important than immediate freshness.", "hasChildren": false @@ -38821,7 +42045,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "QMD Update Timeout (ms)", "help": "Sets maximum runtime for each `qmd update` cycle in milliseconds (default: 120000). Raise this for larger collections; lower it when you want quicker failure detection in automation.", "hasChildren": false @@ -38833,7 +42060,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "QMD Wait for Boot Sync", "help": "Blocks startup completion until the initial boot-time QMD sync finishes (default: false). Enable when you need fully up-to-date recall before serving traffic, and keep off for faster boot.", "hasChildren": false @@ -38845,7 +42074,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Messages", "help": "Message formatting, acknowledgment, queueing, debounce, and status reaction behavior for inbound/outbound chat flows. Use this section when channel responsiveness or message UX needs adjustment.", "hasChildren": true @@ -38857,7 +42088,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Ack Reaction Emoji", "help": "Emoji reaction used to acknowledge inbound messages (empty disables).", "hasChildren": false @@ -38867,10 +42100,19 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["group-mentions", "group-all", "direct", "all", "off", "none"], + "enumValues": [ + "group-mentions", + "group-all", + "direct", + "all", + "off", + "none" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Ack Reaction Scope", "help": "When to send ack reactions (\"group-mentions\", \"group-all\", \"direct\", \"all\", \"off\", \"none\"). \"off\"/\"none\" disables ack reactions entirely.", "hasChildren": false @@ -38882,7 +42124,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Group Chat Rules", "help": "Group-message handling controls including mention triggers and history window sizing. Keep mention patterns narrow so group channels do not trigger on every message.", "hasChildren": true @@ -38894,7 +42138,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Group History Limit", "help": "Maximum number of prior group messages loaded as context per turn for group sessions. Use higher values for richer continuity, or lower values for faster and cheaper responses.", "hasChildren": false @@ -38906,7 +42152,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Group Mention Patterns", "help": "Safe case-insensitive regex patterns used to detect explicit mentions/trigger phrases in group chats. Use precise patterns to reduce false positives in high-volume channels; invalid or unsafe nested-repetition patterns are ignored.", "hasChildren": true @@ -38928,7 +42176,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Inbound Debounce", "help": "Direct inbound debounce settings used before queue/turn processing starts. Configure this for provider-specific rapid message bursts from the same sender.", "hasChildren": true @@ -38940,7 +42190,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Inbound Debounce by Channel (ms)", "help": "Per-channel inbound debounce overrides keyed by provider id in milliseconds. Use this where some providers send message fragments more aggressively than others.", "hasChildren": true @@ -38962,7 +42214,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Inbound Message Debounce (ms)", "help": "Debounce window (ms) for batching rapid inbound messages from the same sender (0 to disable).", "hasChildren": false @@ -38974,7 +42228,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Inbound Message Prefix", "help": "Prefix text prepended to inbound user messages before they are handed to the agent runtime. Use this sparingly for channel context markers and keep it stable across sessions.", "hasChildren": false @@ -38986,7 +42242,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Inbound Queue", "help": "Inbound message queue strategy used to buffer bursts before processing turns. Tune this for busy channels where sequential processing or batching behavior matters.", "hasChildren": true @@ -38998,7 +42256,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Queue Mode by Channel", "help": "Per-channel queue mode overrides keyed by provider id (for example telegram, discord, slack). Use this when one channel’s traffic pattern needs different queue behavior than global defaults.", "hasChildren": true @@ -39110,7 +42370,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Queue Capacity", "help": "Maximum number of queued inbound items retained before drop policy applies. Keep caps bounded in noisy channels so memory usage remains predictable.", "hasChildren": false @@ -39122,7 +42384,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Queue Debounce (ms)", "help": "Global queue debounce window in milliseconds before processing buffered inbound messages. Use higher values to coalesce rapid bursts, or lower values for reduced response latency.", "hasChildren": false @@ -39134,7 +42398,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Queue Debounce by Channel (ms)", "help": "Per-channel debounce overrides for queue behavior keyed by provider id. Use this to tune burst handling independently for chat surfaces with different pacing.", "hasChildren": true @@ -39156,7 +42422,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Queue Drop Strategy", "help": "Drop strategy when queue cap is exceeded: \"old\", \"new\", or \"summarize\". Use summarize when preserving intent matters, or old/new when deterministic dropping is preferred.", "hasChildren": false @@ -39168,7 +42436,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Queue Mode", "help": "Queue behavior mode: \"steer\", \"followup\", \"collect\", \"steer-backlog\", \"steer+backlog\", \"queue\", or \"interrupt\". Keep conservative modes unless you intentionally need aggressive interruption/backlog semantics.", "hasChildren": false @@ -39180,7 +42450,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Remove Ack Reaction After Reply", "help": "Removes the acknowledgment reaction after final reply delivery when enabled. Keep enabled for cleaner UX in channels where persistent ack reactions create clutter.", "hasChildren": false @@ -39192,7 +42464,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Outbound Response Prefix", "help": "Prefix text prepended to outbound assistant replies before sending to channels. Use for lightweight branding/context tags and avoid long prefixes that reduce content density.", "hasChildren": false @@ -39204,7 +42478,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Status Reactions", "help": "Lifecycle status reactions that update the emoji on the trigger message as the agent progresses (queued → thinking → tool → done/error).", "hasChildren": true @@ -39216,7 +42492,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Status Reaction Emojis", "help": "Override default status reaction emojis. Keys: thinking, compacting, tool, coding, web, done, error, stallSoft, stallHard. Must be valid Telegram reaction emojis.", "hasChildren": true @@ -39318,7 +42596,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Status Reactions", "help": "Enable lifecycle status reactions for Telegram. When enabled, the ack reaction becomes the initial 'queued' state and progresses through thinking, tool, done/error automatically. Default: false.", "hasChildren": false @@ -39330,7 +42610,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Status Reaction Timing", "help": "Override default timing. Keys: debounceMs (700), stallSoftMs (25000), stallHardMs (60000), doneHoldMs (1500), errorHoldMs (2500).", "hasChildren": true @@ -39392,7 +42674,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Suppress Tool Error Warnings", "help": "When true, suppress ⚠️ tool-error warnings from being shown to the user. The agent already sees errors in context and can retry. Default: false.", "hasChildren": false @@ -39404,7 +42688,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Message Text-to-Speech", "help": "Text-to-speech policy for reading agent replies aloud on supported voice or audio surfaces. Keep disabled unless voice playback is part of your operator/user workflow.", "hasChildren": true @@ -39414,7 +42700,12 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["off", "always", "inbound", "tagged"], + "enumValues": [ + "off", + "always", + "inbound", + "tagged" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -39543,11 +42834,18 @@ { "path": "messages.tts.elevenlabs.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "media", "security"], + "tags": [ + "auth", + "media", + "security" + ], "hasChildren": true }, { @@ -39585,7 +42883,11 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["auto", "on", "off"], + "enumValues": [ + "auto", + "on", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -39726,7 +43028,10 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["final", "all"], + "enumValues": [ + "final", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -39835,11 +43140,18 @@ { "path": "messages.tts.openai.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "media", "security"], + "tags": [ + "auth", + "media", + "security" + ], "hasChildren": true }, { @@ -39937,7 +43249,11 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["elevenlabs", "openai", "edge"], + "enumValues": [ + "elevenlabs", + "openai", + "edge" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -39970,7 +43286,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Metadata", "help": "Metadata fields automatically maintained by OpenClaw to record write/version history for this config file. Keep these values system-managed and avoid manual edits unless debugging migration history.", "hasChildren": true @@ -39982,7 +43300,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Config Last Touched At", "help": "ISO timestamp of the last config write (auto-set).", "hasChildren": false @@ -39994,7 +43314,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Config Last Touched Version", "help": "Auto-set when OpenClaw writes the config.", "hasChildren": false @@ -40006,7 +43328,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Models", "help": "Model catalog root for provider definitions, merge/replace behavior, and optional Bedrock discovery integration. Keep provider definitions explicit and validated before relying on production failover paths.", "hasChildren": true @@ -40018,7 +43342,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Bedrock Model Discovery", "help": "Automatic AWS Bedrock model discovery settings used to synthesize provider model entries from account visibility. Keep discovery scoped and refresh intervals conservative to reduce API churn.", "hasChildren": true @@ -40030,7 +43356,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Bedrock Default Context Window", "help": "Fallback context-window value applied to discovered models when provider metadata lacks explicit limits. Use realistic defaults to avoid oversized prompts that exceed true provider constraints.", "hasChildren": false @@ -40042,7 +43370,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "models", "performance", "security"], + "tags": [ + "auth", + "models", + "performance", + "security" + ], "label": "Bedrock Default Max Tokens", "help": "Fallback max-token value applied to discovered models without explicit output token limits. Use conservative defaults to reduce truncation surprises and unexpected token spend.", "hasChildren": false @@ -40054,7 +43387,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Bedrock Discovery Enabled", "help": "Enables periodic Bedrock model discovery and catalog refresh for Bedrock-backed providers. Keep disabled unless Bedrock is actively used and IAM permissions are correctly configured.", "hasChildren": false @@ -40066,7 +43401,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Bedrock Discovery Provider Filter", "help": "Optional provider allowlist filter for Bedrock discovery so only selected providers are refreshed. Use this to limit discovery scope in multi-provider environments.", "hasChildren": true @@ -40088,7 +43425,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "performance"], + "tags": [ + "models", + "performance" + ], "label": "Bedrock Discovery Refresh Interval (s)", "help": "Refresh cadence for Bedrock discovery polling in seconds to detect newly available models over time. Use longer intervals in production to reduce API cost and control-plane noise.", "hasChildren": false @@ -40100,7 +43440,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Bedrock Discovery Region", "help": "AWS region used for Bedrock discovery calls when discovery is enabled for your deployment. Use the region where your Bedrock models are provisioned to avoid empty discovery results.", "hasChildren": false @@ -40112,7 +43454,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Catalog Mode", "help": "Controls provider catalog behavior: \"merge\" keeps built-ins and overlays your custom providers, while \"replace\" uses only your configured providers. In \"merge\", matching provider IDs preserve non-empty agent models.json baseUrl values, while apiKey values are preserved only when the provider is not SecretRef-managed in current config/auth-profile context; SecretRef-managed providers refresh apiKey from current source markers, and matching model contextWindow/maxTokens use the higher value between explicit and implicit entries.", "hasChildren": false @@ -40124,7 +43468,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Providers", "help": "Provider map keyed by provider ID containing connection/auth settings and concrete model definitions. Use stable provider keys so references from agents and tooling remain portable across environments.", "hasChildren": true @@ -40156,7 +43502,9 @@ ], "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider API Adapter", "help": "Provider API adapter selection controlling request/response compatibility handling for model calls. Use the adapter that matches your upstream provider protocol to avoid feature mismatch.", "hasChildren": false @@ -40164,11 +43512,18 @@ { "path": "models.providers.*.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "models", "security"], + "tags": [ + "auth", + "models", + "security" + ], "label": "Model Provider API Key", "help": "Provider credential used for API-key based authentication when the provider requires direct key auth. Use secret/env substitution and avoid storing real keys in committed config files.", "hasChildren": true @@ -40210,7 +43565,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Auth Mode", "help": "Selects provider auth style: \"api-key\" for API key auth, \"token\" for bearer token auth, \"oauth\" for OAuth credentials, and \"aws-sdk\" for AWS credential resolution. Match this to your provider requirements.", "hasChildren": false @@ -40222,7 +43579,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Authorization Header", "help": "When true, credentials are sent via the HTTP Authorization header even if alternate auth is possible. Use this only when your provider or proxy explicitly requires Authorization forwarding.", "hasChildren": false @@ -40234,7 +43593,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Base URL", "help": "Base URL for the provider endpoint used to serve model requests for that provider entry. Use HTTPS endpoints and keep URLs environment-specific through config templating where needed.", "hasChildren": false @@ -40246,7 +43607,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Headers", "help": "Static HTTP headers merged into provider requests for tenant routing, proxy auth, or custom gateway requirements. Use this sparingly and keep sensitive header values in secrets.", "hasChildren": true @@ -40254,11 +43617,17 @@ { "path": "models.providers.*.headers.*", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["models", "security"], + "tags": [ + "models", + "security" + ], "hasChildren": true }, { @@ -40298,7 +43667,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Inject num_ctx (OpenAI Compat)", "help": "Controls whether OpenClaw injects `options.num_ctx` for Ollama providers configured with the OpenAI-compatible adapter (`openai-completions`). Default is true. Set false only if your proxy/upstream rejects unknown `options` payload fields.", "hasChildren": false @@ -40310,7 +43681,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["models"], + "tags": [ + "models" + ], "label": "Model Provider Model List", "help": "Declared model list for a provider including identifiers, metadata, and optional compatibility/cost hints. Keep IDs exact to provider catalog values so selection and fallback resolve correctly.", "hasChildren": true @@ -40632,7 +44005,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Node Host", "help": "Node host controls for features exposed from this gateway node to other nodes or clients. Keep defaults unless you intentionally proxy local capabilities across your node network.", "hasChildren": true @@ -40644,7 +44019,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Node Browser Proxy", "help": "Groups browser-proxy settings for exposing local browser control through node routing. Enable only when remote node workflows need your local browser profiles.", "hasChildren": true @@ -40656,7 +44033,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "network", "storage"], + "tags": [ + "access", + "network", + "storage" + ], "label": "Node Browser Proxy Allowed Profiles", "help": "Optional allowlist of browser profile names exposed through node proxy routing. Leave empty to expose all configured profiles, or use a tight list to enforce least-privilege profile access.", "hasChildren": true @@ -40678,7 +44059,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["network"], + "tags": [ + "network" + ], "label": "Node Browser Proxy Enabled", "help": "Expose the local browser control server through node proxy routing so remote clients can use this host's browser capabilities. Keep disabled unless remote automation explicitly depends on it.", "hasChildren": false @@ -40690,7 +44073,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugins", "help": "Plugin system controls for enabling extensions, constraining load scope, configuring entries, and tracking installs. Keep plugin policy explicit and least-privilege in production environments.", "hasChildren": true @@ -40702,7 +44087,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Plugin Allowlist", "help": "Optional allowlist of plugin IDs; when set, only listed plugins are eligible to load. Use this to enforce approved extension inventories in controlled environments.", "hasChildren": true @@ -40724,7 +44111,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Plugin Denylist", "help": "Optional denylist of plugin IDs that are blocked even if allowlists or paths include them. Use deny rules for emergency rollback and hard blocks on risky plugins.", "hasChildren": true @@ -40746,7 +44135,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Plugins", "help": "Enable or disable plugin/extension loading globally during startup and config reload (default: true). Keep enabled only when extension capabilities are required by your deployment.", "hasChildren": false @@ -40758,7 +44149,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Entries", "help": "Per-plugin settings keyed by plugin ID including enablement and plugin-specific runtime configuration payloads. Use this for scoped plugin tuning without changing global loader policy.", "hasChildren": true @@ -40780,7 +44173,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Config", "help": "Plugin-defined configuration payload interpreted by that plugin's own schema and validation rules. Use only documented fields from the plugin to prevent ignored or invalid settings.", "hasChildren": true @@ -40801,7 +44196,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Enabled", "help": "Per-plugin enablement override for a specific entry, applied on top of global plugin policy (restart required). Use this to stage plugin rollout gradually across environments.", "hasChildren": false @@ -40813,7 +44210,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -40825,7 +44224,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -40837,7 +44238,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACPX Runtime", "help": "ACP runtime backend powered by acpx with configurable command path and version policy. (plugin: acpx)", "hasChildren": true @@ -40849,7 +44252,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ACPX Runtime Config", "help": "Plugin-defined config payload for acpx.", "hasChildren": true @@ -40861,7 +44266,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "acpx Command", "help": "Optional path/command override for acpx (for example /home/user/repos/acpx/dist/cli.js). Leave unset to use plugin-local bundled acpx.", "hasChildren": false @@ -40873,7 +44280,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Working Directory", "help": "Default cwd for ACP session operations when not set per session.", "hasChildren": false @@ -40885,7 +44294,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Expected acpx Version", "help": "Exact version to enforce (for example 0.1.16) or \"any\" to skip strict version matching.", "hasChildren": false @@ -40897,7 +44308,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "MCP Servers", "help": "Named MCP server definitions to inject into ACPX-backed session bootstrap. Each entry needs a command and can include args and env.", "hasChildren": true @@ -40967,10 +44380,15 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["deny", "fail"], + "enumValues": [ + "deny", + "fail" + ], "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Non-Interactive Permission Policy", "help": "acpx policy when interactive permission prompts are unavailable.", "hasChildren": false @@ -40980,10 +44398,16 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["approve-all", "approve-reads", "deny-all"], + "enumValues": [ + "approve-all", + "approve-reads", + "deny-all" + ], "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Permission Mode", "help": "Default acpx permission policy for runtime prompts.", "hasChildren": false @@ -40995,7 +44419,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced"], + "tags": [ + "access", + "advanced" + ], "label": "Queue Owner TTL Seconds", "help": "Idle queue-owner TTL for acpx prompt turns. Keep this short in OpenClaw to avoid delayed completion after each turn.", "hasChildren": false @@ -41007,7 +44434,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Strict Windows cmd Wrapper", "help": "Enabled by default. On Windows, reject unresolved .cmd/.bat wrappers instead of shell fallback. Disable only for compatibility with non-standard wrappers.", "hasChildren": false @@ -41019,7 +44448,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "performance"], + "tags": [ + "advanced", + "performance" + ], "label": "Prompt Timeout Seconds", "help": "Optional acpx timeout for each runtime turn.", "hasChildren": false @@ -41031,7 +44463,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable ACPX Runtime", "hasChildren": false }, @@ -41042,7 +44476,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41054,7 +44490,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41066,7 +44504,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/bluebubbles", "help": "OpenClaw BlueBubbles channel plugin (plugin: bluebubbles)", "hasChildren": true @@ -41078,7 +44518,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/bluebubbles Config", "help": "Plugin-defined config payload for bluebubbles.", "hasChildren": false @@ -41090,7 +44532,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/bluebubbles", "hasChildren": false }, @@ -41101,7 +44545,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41113,7 +44559,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41125,7 +44573,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/copilot-proxy", "help": "OpenClaw Copilot Proxy provider plugin (plugin: copilot-proxy)", "hasChildren": true @@ -41137,7 +44587,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/copilot-proxy Config", "help": "Plugin-defined config payload for copilot-proxy.", "hasChildren": false @@ -41149,7 +44601,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/copilot-proxy", "hasChildren": false }, @@ -41160,7 +44614,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41172,7 +44628,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41184,7 +44642,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Device Pairing", "help": "Generate setup codes and approve device pairing requests. (plugin: device-pair)", "hasChildren": true @@ -41196,7 +44656,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Device Pairing Config", "help": "Plugin-defined config payload for device-pair.", "hasChildren": true @@ -41208,7 +44670,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Gateway URL", "help": "Public WebSocket URL used for /pair setup codes (ws/wss or http/https).", "hasChildren": false @@ -41220,7 +44684,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Device Pairing", "hasChildren": false }, @@ -41231,7 +44697,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41243,7 +44711,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41255,7 +44725,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "@openclaw/diagnostics-otel", "help": "OpenClaw diagnostics OpenTelemetry exporter (plugin: diagnostics-otel)", "hasChildren": true @@ -41267,7 +44739,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "@openclaw/diagnostics-otel Config", "help": "Plugin-defined config payload for diagnostics-otel.", "hasChildren": false @@ -41279,7 +44753,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["observability"], + "tags": [ + "observability" + ], "label": "Enable @openclaw/diagnostics-otel", "hasChildren": false }, @@ -41290,7 +44766,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41302,7 +44780,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41314,7 +44794,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Diffs", "help": "Read-only diff viewer and file renderer for agents. (plugin: diffs)", "hasChildren": true @@ -41326,7 +44808,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Diffs Config", "help": "Plugin-defined config payload for diffs.", "hasChildren": true @@ -41349,7 +44833,9 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Background Highlights", "help": "Show added/removed background highlights by default.", "hasChildren": false @@ -41359,11 +44845,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["bars", "classic", "none"], + "enumValues": [ + "bars", + "classic", + "none" + ], "defaultValue": "bars", "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Diff Indicator Style", "help": "Choose added/removed indicators style.", "hasChildren": false @@ -41373,11 +44865,16 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["png", "pdf"], + "enumValues": [ + "png", + "pdf" + ], "defaultValue": "png", "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Default File Format", "help": "Rendered file format for file mode (PNG or PDF).", "hasChildren": false @@ -41390,7 +44887,10 @@ "defaultValue": 960, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Default File Max Width", "help": "Maximum file render width in CSS pixels.", "hasChildren": false @@ -41400,11 +44900,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["standard", "hq", "print"], + "enumValues": [ + "standard", + "hq", + "print" + ], "defaultValue": "standard", "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Default File Quality", "help": "Quality preset for PNG/PDF rendering.", "hasChildren": false @@ -41417,7 +44923,9 @@ "defaultValue": 2, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Default File Scale", "help": "Device scale factor used while rendering file artifacts.", "hasChildren": false @@ -41430,7 +44938,9 @@ "defaultValue": "Fira Code", "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Font", "help": "Preferred font family name for diff content and headers.", "hasChildren": false @@ -41443,7 +44953,9 @@ "defaultValue": 15, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Font Size", "help": "Base diff font size in pixels.", "hasChildren": false @@ -41453,7 +44965,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["png", "pdf"], + "enumValues": [ + "png", + "pdf" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -41464,7 +44979,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["png", "pdf"], + "enumValues": [ + "png", + "pdf" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -41485,7 +45003,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["standard", "hq", "print"], + "enumValues": [ + "standard", + "hq", + "print" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -41506,11 +45028,16 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["unified", "split"], + "enumValues": [ + "unified", + "split" + ], "defaultValue": "unified", "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Layout", "help": "Initial diff layout shown in the viewer.", "hasChildren": false @@ -41523,7 +45050,9 @@ "defaultValue": 1.6, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Line Spacing", "help": "Line-height multiplier applied to diff rows.", "hasChildren": false @@ -41533,11 +45062,18 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["view", "image", "file", "both"], + "enumValues": [ + "view", + "image", + "file", + "both" + ], "defaultValue": "both", "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Output Mode", "help": "Tool default when mode is omitted. Use view for canvas/gateway viewer, file for PNG/PDF, or both.", "hasChildren": false @@ -41550,7 +45086,9 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Show Line Numbers", "help": "Show line numbers by default.", "hasChildren": false @@ -41560,11 +45098,16 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["light", "dark"], + "enumValues": [ + "light", + "dark" + ], "defaultValue": "dark", "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Theme", "help": "Initial viewer theme.", "hasChildren": false @@ -41577,7 +45120,9 @@ "defaultValue": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Word Wrap", "help": "Wrap long lines by default.", "hasChildren": false @@ -41600,7 +45145,9 @@ "defaultValue": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Remote Viewer", "help": "Allow non-loopback access to diff viewer URLs when the token path is known.", "hasChildren": false @@ -41612,7 +45159,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Diffs", "hasChildren": false }, @@ -41623,7 +45172,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41635,7 +45186,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41647,7 +45200,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/discord", "help": "OpenClaw Discord channel plugin (plugin: discord)", "hasChildren": true @@ -41659,7 +45214,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/discord Config", "help": "Plugin-defined config payload for discord.", "hasChildren": false @@ -41671,7 +45228,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/discord", "hasChildren": false }, @@ -41682,7 +45241,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41694,7 +45255,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41706,7 +45269,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/feishu", "help": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng) (plugin: feishu)", "hasChildren": true @@ -41718,7 +45283,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/feishu Config", "help": "Plugin-defined config payload for feishu.", "hasChildren": false @@ -41730,7 +45297,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/feishu", "hasChildren": false }, @@ -41741,7 +45310,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41753,7 +45324,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41765,7 +45338,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/google-gemini-cli-auth", "help": "OpenClaw Gemini CLI OAuth provider plugin (plugin: google-gemini-cli-auth)", "hasChildren": true @@ -41777,7 +45352,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/google-gemini-cli-auth Config", "help": "Plugin-defined config payload for google-gemini-cli-auth.", "hasChildren": false @@ -41789,7 +45366,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/google-gemini-cli-auth", "hasChildren": false }, @@ -41800,7 +45379,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41812,7 +45393,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41824,7 +45407,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/googlechat", "help": "OpenClaw Google Chat channel plugin (plugin: googlechat)", "hasChildren": true @@ -41836,7 +45421,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/googlechat Config", "help": "Plugin-defined config payload for googlechat.", "hasChildren": false @@ -41848,7 +45435,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/googlechat", "hasChildren": false }, @@ -41859,7 +45448,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41871,7 +45462,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41883,7 +45476,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/imessage", "help": "OpenClaw iMessage channel plugin (plugin: imessage)", "hasChildren": true @@ -41895,7 +45490,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/imessage Config", "help": "Plugin-defined config payload for imessage.", "hasChildren": false @@ -41907,7 +45504,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/imessage", "hasChildren": false }, @@ -41918,7 +45517,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41930,7 +45531,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -41942,7 +45545,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/irc", "help": "OpenClaw IRC channel plugin (plugin: irc)", "hasChildren": true @@ -41954,7 +45559,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/irc Config", "help": "Plugin-defined config payload for irc.", "hasChildren": false @@ -41966,7 +45573,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/irc", "hasChildren": false }, @@ -41977,7 +45586,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -41989,7 +45600,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42001,7 +45614,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/line", "help": "OpenClaw LINE channel plugin (plugin: line)", "hasChildren": true @@ -42013,7 +45628,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/line Config", "help": "Plugin-defined config payload for line.", "hasChildren": false @@ -42025,7 +45642,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/line", "hasChildren": false }, @@ -42036,7 +45655,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42048,7 +45669,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42060,7 +45683,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "LLM Task", "help": "Generic JSON-only LLM tool for structured tasks callable from workflows. (plugin: llm-task)", "hasChildren": true @@ -42072,7 +45697,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "LLM Task Config", "help": "Plugin-defined config payload for llm-task.", "hasChildren": true @@ -42154,7 +45781,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable LLM Task", "hasChildren": false }, @@ -42165,7 +45794,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42177,7 +45808,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42189,7 +45822,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Lobster", "help": "Typed workflow tool with resumable approvals. (plugin: lobster)", "hasChildren": true @@ -42201,7 +45836,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Lobster Config", "help": "Plugin-defined config payload for lobster.", "hasChildren": false @@ -42213,7 +45850,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Lobster", "hasChildren": false }, @@ -42224,7 +45863,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42236,7 +45877,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42248,7 +45891,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/matrix", "help": "OpenClaw Matrix channel plugin (plugin: matrix)", "hasChildren": true @@ -42260,7 +45905,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/matrix Config", "help": "Plugin-defined config payload for matrix.", "hasChildren": false @@ -42272,7 +45919,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/matrix", "hasChildren": false }, @@ -42283,7 +45932,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42295,7 +45946,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42307,7 +45960,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/mattermost", "help": "OpenClaw Mattermost channel plugin (plugin: mattermost)", "hasChildren": true @@ -42319,7 +45974,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/mattermost Config", "help": "Plugin-defined config payload for mattermost.", "hasChildren": false @@ -42331,7 +45988,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/mattermost", "hasChildren": false }, @@ -42342,7 +46001,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42354,7 +46015,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42366,7 +46029,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/memory-core", "help": "OpenClaw core memory search plugin (plugin: memory-core)", "hasChildren": true @@ -42378,7 +46043,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/memory-core Config", "help": "Plugin-defined config payload for memory-core.", "hasChildren": false @@ -42390,7 +46057,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/memory-core", "hasChildren": false }, @@ -42401,7 +46070,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42413,7 +46084,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42425,7 +46098,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "@openclaw/memory-lancedb", "help": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture (plugin: memory-lancedb)", "hasChildren": true @@ -42437,7 +46112,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "@openclaw/memory-lancedb Config", "help": "Plugin-defined config payload for memory-lancedb.", "hasChildren": true @@ -42449,7 +46126,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Auto-Capture", "help": "Automatically capture important information from conversations", "hasChildren": false @@ -42461,7 +46140,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Auto-Recall", "help": "Automatically inject relevant memories into context", "hasChildren": false @@ -42473,7 +46154,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "performance", "storage"], + "tags": [ + "advanced", + "performance", + "storage" + ], "label": "Capture Max Chars", "help": "Maximum message length eligible for auto-capture", "hasChildren": false @@ -42485,7 +46170,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Database Path", "hasChildren": false }, @@ -42506,7 +46194,11 @@ "required": true, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "storage"], + "tags": [ + "auth", + "security", + "storage" + ], "label": "OpenAI API Key", "help": "API key for OpenAI embeddings (or use ${OPENAI_API_KEY})", "hasChildren": false @@ -42518,7 +46210,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Base URL", "help": "Base URL for compatible providers (e.g. http://localhost:11434/v1)", "hasChildren": false @@ -42530,7 +46225,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Dimensions", "help": "Vector dimensions for custom models (required for non-standard models)", "hasChildren": false @@ -42542,7 +46240,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "storage"], + "tags": [ + "models", + "storage" + ], "label": "Embedding Model", "help": "OpenAI embedding model to use", "hasChildren": false @@ -42554,7 +46255,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Enable @openclaw/memory-lancedb", "hasChildren": false }, @@ -42565,7 +46268,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42577,7 +46282,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42589,7 +46296,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "@openclaw/minimax-portal-auth", "help": "OpenClaw MiniMax Portal OAuth provider plugin (plugin: minimax-portal-auth)", "hasChildren": true @@ -42601,7 +46310,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "@openclaw/minimax-portal-auth Config", "help": "Plugin-defined config payload for minimax-portal-auth.", "hasChildren": false @@ -42613,7 +46324,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Enable @openclaw/minimax-portal-auth", "hasChildren": false }, @@ -42624,7 +46337,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42636,7 +46351,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42648,7 +46365,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/msteams", "help": "OpenClaw Microsoft Teams channel plugin (plugin: msteams)", "hasChildren": true @@ -42660,7 +46379,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/msteams Config", "help": "Plugin-defined config payload for msteams.", "hasChildren": false @@ -42672,7 +46393,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/msteams", "hasChildren": false }, @@ -42683,7 +46406,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42695,7 +46420,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42707,7 +46434,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/nextcloud-talk", "help": "OpenClaw Nextcloud Talk channel plugin (plugin: nextcloud-talk)", "hasChildren": true @@ -42719,7 +46448,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/nextcloud-talk Config", "help": "Plugin-defined config payload for nextcloud-talk.", "hasChildren": false @@ -42731,7 +46462,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/nextcloud-talk", "hasChildren": false }, @@ -42742,7 +46475,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42754,7 +46489,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42766,7 +46503,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/nostr", "help": "OpenClaw Nostr channel plugin for NIP-04 encrypted DMs (plugin: nostr)", "hasChildren": true @@ -42778,7 +46517,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/nostr Config", "help": "Plugin-defined config payload for nostr.", "hasChildren": false @@ -42790,7 +46531,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/nostr", "hasChildren": false }, @@ -42801,7 +46544,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42813,7 +46558,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42825,7 +46572,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/ollama-provider", "help": "OpenClaw Ollama provider plugin (plugin: ollama)", "hasChildren": true @@ -42837,7 +46586,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/ollama-provider Config", "help": "Plugin-defined config payload for ollama.", "hasChildren": false @@ -42849,7 +46600,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/ollama-provider", "hasChildren": false }, @@ -42860,7 +46613,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42872,7 +46627,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42884,7 +46641,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "OpenProse", "help": "OpenProse VM skill pack with a /prose slash command. (plugin: open-prose)", "hasChildren": true @@ -42896,7 +46655,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "OpenProse Config", "help": "Plugin-defined config payload for open-prose.", "hasChildren": false @@ -42908,7 +46669,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable OpenProse", "hasChildren": false }, @@ -42919,7 +46682,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42931,7 +46696,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -42943,7 +46710,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Phone Control", "help": "Arm/disarm high-risk phone node commands (camera/screen/writes) with an optional auto-expiry. (plugin: phone-control)", "hasChildren": true @@ -42955,7 +46724,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Phone Control Config", "help": "Plugin-defined config payload for phone-control.", "hasChildren": false @@ -42967,7 +46738,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Phone Control", "hasChildren": false }, @@ -42978,7 +46751,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -42990,7 +46765,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43002,7 +46779,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "qwen-portal-auth", "help": "Plugin entry for qwen-portal-auth.", "hasChildren": true @@ -43014,7 +46793,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "qwen-portal-auth Config", "help": "Plugin-defined config payload for qwen-portal-auth.", "hasChildren": false @@ -43026,7 +46807,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable qwen-portal-auth", "hasChildren": false }, @@ -43037,7 +46820,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43049,7 +46834,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43061,7 +46848,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/sglang-provider", "help": "OpenClaw SGLang provider plugin (plugin: sglang)", "hasChildren": true @@ -43073,7 +46862,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/sglang-provider Config", "help": "Plugin-defined config payload for sglang.", "hasChildren": false @@ -43085,7 +46876,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/sglang-provider", "hasChildren": false }, @@ -43096,7 +46889,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43108,7 +46903,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43120,7 +46917,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/signal", "help": "OpenClaw Signal channel plugin (plugin: signal)", "hasChildren": true @@ -43132,7 +46931,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/signal Config", "help": "Plugin-defined config payload for signal.", "hasChildren": false @@ -43144,7 +46945,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/signal", "hasChildren": false }, @@ -43155,7 +46958,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43167,7 +46972,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43179,7 +46986,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/slack", "help": "OpenClaw Slack channel plugin (plugin: slack)", "hasChildren": true @@ -43191,7 +47000,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/slack Config", "help": "Plugin-defined config payload for slack.", "hasChildren": false @@ -43203,7 +47014,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/slack", "hasChildren": false }, @@ -43214,7 +47027,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43226,7 +47041,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43238,7 +47055,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/synology-chat", "help": "Synology Chat channel plugin for OpenClaw (plugin: synology-chat)", "hasChildren": true @@ -43250,7 +47069,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/synology-chat Config", "help": "Plugin-defined config payload for synology-chat.", "hasChildren": false @@ -43262,7 +47083,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/synology-chat", "hasChildren": false }, @@ -43273,7 +47096,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43285,7 +47110,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43297,7 +47124,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Talk Voice", "help": "Manage Talk voice selection (list/set). (plugin: talk-voice)", "hasChildren": true @@ -43309,7 +47138,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Talk Voice Config", "help": "Plugin-defined config payload for talk-voice.", "hasChildren": false @@ -43321,7 +47152,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Talk Voice", "hasChildren": false }, @@ -43332,7 +47165,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43344,7 +47179,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43356,7 +47193,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/telegram", "help": "OpenClaw Telegram channel plugin (plugin: telegram)", "hasChildren": true @@ -43368,7 +47207,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/telegram Config", "help": "Plugin-defined config payload for telegram.", "hasChildren": false @@ -43380,7 +47221,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/telegram", "hasChildren": false }, @@ -43391,7 +47234,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43403,7 +47248,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43415,7 +47262,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Thread Ownership", "help": "Prevents multiple agents from responding in the same Slack thread. Uses HTTP calls to the slack-forwarder ownership API. (plugin: thread-ownership)", "hasChildren": true @@ -43427,7 +47276,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Thread Ownership Config", "help": "Plugin-defined config payload for thread-ownership.", "hasChildren": true @@ -43439,7 +47290,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "A/B Test Channels", "help": "Slack channel IDs where thread ownership is enforced", "hasChildren": true @@ -43461,7 +47314,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Forwarder URL", "help": "Base URL of the slack-forwarder ownership API (default: http://slack-forwarder:8750)", "hasChildren": false @@ -43473,7 +47328,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Enable Thread Ownership", "hasChildren": false }, @@ -43484,7 +47341,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43496,7 +47355,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43508,7 +47369,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/tlon", "help": "OpenClaw Tlon/Urbit channel plugin (plugin: tlon)", "hasChildren": true @@ -43520,7 +47383,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/tlon Config", "help": "Plugin-defined config payload for tlon.", "hasChildren": false @@ -43532,7 +47397,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/tlon", "hasChildren": false }, @@ -43543,7 +47410,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43555,7 +47424,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43567,7 +47438,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/twitch", "help": "OpenClaw Twitch channel plugin (plugin: twitch)", "hasChildren": true @@ -43579,7 +47452,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/twitch Config", "help": "Plugin-defined config payload for twitch.", "hasChildren": false @@ -43591,7 +47466,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/twitch", "hasChildren": false }, @@ -43602,7 +47479,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43614,7 +47493,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43626,7 +47507,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/vllm-provider", "help": "OpenClaw vLLM provider plugin (plugin: vllm)", "hasChildren": true @@ -43638,7 +47521,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/vllm-provider Config", "help": "Plugin-defined config payload for vllm.", "hasChildren": false @@ -43650,7 +47535,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/vllm-provider", "hasChildren": false }, @@ -43661,7 +47548,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -43673,7 +47562,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -43685,7 +47576,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/voice-call", "help": "OpenClaw voice-call plugin (plugin: voice-call)", "hasChildren": true @@ -43697,7 +47590,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/voice-call Config", "help": "Plugin-defined config payload for voice-call.", "hasChildren": true @@ -43709,7 +47604,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Inbound Allowlist", "hasChildren": true }, @@ -43740,7 +47637,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "From Number", "hasChildren": false }, @@ -43751,7 +47650,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Inbound Greeting", "hasChildren": false }, @@ -43760,10 +47661,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["disabled", "allowlist", "pairing", "open"], + "enumValues": [ + "disabled", + "allowlist", + "pairing", + "open" + ], "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Inbound Policy", "hasChildren": false }, @@ -43802,10 +47710,15 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["notify", "conversation"], + "enumValues": [ + "notify", + "conversation" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default Call Mode", "hasChildren": false }, @@ -43816,7 +47729,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Notify Hangup Delay (sec)", "hasChildren": false }, @@ -43855,10 +47770,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["telnyx", "twilio", "plivo", "mock"], + "enumValues": [ + "telnyx", + "twilio", + "plivo", + "mock" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Provider", "help": "Use twilio, telnyx, or mock for dev/no-network.", "hasChildren": false @@ -43870,7 +47792,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Public Webhook URL", "hasChildren": false }, @@ -43881,7 +47805,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Response Model", "hasChildren": false }, @@ -43892,7 +47818,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Response System Prompt", "hasChildren": false }, @@ -43903,7 +47831,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "performance"], + "tags": [ + "advanced", + "performance" + ], "label": "Response Timeout (ms)", "hasChildren": false }, @@ -43934,7 +47865,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Webhook Bind", "hasChildren": false }, @@ -43945,7 +47878,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Webhook Path", "hasChildren": false }, @@ -43956,7 +47891,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Webhook Port", "hasChildren": false }, @@ -43977,7 +47914,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Skip Signature Verification", "hasChildren": false }, @@ -43998,7 +47937,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Call Log Store Path", "hasChildren": false }, @@ -44019,7 +47961,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable Streaming", "hasChildren": false }, @@ -44060,7 +48004,11 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["advanced", "auth", "security"], + "tags": [ + "advanced", + "auth", + "security" + ], "label": "OpenAI Realtime API Key", "hasChildren": false }, @@ -44091,7 +48039,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Media Stream Path", "hasChildren": false }, @@ -44102,7 +48053,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media"], + "tags": [ + "advanced", + "media" + ], "label": "Realtime STT Model", "hasChildren": false }, @@ -44111,7 +48065,9 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["openai-realtime"], + "enumValues": [ + "openai-realtime" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -44152,7 +48108,9 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["openai"], + "enumValues": [ + "openai" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -44173,10 +48131,16 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["off", "serve", "funnel"], + "enumValues": [ + "off", + "serve", + "funnel" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Tailscale Mode", "hasChildren": false }, @@ -44187,7 +48151,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "storage"], + "tags": [ + "advanced", + "storage" + ], "label": "Tailscale Path", "hasChildren": false }, @@ -44208,7 +48175,10 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Telnyx API Key", "hasChildren": false }, @@ -44219,7 +48189,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Telnyx Connection ID", "hasChildren": false }, @@ -44230,7 +48202,9 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["security"], + "tags": [ + "security" + ], "label": "Telnyx Public Key", "hasChildren": false }, @@ -44241,7 +48215,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Default To Number", "hasChildren": false }, @@ -44270,7 +48246,12 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["off", "always", "inbound", "tagged"], + "enumValues": [ + "off", + "always", + "inbound", + "tagged" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -44403,7 +48384,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["advanced", "auth", "media", "security"], + "tags": [ + "advanced", + "auth", + "media", + "security" + ], "label": "ElevenLabs API Key", "hasChildren": false }, @@ -44412,7 +48398,11 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["auto", "on", "off"], + "enumValues": [ + "auto", + "on", + "off" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -44425,7 +48415,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media"], + "tags": [ + "advanced", + "media" + ], "label": "ElevenLabs Base URL", "hasChildren": false }, @@ -44446,7 +48439,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media", "models"], + "tags": [ + "advanced", + "media", + "models" + ], "label": "ElevenLabs Model ID", "hasChildren": false }, @@ -44467,7 +48464,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media"], + "tags": [ + "advanced", + "media" + ], "label": "ElevenLabs Voice ID", "hasChildren": false }, @@ -44556,7 +48556,10 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["final", "all"], + "enumValues": [ + "final", + "all" + ], "deprecated": false, "sensitive": false, "tags": [], @@ -44669,7 +48672,12 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["advanced", "auth", "media", "security"], + "tags": [ + "advanced", + "auth", + "media", + "security" + ], "label": "OpenAI API Key", "hasChildren": false }, @@ -44700,7 +48708,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media", "models"], + "tags": [ + "advanced", + "media", + "models" + ], "label": "OpenAI TTS Model", "hasChildren": false }, @@ -44721,7 +48733,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced", "media"], + "tags": [ + "advanced", + "media" + ], "label": "OpenAI TTS Voice", "hasChildren": false }, @@ -44740,10 +48755,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["openai", "elevenlabs", "edge"], + "enumValues": [ + "openai", + "elevenlabs", + "edge" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced", "media"], + "tags": [ + "advanced", + "media" + ], "label": "TTS Provider Override", "help": "Deep-merges with messages.tts (Edge is ignored for calls).", "hasChildren": false @@ -44785,7 +48807,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced"], + "tags": [ + "access", + "advanced" + ], "label": "Allow ngrok Free Tier (Loopback Bypass)", "hasChildren": false }, @@ -44796,7 +48821,11 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["advanced", "auth", "security"], + "tags": [ + "advanced", + "auth", + "security" + ], "label": "ngrok Auth Token", "hasChildren": false }, @@ -44807,7 +48836,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "ngrok Domain", "hasChildren": false }, @@ -44816,10 +48847,17 @@ "kind": "plugin", "type": "string", "required": false, - "enumValues": ["none", "ngrok", "tailscale-serve", "tailscale-funnel"], + "enumValues": [ + "none", + "ngrok", + "tailscale-serve", + "tailscale-funnel" + ], "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Tunnel Provider", "hasChildren": false }, @@ -44840,7 +48878,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Twilio Account SID", "hasChildren": false }, @@ -44851,7 +48891,10 @@ "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "label": "Twilio Auth Token", "hasChildren": false }, @@ -44922,7 +48965,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/voice-call", "hasChildren": false }, @@ -44933,7 +48978,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -44945,7 +48992,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -44957,7 +49006,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/whatsapp", "help": "OpenClaw WhatsApp channel plugin (plugin: whatsapp)", "hasChildren": true @@ -44969,7 +49020,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/whatsapp Config", "help": "Plugin-defined config payload for whatsapp.", "hasChildren": false @@ -44981,7 +49034,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/whatsapp", "hasChildren": false }, @@ -44992,7 +49047,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45004,7 +49061,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45016,7 +49075,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/zalo", "help": "OpenClaw Zalo channel plugin (plugin: zalo)", "hasChildren": true @@ -45028,7 +49089,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/zalo Config", "help": "Plugin-defined config payload for zalo.", "hasChildren": false @@ -45040,7 +49103,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/zalo", "hasChildren": false }, @@ -45051,7 +49116,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45063,7 +49130,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45075,7 +49144,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/zalouser", "help": "OpenClaw Zalo Personal Account plugin via native zca-js integration (plugin: zalouser)", "hasChildren": true @@ -45087,7 +49158,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "@openclaw/zalouser Config", "help": "Plugin-defined config payload for zalouser.", "hasChildren": false @@ -45099,7 +49172,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Enable @openclaw/zalouser", "hasChildren": false }, @@ -45110,7 +49185,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Hook Policy", "help": "Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.", "hasChildren": true @@ -45122,7 +49199,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access"], + "tags": [ + "access" + ], "label": "Allow Prompt Injection Hooks", "help": "Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.", "hasChildren": false @@ -45134,7 +49213,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Install Records", "help": "CLI-managed install metadata (used by `openclaw plugins update` to locate install sources).", "hasChildren": true @@ -45156,7 +49237,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Install Time", "help": "ISO timestamp of last install/update.", "hasChildren": false @@ -45168,7 +49251,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Plugin Install Path", "help": "Resolved install directory (usually ~/.openclaw/extensions/).", "hasChildren": false @@ -45180,7 +49265,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolved Integrity", "help": "Resolved npm dist integrity hash for the fetched artifact (if reported by npm).", "hasChildren": false @@ -45192,7 +49279,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolution Time", "help": "ISO timestamp when npm package metadata was last resolved for this install record.", "hasChildren": false @@ -45204,7 +49293,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolved Package Name", "help": "Resolved npm package name from the fetched artifact.", "hasChildren": false @@ -45216,7 +49307,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolved Package Spec", "help": "Resolved exact npm spec (@) from the fetched artifact.", "hasChildren": false @@ -45228,7 +49321,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolved Package Version", "help": "Resolved npm package version from the fetched artifact (useful for non-pinned specs).", "hasChildren": false @@ -45240,7 +49335,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Resolved Shasum", "help": "Resolved npm dist shasum for the fetched artifact (if reported by npm).", "hasChildren": false @@ -45252,7 +49349,9 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Install Source", "help": "Install source (\"npm\", \"archive\", or \"path\").", "hasChildren": false @@ -45264,7 +49363,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Plugin Install Source Path", "help": "Original archive/path used for install (if any).", "hasChildren": false @@ -45276,7 +49377,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Install Spec", "help": "Original npm spec used for install (if source is npm).", "hasChildren": false @@ -45288,7 +49391,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Install Version", "help": "Version recorded at install time (if available).", "hasChildren": false @@ -45300,7 +49405,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Loader", "help": "Plugin loader configuration group for specifying filesystem paths where plugins are discovered. Keep load paths explicit and reviewed to avoid accidental untrusted extension loading.", "hasChildren": true @@ -45312,7 +49419,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Plugin Load Paths", "help": "Additional plugin files or directories scanned by the loader beyond built-in defaults. Use dedicated extension directories and avoid broad paths with unrelated executable content.", "hasChildren": true @@ -45334,7 +49443,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Plugin Slots", "help": "Selects which plugins own exclusive runtime slots such as memory so only one plugin provides that capability. Use explicit slot ownership to avoid overlapping providers with conflicting behavior.", "hasChildren": true @@ -45346,7 +49457,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Context Engine Plugin", "help": "Selects the active context engine plugin by id so one plugin provides context orchestration behavior.", "hasChildren": false @@ -45358,7 +49471,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Memory Plugin", "help": "Select the active memory plugin by id, or \"none\" to disable memory plugins.", "hasChildren": false @@ -45690,7 +49805,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session", "help": "Global session routing, reset, delivery policy, and maintenance controls for conversation history behavior. Keep defaults unless you need stricter isolation, retention, or delivery constraints.", "hasChildren": true @@ -45702,7 +49819,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Agent-to-Agent", "help": "Groups controls for inter-agent session exchanges, including loop prevention limits on reply chaining. Keep defaults unless you run advanced agent-to-agent automation with strict turn caps.", "hasChildren": true @@ -45714,7 +49833,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Agent-to-Agent Ping-Pong Turns", "help": "Max reply-back turns between requester and target agents during agent-to-agent exchanges (0-5). Use lower values to hard-limit chatter loops and preserve predictable run completion.", "hasChildren": false @@ -45726,7 +49848,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "DM Session Scope", "help": "DM session scoping: \"main\" keeps continuity, while \"per-peer\", \"per-channel-peer\", and \"per-account-channel-peer\" increase isolation. Use isolated modes for shared inboxes or multi-account deployments.", "hasChildren": false @@ -45738,7 +49862,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Identity Links", "help": "Maps canonical identities to provider-prefixed peer IDs so equivalent users resolve to one DM thread (example: telegram:123456). Use this when the same human appears across multiple channels or accounts.", "hasChildren": true @@ -45770,7 +49896,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Idle Minutes", "help": "Applies a legacy idle reset window in minutes for session reuse behavior across inactivity gaps. Use this only for compatibility and prefer structured reset policies under session.reset/session.resetByType.", "hasChildren": false @@ -45782,7 +49910,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Main Key", "help": "Overrides the canonical main session key used for continuity when dmScope or routing logic points to \"main\". Use a stable value only if you intentionally need custom session anchoring.", "hasChildren": false @@ -45794,7 +49924,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Maintenance", "help": "Automatic session-store maintenance controls for pruning age, entry caps, and file rotation behavior. Start in warn mode to observe impact, then enforce once thresholds are tuned.", "hasChildren": true @@ -45802,11 +49934,16 @@ { "path": "session.maintenance.highWaterBytes", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Disk High-water Target", "help": "Target size after disk-budget cleanup (high-water mark). Defaults to 80% of maxDiskBytes; set explicitly for tighter reclaim behavior on constrained disks.", "hasChildren": false @@ -45814,11 +49951,17 @@ { "path": "session.maintenance.maxDiskBytes", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Session Max Disk Budget", "help": "Optional per-agent sessions-directory disk budget (for example `500mb`). Use this to cap session storage per agent; when exceeded, warn mode reports pressure and enforce mode performs oldest-first cleanup.", "hasChildren": false @@ -45830,7 +49973,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Session Max Entries", "help": "Caps total session entry count retained in the store to prevent unbounded growth over time. Use lower limits for constrained environments, or higher limits when longer history is required.", "hasChildren": false @@ -45840,10 +49986,15 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["enforce", "warn"], + "enumValues": [ + "enforce", + "warn" + ], "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Maintenance Mode", "help": "Determines whether maintenance policies are only reported (\"warn\") or actively applied (\"enforce\"). Keep \"warn\" during rollout and switch to \"enforce\" after validating safe thresholds.", "hasChildren": false @@ -45851,11 +50002,16 @@ { "path": "session.maintenance.pruneAfter", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Prune After", "help": "Removes entries older than this duration (for example `30d` or `12h`) during maintenance passes. Use this as the primary age-retention control and align it with data retention policy.", "hasChildren": false @@ -45867,7 +50023,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Prune Days (Deprecated)", "help": "Deprecated age-retention field kept for compatibility with legacy configs using day counts. Use session.maintenance.pruneAfter instead so duration syntax and behavior are consistent.", "hasChildren": false @@ -45875,11 +50033,17 @@ { "path": "session.maintenance.resetArchiveRetention", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset Archive Retention", "help": "Retention for reset transcript archives (`*.reset.`). Accepts a duration (for example `30d`), or `false` to disable cleanup. Defaults to pruneAfter so reset artifacts do not grow forever.", "hasChildren": false @@ -45887,11 +50051,16 @@ { "path": "session.maintenance.rotateBytes", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Rotate Size", "help": "Rotates the session store when file size exceeds a threshold such as `10mb` or `1gb`. Use this to bound single-file growth and keep backup/restore operations manageable.", "hasChildren": false @@ -45903,7 +50072,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["auth", "performance", "security", "storage"], + "tags": [ + "auth", + "performance", + "security", + "storage" + ], "label": "Session Parent Fork Max Tokens", "help": "Maximum parent-session token count allowed for thread/session inheritance forking. If the parent exceeds this, OpenClaw starts a fresh thread session instead of forking; set 0 to disable this protection.", "hasChildren": false @@ -45915,7 +50089,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset Policy", "help": "Defines the default reset policy object used when no type-specific or channel-specific override applies. Set this first, then layer resetByType or resetByChannel only where behavior must differ.", "hasChildren": true @@ -45927,7 +50103,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Daily Reset Hour", "help": "Sets local-hour boundary (0-23) for daily reset mode so sessions roll over at predictable times. Use with mode=daily and align to operator timezone expectations for human-readable behavior.", "hasChildren": false @@ -45939,7 +50117,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset Idle Minutes", "help": "Sets inactivity window before reset for idle mode and can also act as secondary guard with daily mode. Use larger values to preserve continuity or smaller values for fresher short-lived threads.", "hasChildren": false @@ -45951,7 +50131,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset Mode", "help": "Selects reset strategy: \"daily\" resets at a configured hour and \"idle\" resets after inactivity windows. Keep one clear mode per policy to avoid surprising context turnover patterns.", "hasChildren": false @@ -45963,7 +50145,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset by Channel", "help": "Provides channel-specific reset overrides keyed by provider/channel id for fine-grained behavior control. Use this only when one channel needs exceptional reset behavior beyond type-level policies.", "hasChildren": true @@ -46015,7 +50199,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset by Chat Type", "help": "Overrides reset behavior by chat type (direct, group, thread) when defaults are not sufficient. Use this when group/thread traffic needs different reset cadence than direct messages.", "hasChildren": true @@ -46027,7 +50213,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset (Direct)", "help": "Defines reset policy for direct chats and supersedes the base session.reset configuration for that type. Use this as the canonical direct-message override instead of the legacy dm alias.", "hasChildren": true @@ -46069,7 +50257,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset (DM Deprecated Alias)", "help": "Deprecated alias for direct reset behavior kept for backward compatibility with older configs. Use session.resetByType.direct instead so future tooling and validation remain consistent.", "hasChildren": true @@ -46111,7 +50301,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset (Group)", "help": "Defines reset policy for group chat sessions where continuity and noise patterns differ from DMs. Use shorter idle windows for busy groups if context drift becomes a problem.", "hasChildren": true @@ -46153,7 +50345,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset (Thread)", "help": "Defines reset policy for thread-scoped sessions, including focused channel thread workflows. Use this when thread sessions should expire faster or slower than other chat types.", "hasChildren": true @@ -46195,7 +50389,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Reset Triggers", "help": "Lists message triggers that force a session reset when matched in inbound content. Use sparingly for explicit reset phrases so context is not dropped unexpectedly during normal conversation.", "hasChildren": true @@ -46217,7 +50413,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Scope", "help": "Sets base session grouping strategy: \"per-sender\" isolates by sender and \"global\" shares one session per channel context. Keep \"per-sender\" for safer multi-user behavior unless deliberate shared context is required.", "hasChildren": false @@ -46229,7 +50427,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Policy", "help": "Controls cross-session send permissions using allow/deny rules evaluated against channel, chatType, and key prefixes. Use this to fence where session tools can deliver messages in complex environments.", "hasChildren": true @@ -46241,7 +50442,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Policy Default Action", "help": "Sets fallback action when no sendPolicy rule matches: \"allow\" or \"deny\". Keep \"allow\" for simpler setups, or choose \"deny\" when you require explicit allow rules for every destination.", "hasChildren": false @@ -46253,7 +50457,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Policy Rules", "help": "Ordered allow/deny rules evaluated before the default action, for example `{ action: \"deny\", match: { channel: \"discord\" } }`. Put most specific rules first so broad rules do not shadow exceptions.", "hasChildren": true @@ -46275,7 +50482,10 @@ "required": true, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Action", "help": "Defines rule decision as \"allow\" or \"deny\" when the corresponding match criteria are satisfied. Use deny-first ordering when enforcing strict boundaries with explicit allow exceptions.", "hasChildren": false @@ -46287,7 +50497,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Match", "help": "Defines optional rule match conditions that can combine channel, chatType, and key-prefix constraints. Keep matches narrow so policy intent stays readable and debugging remains straightforward.", "hasChildren": true @@ -46299,7 +50512,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Channel", "help": "Matches rule application to a specific channel/provider id (for example discord, telegram, slack). Use this when one channel should permit or deny delivery independently of others.", "hasChildren": false @@ -46311,7 +50527,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Chat Type", "help": "Matches rule application to chat type (direct, group, thread) so behavior varies by conversation form. Use this when DM and group destinations require different safety boundaries.", "hasChildren": false @@ -46323,7 +50542,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Key Prefix", "help": "Matches a normalized session-key prefix after internal key normalization steps in policy consumers. Use this for general prefix controls, and prefer rawKeyPrefix when exact full-key matching is required.", "hasChildren": false @@ -46335,7 +50557,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "storage"], + "tags": [ + "access", + "storage" + ], "label": "Session Send Rule Raw Key Prefix", "help": "Matches the raw, unnormalized session-key prefix for exact full-key policy targeting. Use this when normalized keyPrefix is too broad and you need agent-prefixed or transport-specific precision.", "hasChildren": false @@ -46347,7 +50572,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Store Path", "help": "Sets the session storage file path used to persist session records across restarts. Use an explicit path only when you need custom disk layout, backup routing, or mounted-volume storage.", "hasChildren": false @@ -46359,7 +50586,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Thread Bindings", "help": "Shared defaults for thread-bound session routing behavior across providers that support thread focus workflows. Configure global defaults here and override per channel only when behavior differs.", "hasChildren": true @@ -46371,7 +50600,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Thread Binding Enabled", "help": "Global master switch for thread-bound session routing features and focused thread delivery behavior. Keep enabled for modern thread workflows unless you need to disable thread binding globally.", "hasChildren": false @@ -46383,7 +50614,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Thread Binding Idle Timeout (hours)", "help": "Default inactivity window in hours for thread-bound sessions across providers/channels (0 disables idle auto-unfocus). Default: 24.", "hasChildren": false @@ -46395,7 +50628,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Thread Binding Max Age (hours)", "help": "Optional hard max age in hours for thread-bound sessions across providers/channels (0 disables hard cap). Default: 0.", "hasChildren": false @@ -46407,7 +50643,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage"], + "tags": [ + "performance", + "storage" + ], "label": "Session Typing Interval (seconds)", "help": "Controls interval for repeated typing indicators while replies are being prepared in typing-capable channels. Increase to reduce chatty updates or decrease for more active typing feedback.", "hasChildren": false @@ -46419,7 +50658,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage"], + "tags": [ + "storage" + ], "label": "Session Typing Mode", "help": "Controls typing behavior timing: \"never\", \"instant\", \"thinking\", or \"message\" based emission points. Keep conservative modes in high-volume channels to avoid unnecessary typing noise.", "hasChildren": false @@ -46431,7 +50672,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Skills", "hasChildren": true }, @@ -46478,11 +50721,17 @@ { "path": "skills.entries.*.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security"], + "tags": [ + "auth", + "security" + ], "hasChildren": true }, { @@ -46691,7 +50940,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Watch Skills", "help": "Enable filesystem watching for skill-definition changes so updates can be applied without full process restart. Keep enabled in development workflows and disable in immutable production images.", "hasChildren": false @@ -46703,7 +50954,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation", "performance"], + "tags": [ + "automation", + "performance" + ], "label": "Skills Watch Debounce (ms)", "help": "Debounce window in milliseconds for coalescing rapid skill file changes before reload logic runs. Increase to reduce reload churn on frequent writes, or lower for faster edit feedback.", "hasChildren": false @@ -46715,7 +50969,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Talk", "help": "Talk-mode voice synthesis settings for voice identity, model selection, output format, and interruption behavior. Use this section to tune human-facing voice UX while controlling latency and cost.", "hasChildren": true @@ -46723,11 +50979,18 @@ { "path": "talk.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "media", "security"], + "tags": [ + "auth", + "media", + "security" + ], "label": "Talk API Key", "help": "Use this legacy ElevenLabs API key for Talk mode only during migration, and keep secrets in env-backed storage. Prefer talk.providers.elevenlabs.apiKey (fallback: ELEVENLABS_API_KEY).", "hasChildren": true @@ -46769,7 +51032,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Interrupt on Speech", "help": "If true (default), stop assistant speech when the user starts speaking in Talk mode. Keep enabled for conversational turn-taking.", "hasChildren": false @@ -46781,7 +51046,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models"], + "tags": [ + "media", + "models" + ], "label": "Talk Model ID", "help": "Legacy ElevenLabs model ID for Talk mode (default: eleven_v3). Prefer talk.providers.elevenlabs.modelId.", "hasChildren": false @@ -46793,7 +51061,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Output Format", "help": "Use this legacy ElevenLabs output format for Talk mode (for example pcm_44100 or mp3_44100_128) only during migration. Prefer talk.providers.elevenlabs.outputFormat.", "hasChildren": false @@ -46805,7 +51075,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Active Provider", "help": "Active Talk provider id (for example \"elevenlabs\").", "hasChildren": false @@ -46817,7 +51089,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Provider Settings", "help": "Provider-specific Talk settings keyed by provider id. During migration, prefer this over legacy talk.* keys.", "hasChildren": true @@ -46844,11 +51118,18 @@ { "path": "talk.providers.*.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "media", "security"], + "tags": [ + "auth", + "media", + "security" + ], "label": "Talk Provider API Key", "help": "Provider API key for Talk mode.", "hasChildren": true @@ -46890,7 +51171,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models"], + "tags": [ + "media", + "models" + ], "label": "Talk Provider Model ID", "help": "Provider default model ID for Talk mode.", "hasChildren": false @@ -46902,7 +51186,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Provider Output Format", "help": "Provider default output format for Talk mode.", "hasChildren": false @@ -46914,7 +51200,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Provider Voice Aliases", "help": "Optional provider voice alias map for Talk directives.", "hasChildren": true @@ -46936,7 +51224,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Provider Voice ID", "help": "Provider default voice ID for Talk mode.", "hasChildren": false @@ -46948,7 +51238,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance"], + "tags": [ + "media", + "performance" + ], "label": "Talk Silence Timeout (ms)", "help": "Milliseconds of user silence before Talk mode finalizes and sends the current transcript. Leave unset to keep the platform default pause window (700 ms on macOS and Android, 900 ms on iOS).", "hasChildren": false @@ -46960,7 +51253,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Voice Aliases", "help": "Use this legacy ElevenLabs voice alias map (for example {\"Clawd\":\"EXAVITQu4vr4xnSDxMaL\"}) only during migration. Prefer talk.providers.elevenlabs.voiceAliases.", "hasChildren": true @@ -46982,7 +51277,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media"], + "tags": [ + "media" + ], "label": "Talk Voice ID", "help": "Legacy ElevenLabs default voice ID for Talk mode. Prefer talk.providers.elevenlabs.voiceId.", "hasChildren": false @@ -46994,7 +51291,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Tools", "help": "Global tool access policy and capability configuration across web, exec, media, messaging, and elevated surfaces. Use this section to constrain risky capabilities before broad rollout.", "hasChildren": true @@ -47006,7 +51305,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Agent-to-Agent Tool Access", "help": "Policy for allowing agent-to-agent tool calls and constraining which target agents can be reached. Keep disabled or tightly scoped unless cross-agent orchestration is intentionally enabled.", "hasChildren": true @@ -47018,7 +51319,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Agent-to-Agent Target Allowlist", "help": "Allowlist of target agent IDs permitted for agent_to_agent calls when orchestration is enabled. Use explicit allowlists to avoid uncontrolled cross-agent call graphs.", "hasChildren": true @@ -47040,7 +51344,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Agent-to-Agent Tool", "help": "Enables the agent_to_agent tool surface so one agent can invoke another agent at runtime. Keep off in simple deployments and enable only when orchestration value outweighs complexity.", "hasChildren": false @@ -47052,7 +51358,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Tool Allowlist", "help": "Absolute tool allowlist that replaces profile-derived defaults for strict environments. Use this only when you intentionally run a tightly curated subset of tool capabilities.", "hasChildren": true @@ -47074,7 +51383,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Tool Allowlist Additions", "help": "Extra tool allowlist entries merged on top of the selected tool profile and default policy. Keep this list small and explicit so audits can quickly identify intentional policy exceptions.", "hasChildren": true @@ -47096,7 +51408,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool Policy by Provider", "help": "Per-provider tool allow/deny overrides keyed by channel/provider ID to tailor capabilities by surface. Use this when one provider needs stricter controls than global tool policy.", "hasChildren": true @@ -47188,7 +51502,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Tool Denylist", "help": "Global tool denylist that blocks listed tools even when profile or provider rules would allow them. Use deny rules for emergency lockouts and long-term defense-in-depth.", "hasChildren": true @@ -47210,7 +51527,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Elevated Tool Access", "help": "Elevated tool access controls for privileged command surfaces that should only be reachable from trusted senders. Keep disabled unless operator workflows explicitly require elevated actions.", "hasChildren": true @@ -47222,7 +51541,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Elevated Tool Allow Rules", "help": "Sender allow rules for elevated tools, usually keyed by channel/provider identity formats. Use narrow, explicit identities so elevated commands cannot be triggered by unintended users.", "hasChildren": true @@ -47240,7 +51562,10 @@ { "path": "tools.elevated.allowFrom.*.*", "kind": "core", - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -47254,7 +51579,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Elevated Tool Access", "help": "Enables elevated tool execution path when sender and policy checks pass. Keep disabled in public/shared channels and enable only for trusted owner-operated contexts.", "hasChildren": false @@ -47266,7 +51593,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Tool", "help": "Exec-tool policy grouping for shell execution host, security mode, approval behavior, and runtime bindings. Keep conservative defaults in production and tighten elevated execution paths.", "hasChildren": true @@ -47288,7 +51617,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "apply_patch Model Allowlist", "help": "Optional allowlist of model ids (e.g. \"gpt-5.2\" or \"openai/gpt-5.2\").", "hasChildren": true @@ -47310,7 +51642,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable apply_patch", "help": "Experimental. Enables apply_patch for OpenAI models when allowed by tool policy.", "hasChildren": false @@ -47322,7 +51656,12 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "advanced", "security", "tools"], + "tags": [ + "access", + "advanced", + "security", + "tools" + ], "label": "apply_patch Workspace-Only", "help": "Restrict apply_patch paths to the workspace directory (default: true). Set false to allow writing outside the workspace (dangerous).", "hasChildren": false @@ -47332,10 +51671,16 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["off", "on-miss", "always"], + "enumValues": [ + "off", + "on-miss", + "always" + ], "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Ask", "help": "Approval strategy for when exec commands require human confirmation before running. Use stricter ask behavior in shared channels and lower-friction settings in private operator contexts.", "hasChildren": false @@ -47365,10 +51710,16 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["sandbox", "gateway", "node"], + "enumValues": [ + "sandbox", + "gateway", + "node" + ], "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Host", "help": "Selects execution host strategy for shell commands, typically controlling local vs delegated execution environment. Use the safest host mode that still satisfies your automation requirements.", "hasChildren": false @@ -47380,7 +51731,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Node Binding", "help": "Node binding configuration for exec tooling when command execution is delegated through connected nodes. Use explicit node binding only when multi-node routing is required.", "hasChildren": false @@ -47392,7 +51745,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Notify On Exit", "help": "When true (default), backgrounded exec sessions on exit and node exec lifecycle events enqueue a system event and request a heartbeat.", "hasChildren": false @@ -47404,7 +51759,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Notify On Empty Success", "help": "When true, successful backgrounded exec exits with empty output still enqueue a completion system event (default: false).", "hasChildren": false @@ -47416,7 +51773,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Exec PATH Prepend", "help": "Directories to prepend to PATH for exec runs (gateway/sandbox).", "hasChildren": true @@ -47438,7 +51798,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Exec Safe Bin Profiles", "help": "Optional per-binary safe-bin profiles (positional limits + allowed/denied flags).", "hasChildren": true @@ -47520,7 +51883,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Safe Bins", "help": "Allow stdin-only safe binaries to run without explicit allowlist entries.", "hasChildren": true @@ -47542,7 +51907,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Exec Safe Bin Trusted Dirs", "help": "Additional explicit directories trusted for safe-bin path checks (PATH entries are never auto-trusted).", "hasChildren": true @@ -47562,10 +51930,16 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["deny", "allowlist", "full"], + "enumValues": [ + "deny", + "allowlist", + "full" + ], "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Exec Security", "help": "Execution security posture selector controlling sandbox/approval expectations for command execution. Keep strict security mode for untrusted prompts and relax only for trusted operator workflows.", "hasChildren": false @@ -47597,7 +51971,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Workspace-only FS tools", "help": "Restrict filesystem tools (read/write/edit/apply_patch) to the workspace directory (default: false).", "hasChildren": false @@ -47619,7 +51995,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Link Understanding", "help": "Enable automatic link understanding pre-processing so URLs can be summarized before agent reasoning. Keep enabled for richer context, and disable when strict minimal processing is required.", "hasChildren": false @@ -47631,7 +52009,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Link Understanding Max Links", "help": "Maximum number of links expanded per turn during link understanding. Use lower values to control latency/cost in chatty threads and higher values when multi-link context is critical.", "hasChildren": false @@ -47643,7 +52024,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "tools"], + "tags": [ + "models", + "tools" + ], "label": "Link Understanding Models", "help": "Preferred model list for link understanding tasks, evaluated in order as fallbacks when supported. Use lightweight models first for routine summarization and heavier models only when needed.", "hasChildren": true @@ -47715,7 +52099,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Link Understanding Scope", "help": "Controls when link understanding runs relative to conversation context and message type. Keep scope conservative to avoid unnecessary fetches on messages where links are not actionable.", "hasChildren": true @@ -47817,7 +52203,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Link Understanding Timeout (sec)", "help": "Per-link understanding timeout budget in seconds before unresolved links are skipped. Keep this bounded to avoid long stalls when external sites are slow or unreachable.", "hasChildren": false @@ -47839,7 +52228,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Critical Threshold", "help": "Critical threshold for repetitive patterns when detector is enabled (default: 20).", "hasChildren": false @@ -47861,7 +52252,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Generic Repeat Detection", "help": "Enable generic repeated same-tool/same-params loop detection (default: true).", "hasChildren": false @@ -47873,7 +52266,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Poll No-Progress Detection", "help": "Enable known poll tool no-progress loop detection (default: true).", "hasChildren": false @@ -47885,7 +52280,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Ping-Pong Detection", "help": "Enable ping-pong loop detection (default: true).", "hasChildren": false @@ -47897,7 +52294,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Detection", "help": "Enable repetitive tool-call loop detection and backoff safety checks (default: false).", "hasChildren": false @@ -47909,7 +52308,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["reliability", "tools"], + "tags": [ + "reliability", + "tools" + ], "label": "Tool-loop Global Circuit Breaker Threshold", "help": "Global no-progress breaker threshold (default: 30).", "hasChildren": false @@ -47921,7 +52323,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop History Size", "help": "Tool history window size for loop detection (default: 30).", "hasChildren": false @@ -47933,7 +52337,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Tool-loop Warning Threshold", "help": "Warning threshold for repetitive patterns when detector is enabled (default: 10).", "hasChildren": false @@ -47965,7 +52371,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Audio Understanding Attachment Policy", "help": "Attachment policy for audio inputs indicating which uploaded files are eligible for audio processing. Keep restrictive defaults in mixed-content channels to avoid unintended audio workloads.", "hasChildren": true @@ -48057,7 +52466,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Transcript Echo Format", "help": "Format string for the echoed transcript message. Use `{transcript}` as a placeholder for the transcribed text. Default: '📝 \"{transcript}\"'.", "hasChildren": false @@ -48069,7 +52481,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Echo Transcript to Chat", "help": "Echo the audio transcript back to the originating chat before agent processing. When enabled, users immediately see what was heard from their voice note, helping them verify transcription accuracy before the agent acts on it. Default: false.", "hasChildren": false @@ -48081,7 +52496,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Enable Audio Understanding", "help": "Enable audio understanding so voice notes or audio clips can be transcribed/summarized for agent context. Disable when audio ingestion is outside policy or unnecessary for your workflows.", "hasChildren": false @@ -48113,7 +52531,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Audio Understanding Language", "help": "Preferred language hint for audio understanding/transcription when provider support is available. Set this to improve recognition accuracy for known primary languages.", "hasChildren": false @@ -48125,7 +52546,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Audio Understanding Max Bytes", "help": "Maximum accepted audio payload size in bytes before processing is rejected or clipped by policy. Set this based on expected recording length and upstream provider limits.", "hasChildren": false @@ -48137,7 +52562,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Audio Understanding Max Chars", "help": "Maximum characters retained from audio understanding output to prevent oversized transcript injection. Increase for long-form dictation, or lower to keep conversational turns compact.", "hasChildren": false @@ -48149,7 +52578,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models", "tools"], + "tags": [ + "media", + "models", + "tools" + ], "label": "Audio Understanding Models", "help": "Ordered model preferences specifically for audio understanding, used before shared media model fallback. Choose models optimized for transcription quality in your primary language/domain.", "hasChildren": true @@ -48387,7 +52820,11 @@ { "path": "tools.media.audio.models.*.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -48421,7 +52858,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Audio Understanding Prompt", "help": "Instruction template guiding audio understanding output style, such as concise summary versus near-verbatim transcript. Keep wording consistent so downstream automations can rely on output format.", "hasChildren": false @@ -48449,7 +52889,11 @@ { "path": "tools.media.audio.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -48463,7 +52907,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Audio Understanding Scope", "help": "Scope selector for when audio understanding runs across inbound messages and attachments. Keep focused scopes in high-volume channels to reduce cost and avoid accidental transcription.", "hasChildren": true @@ -48565,7 +53012,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Audio Understanding Timeout (sec)", "help": "Timeout in seconds for audio understanding execution before the operation is cancelled. Use longer timeouts for long recordings and tighter ones for interactive chat responsiveness.", "hasChildren": false @@ -48577,7 +53028,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Media Understanding Concurrency", "help": "Maximum number of concurrent media understanding operations per turn across image, audio, and video tasks. Lower this in resource-constrained deployments to prevent CPU/network saturation.", "hasChildren": false @@ -48599,7 +53054,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Image Understanding Attachment Policy", "help": "Attachment handling policy for image inputs, including which message attachments qualify for image analysis. Use restrictive settings in untrusted channels to reduce unexpected processing.", "hasChildren": true @@ -48711,7 +53169,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Enable Image Understanding", "help": "Enable image understanding so attached or referenced images can be interpreted into textual context. Disable if you need text-only operation or want to avoid image-processing cost.", "hasChildren": false @@ -48753,7 +53214,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Image Understanding Max Bytes", "help": "Maximum accepted image payload size in bytes before the item is skipped or truncated by policy. Keep limits realistic for your provider caps and infrastructure bandwidth.", "hasChildren": false @@ -48765,7 +53230,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Image Understanding Max Chars", "help": "Maximum characters returned from image understanding output after model response normalization. Use tighter limits to reduce prompt bloat and larger limits for detail-heavy OCR tasks.", "hasChildren": false @@ -48777,7 +53246,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models", "tools"], + "tags": [ + "media", + "models", + "tools" + ], "label": "Image Understanding Models", "help": "Ordered model preferences specifically for image understanding when you want to override shared media models. Put the most reliable multimodal model first to reduce fallback attempts.", "hasChildren": true @@ -49015,7 +53488,11 @@ { "path": "tools.media.image.models.*.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -49049,7 +53526,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Image Understanding Prompt", "help": "Instruction template used for image understanding requests to shape extraction style and detail level. Keep prompts deterministic so outputs stay consistent across turns and channels.", "hasChildren": false @@ -49077,7 +53557,11 @@ { "path": "tools.media.image.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -49091,7 +53575,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Image Understanding Scope", "help": "Scope selector for when image understanding is attempted (for example only explicit requests versus broader auto-detection). Keep narrow scope in busy channels to control token and API spend.", "hasChildren": true @@ -49193,7 +53680,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Image Understanding Timeout (sec)", "help": "Timeout in seconds for each image understanding request before it is aborted. Increase for high-resolution analysis and lower it for latency-sensitive operator workflows.", "hasChildren": false @@ -49205,7 +53696,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models", "tools"], + "tags": [ + "media", + "models", + "tools" + ], "label": "Media Understanding Shared Models", "help": "Shared fallback model list used by media understanding tools when modality-specific model lists are not set. Keep this aligned with available multimodal providers to avoid runtime fallback churn.", "hasChildren": true @@ -49443,7 +53938,11 @@ { "path": "tools.media.models.*.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -49487,7 +53986,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Video Understanding Attachment Policy", "help": "Attachment eligibility policy for video analysis, defining which message files can trigger video processing. Keep this explicit in shared channels to prevent accidental large media workloads.", "hasChildren": true @@ -49599,7 +54101,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Enable Video Understanding", "help": "Enable video understanding so clips can be summarized into text for downstream reasoning and responses. Disable when processing video is out of policy or too expensive for your deployment.", "hasChildren": false @@ -49641,7 +54146,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Video Understanding Max Bytes", "help": "Maximum accepted video payload size in bytes before policy rejection or trimming occurs. Tune this to provider and infrastructure limits to avoid repeated timeout/failure loops.", "hasChildren": false @@ -49653,7 +54162,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Video Understanding Max Chars", "help": "Maximum characters retained from video understanding output to control prompt growth. Raise for dense scene descriptions and lower when concise summaries are preferred.", "hasChildren": false @@ -49665,7 +54178,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "models", "tools"], + "tags": [ + "media", + "models", + "tools" + ], "label": "Video Understanding Models", "help": "Ordered model preferences specifically for video understanding before shared media fallback applies. Prioritize models with strong multimodal video support to minimize degraded summaries.", "hasChildren": true @@ -49903,7 +54420,11 @@ { "path": "tools.media.video.models.*.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -49937,7 +54458,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Video Understanding Prompt", "help": "Instruction template for video understanding describing desired summary granularity and focus areas. Keep this stable so output quality remains predictable across model/provider fallbacks.", "hasChildren": false @@ -49965,7 +54489,11 @@ { "path": "tools.media.video.providerOptions.*.*", "kind": "core", - "type": ["boolean", "number", "string"], + "type": [ + "boolean", + "number", + "string" + ], "required": false, "deprecated": false, "sensitive": false, @@ -49979,7 +54507,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "tools"], + "tags": [ + "media", + "tools" + ], "label": "Video Understanding Scope", "help": "Scope selector controlling when video understanding is attempted across incoming events. Narrow scope in noisy channels, and broaden only where video interpretation is core to workflow.", "hasChildren": true @@ -50081,7 +54612,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["media", "performance", "tools"], + "tags": [ + "media", + "performance", + "tools" + ], "label": "Video Understanding Timeout (sec)", "help": "Timeout in seconds for each video understanding request before cancellation. Use conservative values in interactive channels and longer values for offline or batch-heavy processing.", "hasChildren": false @@ -50103,7 +54638,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Allow Cross-Context Messaging", "help": "Legacy override: allow cross-context sends across all providers.", "hasChildren": false @@ -50125,7 +54663,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Message Broadcast", "help": "Enable broadcast action (default: true).", "hasChildren": false @@ -50147,7 +54687,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Allow Cross-Context (Across Providers)", "help": "Allow sends across different providers (default: false).", "hasChildren": false @@ -50159,7 +54702,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["access", "tools"], + "tags": [ + "access", + "tools" + ], "label": "Allow Cross-Context (Same Provider)", "help": "Allow sends to other channels within the same provider (default: true).", "hasChildren": false @@ -50181,7 +54727,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Cross-Context Marker", "help": "Add a visible origin marker when sending cross-context (default: true).", "hasChildren": false @@ -50193,7 +54741,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Cross-Context Marker Prefix", "help": "Text prefix for cross-context markers (supports \"{channel}\").", "hasChildren": false @@ -50205,7 +54755,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Cross-Context Marker Suffix", "help": "Text suffix for cross-context markers (supports \"{channel}\").", "hasChildren": false @@ -50217,7 +54769,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Tool Profile", "help": "Global tool profile name used to select a predefined tool policy baseline before applying allow/deny overrides. Use this for consistent environment posture across agents and keep profile names stable.", "hasChildren": false @@ -50229,7 +54784,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Sandbox Tool Policy", "help": "Tool policy wrapper for sandboxed agent executions so sandbox runs can have distinct capability boundaries. Use this to enforce stronger safety in sandbox contexts.", "hasChildren": true @@ -50241,7 +54799,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Sandbox Tool Allow/Deny Policy", "help": "Allow/deny tool policy applied when agents run in sandboxed execution environments. Keep policies minimal so sandbox tasks cannot escalate into unnecessary external actions.", "hasChildren": true @@ -50391,10 +54952,18 @@ "kind": "core", "type": "string", "required": false, - "enumValues": ["self", "tree", "agent", "all"], + "enumValues": [ + "self", + "tree", + "agent", + "all" + ], "deprecated": false, "sensitive": false, - "tags": ["storage", "tools"], + "tags": [ + "storage", + "tools" + ], "label": "Session Tools Visibility", "help": "Controls which sessions can be targeted by sessions_list/sessions_history/sessions_send. (\"tree\" default = current session + spawned subagent sessions; \"self\" = only current; \"agent\" = any session in the current agent id; \"all\" = any session; cross-agent still requires tools.agentToAgent).", "hasChildren": false @@ -50406,7 +54975,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Subagent Tool Policy", "help": "Tool policy wrapper for spawned subagents to restrict or expand tool availability compared to parent defaults. Use this to keep delegated agent capabilities scoped to task intent.", "hasChildren": true @@ -50418,7 +54989,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Subagent Tool Allow/Deny Policy", "help": "Allow/deny tool policy applied to spawned subagent runtimes for per-subagent hardening. Keep this narrower than parent scope when subagents run semi-autonomous workflows.", "hasChildren": true @@ -50490,7 +55063,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Web Tools", "help": "Web-tool policy grouping for search/fetch providers, limits, and fallback behavior tuning. Keep enabled settings aligned with API key availability and outbound networking policy.", "hasChildren": true @@ -50512,7 +55087,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage", "tools"], + "tags": [ + "performance", + "storage", + "tools" + ], "label": "Web Fetch Cache TTL (min)", "help": "Cache TTL in minutes for web_fetch results.", "hasChildren": false @@ -50524,7 +55103,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Web Fetch Tool", "help": "Enable the web_fetch tool (lightweight HTTP fetch).", "hasChildren": false @@ -50542,11 +55123,18 @@ { "path": "tools.web.fetch.firecrawl.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Firecrawl API Key", "help": "Firecrawl API key (fallback: FIRECRAWL_API_KEY env var).", "hasChildren": true @@ -50588,7 +55176,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Firecrawl Base URL", "help": "Firecrawl base URL (e.g. https://api.firecrawl.dev or custom endpoint).", "hasChildren": false @@ -50600,7 +55190,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Firecrawl Fallback", "help": "Enable Firecrawl fallback for web_fetch (if configured).", "hasChildren": false @@ -50612,7 +55204,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Firecrawl Cache Max Age (ms)", "help": "Firecrawl maxAge (ms) for cached results when supported by the API.", "hasChildren": false @@ -50624,7 +55219,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Firecrawl Main Content Only", "help": "When true, Firecrawl returns only the main content (default: true).", "hasChildren": false @@ -50636,7 +55233,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Firecrawl Timeout (sec)", "help": "Timeout in seconds for Firecrawl requests.", "hasChildren": false @@ -50648,7 +55248,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Web Fetch Max Chars", "help": "Max characters returned by web_fetch (truncated).", "hasChildren": false @@ -50660,7 +55263,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Web Fetch Hard Max Chars", "help": "Hard cap for web_fetch maxChars (applies to config and tool calls).", "hasChildren": false @@ -50672,7 +55278,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage", "tools"], + "tags": [ + "performance", + "storage", + "tools" + ], "label": "Web Fetch Max Redirects", "help": "Maximum redirects allowed for web_fetch (default: 3).", "hasChildren": false @@ -50684,7 +55294,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Web Fetch Readability Extraction", "help": "Use Readability to extract main content from HTML (fallbacks to basic HTML cleanup).", "hasChildren": false @@ -50696,7 +55308,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Web Fetch Timeout (sec)", "help": "Timeout in seconds for web_fetch requests.", "hasChildren": false @@ -50708,7 +55323,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Web Fetch User-Agent", "help": "Override User-Agent header for web_fetch requests.", "hasChildren": false @@ -50726,11 +55343,18 @@ { "path": "tools.web.search.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Brave Search API Key", "help": "Brave Search API key (fallback: BRAVE_API_KEY env var).", "hasChildren": true @@ -50782,7 +55406,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Brave Search Mode", "help": "Brave Search mode: \"web\" (URL results) or \"llm-context\" (pre-extracted page content for LLM grounding).", "hasChildren": false @@ -50794,7 +55420,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "storage", "tools"], + "tags": [ + "performance", + "storage", + "tools" + ], "label": "Web Search Cache TTL (min)", "help": "Cache TTL in minutes for web_search results.", "hasChildren": false @@ -50806,7 +55436,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Enable Web Search Tool", "help": "Enable the web_search tool (requires a provider API key).", "hasChildren": false @@ -50824,11 +55456,18 @@ { "path": "tools.web.search.gemini.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Gemini Search API Key", "help": "Gemini API key for Google Search grounding (fallback: GEMINI_API_KEY env var).", "hasChildren": true @@ -50870,7 +55509,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "tools"], + "tags": [ + "models", + "tools" + ], "label": "Gemini Search Model", "help": "Gemini model override (default: \"gemini-2.5-flash\").", "hasChildren": false @@ -50888,11 +55530,18 @@ { "path": "tools.web.search.grok.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Grok Search API Key", "help": "Grok (xAI) API key (fallback: XAI_API_KEY env var).", "hasChildren": true @@ -50944,7 +55593,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "tools"], + "tags": [ + "models", + "tools" + ], "label": "Grok Search Model", "help": "Grok model override (default: \"grok-4-1-fast\").", "hasChildren": false @@ -50962,11 +55614,18 @@ { "path": "tools.web.search.kimi.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Kimi Search API Key", "help": "Moonshot/Kimi API key (fallback: KIMI_API_KEY or MOONSHOT_API_KEY env var).", "hasChildren": true @@ -51008,7 +55667,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Kimi Search Base URL", "help": "Kimi base URL override (default: \"https://api.moonshot.ai/v1\").", "hasChildren": false @@ -51020,7 +55681,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "tools"], + "tags": [ + "models", + "tools" + ], "label": "Kimi Search Model", "help": "Kimi model override (default: \"moonshot-v1-128k\").", "hasChildren": false @@ -51032,7 +55696,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Web Search Max Results", "help": "Number of results to return (1-10).", "hasChildren": false @@ -51050,11 +55717,18 @@ { "path": "tools.web.search.perplexity.apiKey", "kind": "core", - "type": ["object", "string"], + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, - "tags": ["auth", "security", "tools"], + "tags": [ + "auth", + "security", + "tools" + ], "label": "Perplexity API Key", "help": "Perplexity or OpenRouter API key (fallback: PERPLEXITY_API_KEY or OPENROUTER_API_KEY env var). Direct Perplexity keys default to the Search API; OpenRouter keys use Sonar chat completions.", "hasChildren": true @@ -51096,7 +55770,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Perplexity Base URL", "help": "Optional Perplexity/OpenRouter chat-completions base URL override. Setting this opts Perplexity into the legacy Sonar/OpenRouter compatibility path.", "hasChildren": false @@ -51108,7 +55784,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["models", "tools"], + "tags": [ + "models", + "tools" + ], "label": "Perplexity Model", "help": "Optional Sonar/OpenRouter model override (default: \"perplexity/sonar-pro\"). Setting this opts Perplexity into the legacy chat-completions compatibility path.", "hasChildren": false @@ -51120,7 +55799,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["tools"], + "tags": [ + "tools" + ], "label": "Web Search Provider", "help": "Search provider (\"brave\", \"gemini\", \"grok\", \"kimi\", or \"perplexity\"). Auto-detected from available API keys if omitted.", "hasChildren": false @@ -51132,7 +55813,10 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance", "tools"], + "tags": [ + "performance", + "tools" + ], "label": "Web Search Timeout (sec)", "help": "Timeout in seconds for web_search requests.", "hasChildren": false @@ -51144,7 +55828,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "UI", "help": "UI presentation settings for accenting and assistant identity shown in control surfaces. Use this for branding and readability customization without changing runtime behavior.", "hasChildren": true @@ -51156,7 +55842,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Assistant Appearance", "help": "Assistant display identity settings for name and avatar shown in UI surfaces. Keep these values aligned with your operator-facing persona and support expectations.", "hasChildren": true @@ -51168,7 +55856,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Assistant Avatar", "help": "Assistant avatar image source used in UI surfaces (URL, path, or data URI depending on runtime support). Use trusted assets and consistent branding dimensions for clean rendering.", "hasChildren": false @@ -51180,7 +55870,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Assistant Name", "help": "Display name shown for the assistant in UI views, chat chrome, and status contexts. Keep this stable so operators can reliably identify which assistant persona is active.", "hasChildren": false @@ -51192,7 +55884,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Accent Color", "help": "Primary accent/seam color used by UI surfaces for emphasis, badges, and visual identity cues. Use high-contrast values that remain readable across light/dark themes.", "hasChildren": false @@ -51204,7 +55898,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Updates", "help": "Update-channel and startup-check behavior for keeping OpenClaw runtime versions current. Use conservative channels in production and more experimental channels only in controlled environments.", "hasChildren": true @@ -51226,7 +55922,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Auto Update Beta Check Interval (hours)", "help": "How often beta-channel checks run in hours (default: 1).", "hasChildren": false @@ -51238,7 +55936,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Auto Update Enabled", "help": "Enable background auto-update for package installs (default: false).", "hasChildren": false @@ -51250,7 +55950,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Auto Update Stable Delay (hours)", "help": "Minimum delay before stable-channel auto-apply starts (default: 6).", "hasChildren": false @@ -51262,7 +55964,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Auto Update Stable Jitter (hours)", "help": "Extra stable-channel rollout spread window in hours (default: 12).", "hasChildren": false @@ -51274,7 +55978,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Update Channel", "help": "Update channel for git + npm installs (\"stable\", \"beta\", or \"dev\").", "hasChildren": false @@ -51286,7 +55992,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Update Check on Start", "help": "Check for npm updates when the gateway starts (default: true).", "hasChildren": false @@ -51298,7 +56006,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Channel", "help": "Web channel runtime settings for heartbeat and reconnect behavior when operating web-based chat surfaces. Use reconnect values tuned to your network reliability profile and expected uptime needs.", "hasChildren": true @@ -51310,7 +56020,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Channel Enabled", "help": "Enables the web channel runtime and related websocket lifecycle behavior. Keep disabled when web chat is unused to reduce active connection management overhead.", "hasChildren": false @@ -51322,7 +56034,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["automation"], + "tags": [ + "automation" + ], "label": "Web Channel Heartbeat Interval (sec)", "help": "Heartbeat interval in seconds for web channel connectivity and liveness maintenance. Use shorter intervals for faster detection, or longer intervals to reduce keepalive chatter.", "hasChildren": false @@ -51334,7 +56048,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Channel Reconnect Policy", "help": "Reconnect backoff policy for web channel reconnect attempts after transport failure. Keep bounded retries and jitter tuned to avoid thundering-herd reconnect behavior.", "hasChildren": true @@ -51346,7 +56062,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Reconnect Backoff Factor", "help": "Exponential backoff multiplier used between reconnect attempts in web channel retry loops. Keep factor above 1 and tune with jitter for stable large-fleet reconnect behavior.", "hasChildren": false @@ -51358,7 +56076,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Reconnect Initial Delay (ms)", "help": "Initial reconnect delay in milliseconds before the first retry after disconnection. Use modest delays to recover quickly without immediate retry storms.", "hasChildren": false @@ -51370,7 +56090,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Web Reconnect Jitter", "help": "Randomization factor (0-1) applied to reconnect delays to desynchronize clients after outage events. Keep non-zero jitter in multi-client deployments to reduce synchronized spikes.", "hasChildren": false @@ -51382,7 +56104,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Web Reconnect Max Attempts", "help": "Maximum reconnect attempts before giving up for the current failure sequence (0 means no retries). Use finite caps for controlled failure handling in automation-sensitive environments.", "hasChildren": false @@ -51394,7 +56118,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["performance"], + "tags": [ + "performance" + ], "label": "Web Reconnect Max Delay (ms)", "help": "Maximum reconnect backoff cap in milliseconds to bound retry delay growth over repeated failures. Use a reasonable cap so recovery remains timely after prolonged outages.", "hasChildren": false @@ -51406,7 +56132,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Setup Wizard State", "help": "Setup wizard state tracking fields that record the most recent guided onboarding run details. Keep these fields for observability and troubleshooting of setup flows across upgrades.", "hasChildren": true @@ -51418,7 +56146,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Wizard Last Run Timestamp", "help": "ISO timestamp for when the setup wizard most recently completed on this host. Use this to confirm onboarding recency during support and operational audits.", "hasChildren": false @@ -51430,7 +56160,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Wizard Last Run Command", "help": "Command invocation recorded for the latest wizard run to preserve execution context. Use this to reproduce onboarding steps when verifying setup regressions.", "hasChildren": false @@ -51442,7 +56174,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Wizard Last Run Commit", "help": "Source commit identifier recorded for the last wizard execution in development builds. Use this to correlate onboarding behavior with exact source state during debugging.", "hasChildren": false @@ -51454,7 +56188,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Wizard Last Run Mode", "help": "Wizard execution mode recorded as \"local\" or \"remote\" for the most recent onboarding flow. Use this to understand whether setup targeted direct local runtime or remote gateway topology.", "hasChildren": false @@ -51466,7 +56202,9 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": ["advanced"], + "tags": [ + "advanced" + ], "label": "Wizard Last Run Version", "help": "OpenClaw version recorded at the time of the most recent wizard run on this config. Use this when diagnosing behavior differences across version-to-version onboarding changes.", "hasChildren": false From 5a7aba94a2bf1d0ca5aabd86337259a8001c8f6a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 15 Mar 2026 14:18:12 -0700 Subject: [PATCH 16/16] CLI: support package-manager installs from GitHub main (#47630) * CLI: resolve package-manager main install specs * CLI: skip registry resolution for raw package specs * CLI: support main package target updates * CLI: document package update specs in help * Tests: cover package install spec resolution * Tests: cover npm main-package updates * Tests: cover update --tag main * Installer: support main package targets * Installer: support main package targets on Windows * Docs: document package-manager main updates * Docs: document installer main targets * Docs: document npm and pnpm main installs * Docs: document update --tag main * Changelog: note package-manager main installs * Update src/infra/update-global.test.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/cli/update.md | 3 +- docs/install/index.md | 10 ++++ docs/install/installer.md | 82 ++++++++++++++++------------ docs/install/updating.md | 20 ++++++- scripts/install.ps1 | 40 ++++++++++++-- scripts/install.sh | 52 +++++++++++++++--- src/cli/update-cli.test.ts | 42 ++++++++++++++ src/cli/update-cli.ts | 8 ++- src/cli/update-cli/shared.ts | 4 ++ src/cli/update-cli/update-command.ts | 31 ++++++++--- src/infra/update-global.test.ts | 38 +++++++++++++ src/infra/update-global.ts | 38 ++++++++++++- src/infra/update-runner.test.ts | 14 +++++ 14 files changed, 320 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b4546d49d2..bf37c1757e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai - Refactor/channels: remove the legacy channel shim directories and point channel-specific imports directly at the extension-owned implementations. (#45967) thanks @scoootscooob. - Android/nodes: add `callLog.search` plus shared Call Log permission wiring so Android nodes can search recent call history through the gateway. (#44073) Thanks @lxk7280. - Docs/Zalo: clarify the Marketplace-bot support matrix and config guidance so the Zalo channel docs match current Bot Creator behavior more closely. (#47552) Thanks @No898. +- Install/update: allow package-manager installs from GitHub `main` via `openclaw update --tag main`, installer `--version main`, or direct npm/pnpm git specs. ### Fixes diff --git a/docs/cli/update.md b/docs/cli/update.md index 7a1840096f2..d1c61518b0c 100644 --- a/docs/cli/update.md +++ b/docs/cli/update.md @@ -21,6 +21,7 @@ openclaw update wizard openclaw update --channel beta openclaw update --channel dev openclaw update --tag beta +openclaw update --tag main openclaw update --dry-run openclaw update --no-restart openclaw update --json @@ -31,7 +32,7 @@ openclaw --update - `--no-restart`: skip restarting the Gateway service after a successful update. - `--channel `: set the update channel (git + npm; persisted in config). -- `--tag `: override the npm dist-tag or version for this update only. +- `--tag `: override the package target for this update only. For package installs, `main` maps to `github:openclaw/openclaw#main`. - `--dry-run`: preview planned update actions (channel/tag/target/restart flow) without writing config, installing, syncing plugins, or restarting. - `--json`: print machine-readable `UpdateRunResult` JSON. - `--timeout `: per-step timeout (default is 1200s). diff --git a/docs/install/index.md b/docs/install/index.md index d0f847838d0..464a457a360 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -102,6 +102,16 @@ For VPS/cloud hosts, avoid third-party "1-click" marketplace images when possibl + Want the current GitHub `main` head with a package-manager install? + + ```bash + npm install -g github:openclaw/openclaw#main + ``` + + ```bash + pnpm add -g github:openclaw/openclaw#main + ``` + diff --git a/docs/install/installer.md b/docs/install/installer.md index 6317e8e06cc..5859c22fd0d 100644 --- a/docs/install/installer.md +++ b/docs/install/installer.md @@ -116,6 +116,11 @@ The script exits with code `2` for invalid method selection or invalid `--instal curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git ``` + + ```bash + curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --version main + ``` + ```bash curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --dry-run @@ -126,39 +131,39 @@ The script exits with code `2` for invalid method selection or invalid `--instal -| Flag | Description | -| ------------------------------- | ---------------------------------------------------------- | -| `--install-method npm\|git` | Choose install method (default: `npm`). Alias: `--method` | -| `--npm` | Shortcut for npm method | -| `--git` | Shortcut for git method. Alias: `--github` | -| `--version ` | npm version or dist-tag (default: `latest`) | -| `--beta` | Use beta dist-tag if available, else fallback to `latest` | -| `--git-dir ` | Checkout directory (default: `~/openclaw`). Alias: `--dir` | -| `--no-git-update` | Skip `git pull` for existing checkout | -| `--no-prompt` | Disable prompts | -| `--no-onboard` | Skip onboarding | -| `--onboard` | Enable onboarding | -| `--dry-run` | Print actions without applying changes | -| `--verbose` | Enable debug output (`set -x`, npm notice-level logs) | -| `--help` | Show usage (`-h`) | +| Flag | Description | +| ------------------------------------- | ---------------------------------------------------------- | +| `--install-method npm\|git` | Choose install method (default: `npm`). Alias: `--method` | +| `--npm` | Shortcut for npm method | +| `--git` | Shortcut for git method. Alias: `--github` | +| `--version ` | npm version, dist-tag, or package spec (default: `latest`) | +| `--beta` | Use beta dist-tag if available, else fallback to `latest` | +| `--git-dir ` | Checkout directory (default: `~/openclaw`). Alias: `--dir` | +| `--no-git-update` | Skip `git pull` for existing checkout | +| `--no-prompt` | Disable prompts | +| `--no-onboard` | Skip onboarding | +| `--onboard` | Enable onboarding | +| `--dry-run` | Print actions without applying changes | +| `--verbose` | Enable debug output (`set -x`, npm notice-level logs) | +| `--help` | Show usage (`-h`) | -| Variable | Description | -| ------------------------------------------- | --------------------------------------------- | -| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method | -| `OPENCLAW_VERSION=latest\|next\|` | npm version or dist-tag | -| `OPENCLAW_BETA=0\|1` | Use beta if available | -| `OPENCLAW_GIT_DIR=` | Checkout directory | -| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates | -| `OPENCLAW_NO_PROMPT=1` | Disable prompts | -| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding | -| `OPENCLAW_DRY_RUN=1` | Dry run mode | -| `OPENCLAW_VERBOSE=1` | Debug mode | -| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level | -| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) | +| Variable | Description | +| ------------------------------------------------------- | --------------------------------------------- | +| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method | +| `OPENCLAW_VERSION=latest\|next\|main\|\|` | npm version, dist-tag, or package spec | +| `OPENCLAW_BETA=0\|1` | Use beta if available | +| `OPENCLAW_GIT_DIR=` | Checkout directory | +| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates | +| `OPENCLAW_NO_PROMPT=1` | Disable prompts | +| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding | +| `OPENCLAW_DRY_RUN=1` | Dry run mode | +| `OPENCLAW_VERBOSE=1` | Debug mode | +| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level | +| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) | @@ -276,6 +281,11 @@ Designed for environments where you want everything under a local prefix (defaul & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git ``` + + ```powershell + & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -Tag main + ``` + ```powershell & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git -GitDir "C:\openclaw" @@ -299,14 +309,14 @@ Designed for environments where you want everything under a local prefix (defaul -| Flag | Description | -| ------------------------- | ------------------------------------------------------ | -| `-InstallMethod npm\|git` | Install method (default: `npm`) | -| `-Tag ` | npm dist-tag (default: `latest`) | -| `-GitDir ` | Checkout directory (default: `%USERPROFILE%\openclaw`) | -| `-NoOnboard` | Skip onboarding | -| `-NoGitUpdate` | Skip `git pull` | -| `-DryRun` | Print actions only | +| Flag | Description | +| --------------------------- | ---------------------------------------------------------- | +| `-InstallMethod npm\|git` | Install method (default: `npm`) | +| `-Tag ` | npm dist-tag, version, or package spec (default: `latest`) | +| `-GitDir ` | Checkout directory (default: `%USERPROFILE%\openclaw`) | +| `-NoOnboard` | Skip onboarding | +| `-NoGitUpdate` | Skip `git pull` | +| `-DryRun` | Print actions only | diff --git a/docs/install/updating.md b/docs/install/updating.md index f94c2600776..e304fe0322b 100644 --- a/docs/install/updating.md +++ b/docs/install/updating.md @@ -65,7 +65,25 @@ openclaw update --channel dev openclaw update --channel stable ``` -Use `--tag ` for a one-off install tag/version. +Use `--tag ` for a one-off package target override. + +For the current GitHub `main` head via a package-manager install: + +```bash +openclaw update --tag main +``` + +Manual equivalents: + +```bash +npm i -g github:openclaw/openclaw#main +``` + +```bash +pnpm add -g github:openclaw/openclaw#main +``` + +You can also pass an explicit package spec to `--tag` for one-off updates (for example a GitHub ref or tarball URL). See [Development channels](/install/development-channels) for channel semantics and release notes. diff --git a/scripts/install.ps1 b/scripts/install.ps1 index ac30daf9cb5..fccf2fec06b 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -200,13 +200,15 @@ function Ensure-Git { } function Install-OpenClawNpm { - param([string]$Version = "latest") + param([string]$Target = "latest") + + $installSpec = Resolve-PackageInstallSpec -Target $Target - Write-Host "Installing OpenClaw (openclaw@$Version)..." -Level info + Write-Host "Installing OpenClaw ($installSpec)..." -Level info try { # Use -ExecutionPolicy Bypass to handle restricted execution policy - npm install -g openclaw@$Version --no-fund --no-audit 2>&1 + npm install -g $installSpec --no-fund --no-audit 2>&1 Write-Host "OpenClaw installed" -Level success return $true } catch { @@ -257,6 +259,34 @@ node "%~dp0..\openclaw\dist\entry.js" %* return $true } +function Test-ExplicitPackageInstallSpec { + param([string]$Target) + + if ([string]::IsNullOrWhiteSpace($Target)) { + return $false + } + + return $Target.Contains("://") -or + $Target.Contains("#") -or + $Target -match '^(file|github|git\+ssh|git\+https|git\+http|git\+file|npm):' +} + +function Resolve-PackageInstallSpec { + param([string]$Target = "latest") + + $trimmed = $Target.Trim() + if ([string]::IsNullOrWhiteSpace($trimmed)) { + return "openclaw@latest" + } + if ($trimmed.ToLowerInvariant() -eq "main") { + return "github:openclaw/openclaw#main" + } + if (Test-ExplicitPackageInstallSpec -Target $trimmed) { + return $trimmed + } + return "openclaw@$trimmed" +} + function Add-ToPath { param([string]$Path) @@ -301,9 +331,9 @@ function Main { } if ($DryRun) { - Write-Host "[DRY RUN] Would install OpenClaw via npm (tag: $Tag)" -Level info + Write-Host "[DRY RUN] Would install OpenClaw via npm ($((Resolve-PackageInstallSpec -Target $Tag)))" -Level info } else { - if (!(Install-OpenClawNpm -Version $Tag)) { + if (!(Install-OpenClawNpm -Target $Tag)) { exit 1 } } diff --git a/scripts/install.sh b/scripts/install.sh index 2abfbad9935..70c68bf703c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1011,7 +1011,7 @@ Options: --install-method, --method npm|git Install via npm (default) or from a git checkout --npm Shortcut for --install-method npm --git, --github Shortcut for --install-method git - --version npm install: version (default: latest) + --version npm install target (default: latest; use "main" for GitHub main) --beta Use beta if available, else latest --git-dir, --dir Checkout directory (default: ~/openclaw) --no-git-update Skip git pull for existing checkout @@ -1024,7 +1024,7 @@ Options: Environment variables: OPENCLAW_INSTALL_METHOD=git|npm - OPENCLAW_VERSION=latest|next| + OPENCLAW_VERSION=latest|next|main|| OPENCLAW_BETA=0|1 OPENCLAW_GIT_DIR=... OPENCLAW_GIT_UPDATE=0|1 @@ -1040,6 +1040,7 @@ Examples: curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard --verify + curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --version main curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git --no-onboard EOF } @@ -1963,6 +1964,43 @@ resolve_beta_version() { echo "$beta" } +is_explicit_package_install_spec() { + local value="${1:-}" + [[ "$value" == *"://"* || "$value" == *"#"* || "$value" =~ ^(file|github|git\+ssh|git\+https|git\+http|git\+file|npm): ]] +} + +can_resolve_registry_package_version() { + local value="${1:-}" + if [[ -z "$value" ]]; then + return 0 + fi + if [[ "${value,,}" == "main" ]]; then + return 1 + fi + if is_explicit_package_install_spec "$value"; then + return 1 + fi + return 0 +} + +resolve_package_install_spec() { + local package_name="$1" + local value="$2" + if [[ "${value,,}" == "main" ]]; then + echo "github:openclaw/openclaw#main" + return 0 + fi + if is_explicit_package_install_spec "$value"; then + echo "$value" + return 0 + fi + if [[ "$value" == "latest" ]]; then + echo "${package_name}@latest" + return 0 + fi + echo "${package_name}@${value}" +} + install_openclaw() { local package_name="openclaw" if [[ "$USE_BETA" == "1" ]]; then @@ -1983,18 +2021,16 @@ install_openclaw() { fi local resolved_version="" - resolved_version="$(npm view "${package_name}@${OPENCLAW_VERSION}" version 2>/dev/null || true)" + if can_resolve_registry_package_version "${OPENCLAW_VERSION}"; then + resolved_version="$(npm view "${package_name}@${OPENCLAW_VERSION}" version 2>/dev/null || true)" + fi if [[ -n "$resolved_version" ]]; then ui_info "Installing OpenClaw v${resolved_version}" else ui_info "Installing OpenClaw (${OPENCLAW_VERSION})" fi local install_spec="" - if [[ "${OPENCLAW_VERSION}" == "latest" ]]; then - install_spec="${package_name}@latest" - else - install_spec="${package_name}@${OPENCLAW_VERSION}" - fi + install_spec="$(resolve_package_install_spec "${package_name}" "${OPENCLAW_VERSION}")" if ! install_openclaw_npm "${install_spec}"; then ui_warn "npm install failed; retrying" diff --git a/src/cli/update-cli.test.ts b/src/cli/update-cli.test.ts index f2138215327..77593f876aa 100644 --- a/src/cli/update-cli.test.ts +++ b/src/cli/update-cli.test.ts @@ -549,6 +549,48 @@ describe("update-cli", () => { ); }); + it("maps --tag main to the GitHub main package spec for package updates", async () => { + const tempDir = createCaseDir("openclaw-update"); + mockPackageInstallStatus(tempDir); + + await updateCommand({ yes: true, tag: "main" }); + + expect(runGatewayUpdate).not.toHaveBeenCalled(); + expect(runCommandWithTimeout).toHaveBeenCalledWith( + [ + "npm", + "i", + "-g", + "github:openclaw/openclaw#main", + "--no-fund", + "--no-audit", + "--loglevel=error", + ], + expect.any(Object), + ); + }); + + it("passes explicit git package specs through for package updates", async () => { + const tempDir = createCaseDir("openclaw-update"); + mockPackageInstallStatus(tempDir); + + await updateCommand({ yes: true, tag: "github:openclaw/openclaw#main" }); + + expect(runGatewayUpdate).not.toHaveBeenCalled(); + expect(runCommandWithTimeout).toHaveBeenCalledWith( + [ + "npm", + "i", + "-g", + "github:openclaw/openclaw#main", + "--no-fund", + "--no-audit", + "--loglevel=error", + ], + expect.any(Object), + ); + }); + it("updateCommand outputs JSON when --json is set", async () => { vi.mocked(runGatewayUpdate).mockResolvedValue(makeOkUpdateResult()); vi.mocked(defaultRuntime.log).mockClear(); diff --git a/src/cli/update-cli.ts b/src/cli/update-cli.ts index 7f82f701c8a..529b65cd917 100644 --- a/src/cli/update-cli.ts +++ b/src/cli/update-cli.ts @@ -39,7 +39,10 @@ export function registerUpdateCli(program: Command) { .option("--no-restart", "Skip restarting the gateway service after a successful update") .option("--dry-run", "Preview update actions without making changes", false) .option("--channel ", "Persist update channel (git + npm)") - .option("--tag ", "Override npm dist-tag or version for this update") + .option( + "--tag ", + "Override the package target for this update (dist-tag, version, or package spec)", + ) .option("--timeout ", "Timeout for each update step in seconds (default: 1200)") .option("--yes", "Skip confirmation prompts (non-interactive)", false) .addHelpText("after", () => { @@ -48,6 +51,7 @@ export function registerUpdateCli(program: Command) { ["openclaw update --channel beta", "Switch to beta channel (git + npm)"], ["openclaw update --channel dev", "Switch to dev channel (git + npm)"], ["openclaw update --tag beta", "One-off update to a dist-tag or version"], + ["openclaw update --tag main", "One-off package install from GitHub main"], ["openclaw update --dry-run", "Preview actions without changing anything"], ["openclaw update --no-restart", "Update without restarting the service"], ["openclaw update --json", "Output result as JSON"], @@ -66,7 +70,7 @@ ${theme.heading("What this does:")} ${theme.heading("Switch channels:")} - Use --channel stable|beta|dev to persist the update channel in config - Run openclaw update status to see the active channel and source - - Use --tag for a one-off npm update without persisting + - Use --tag for a one-off package update without persisting ${theme.heading("Non-interactive:")} - Use --yes to accept downgrade prompts diff --git a/src/cli/update-cli/shared.ts b/src/cli/update-cli/shared.ts index d7cbc5ec86b..1f934f3c9be 100644 --- a/src/cli/update-cli/shared.ts +++ b/src/cli/update-cli/shared.ts @@ -10,6 +10,7 @@ import { trimLogTail } from "../../infra/restart-sentinel.js"; import { parseSemver } from "../../infra/runtime-guard.js"; import { fetchNpmTagVersion } from "../../infra/update-check.js"; import { + canResolveRegistryVersionForPackageTarget, detectGlobalInstallManagerByPresence, detectGlobalInstallManagerForRoot, type CommandRunner, @@ -77,6 +78,9 @@ export async function resolveTargetVersion( tag: string, timeoutMs?: number, ): Promise { + if (!canResolveRegistryVersionForPackageTarget(tag)) { + return null; + } const direct = normalizeVersionTag(tag); if (direct) { return direct; diff --git a/src/cli/update-cli/update-command.ts b/src/cli/update-cli/update-command.ts index b94fbd4ffb9..abc9c0080c7 100644 --- a/src/cli/update-cli/update-command.ts +++ b/src/cli/update-cli/update-command.ts @@ -24,6 +24,7 @@ import { checkUpdateStatus, } from "../../infra/update-check.js"; import { + canResolveRegistryVersionForPackageTarget, createGlobalInstallEnv, cleanupGlobalRenameDirs, globalInstallArgs, @@ -731,22 +732,31 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { let targetVersion: string | null = null; let downgradeRisk = false; let fallbackToLatest = false; + let packageInstallSpec: string | null = null; if (updateInstallKind !== "git") { currentVersion = switchToPackage ? null : await readPackageVersion(root); - targetVersion = explicitTag - ? await resolveTargetVersion(tag, timeoutMs) - : await resolveNpmChannelTag({ channel, timeoutMs }).then((resolved) => { - tag = resolved.tag; - fallbackToLatest = channel === "beta" && resolved.tag === "latest"; - return resolved.version; - }); + if (explicitTag) { + targetVersion = await resolveTargetVersion(tag, timeoutMs); + } else { + targetVersion = await resolveNpmChannelTag({ channel, timeoutMs }).then((resolved) => { + tag = resolved.tag; + fallbackToLatest = channel === "beta" && resolved.tag === "latest"; + return resolved.version; + }); + } const cmp = currentVersion && targetVersion ? compareSemverStrings(currentVersion, targetVersion) : null; downgradeRisk = + canResolveRegistryVersionForPackageTarget(tag) && !fallbackToLatest && currentVersion != null && (targetVersion == null || (cmp != null && cmp > 0)); + packageInstallSpec = resolveGlobalInstallSpec({ + packageName: DEFAULT_PACKAGE_NAME, + tag, + env: process.env, + }); } if (opts.dryRun) { @@ -772,7 +782,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { } else if (updateInstallKind === "git") { actions.push(`Run git update flow on channel ${channel} (fetch/rebase/build/doctor)`); } else { - actions.push(`Run global package manager update with spec openclaw@${tag}`); + actions.push(`Run global package manager update with spec ${packageInstallSpec ?? tag}`); } actions.push("Run plugin update sync after core update"); actions.push("Refresh shell completion cache (if needed)"); @@ -789,6 +799,9 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { if (fallbackToLatest) { notes.push("Beta channel resolves to latest for this run (fallback)."); } + if (explicitTag && !canResolveRegistryVersionForPackageTarget(tag)) { + notes.push("Non-registry package specs skip npm version lookup and downgrade previews."); + } printDryRunPreview( { @@ -803,7 +816,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { requestedChannel, storedChannel, effectiveChannel: channel, - tag, + tag: packageInstallSpec ?? tag, currentVersion, targetVersion, downgradeRisk, diff --git a/src/infra/update-global.test.ts b/src/infra/update-global.test.ts index 54cda49a407..3df6151e11c 100644 --- a/src/infra/update-global.test.ts +++ b/src/infra/update-global.test.ts @@ -4,11 +4,15 @@ import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { captureEnv } from "../test-utils/env.js"; import { + canResolveRegistryVersionForPackageTarget, cleanupGlobalRenameDirs, detectGlobalInstallManagerByPresence, detectGlobalInstallManagerForRoot, globalInstallArgs, globalInstallFallbackArgs, + isExplicitPackageInstallSpec, + isMainPackageTarget, + OPENCLAW_MAIN_PACKAGE_SPEC, resolveGlobalPackageRoot, resolveGlobalInstallSpec, resolveGlobalRoot, @@ -60,6 +64,40 @@ describe("update global helpers", () => { ); }); + it("maps main and explicit install specs for global installs", () => { + expect(resolveGlobalInstallSpec({ packageName: "openclaw", tag: "main" })).toBe( + OPENCLAW_MAIN_PACKAGE_SPEC, + ); + expect( + resolveGlobalInstallSpec({ + packageName: "openclaw", + tag: "github:openclaw/openclaw#feature/my-branch", + }), + ).toBe("github:openclaw/openclaw#feature/my-branch"); + expect( + resolveGlobalInstallSpec({ + packageName: "openclaw", + tag: "https://example.com/openclaw-main.tgz", + }), + ).toBe("https://example.com/openclaw-main.tgz"); + }); + + it("classifies main and raw install specs separately from registry selectors", () => { + expect(isMainPackageTarget("main")).toBe(true); + expect(isMainPackageTarget(" MAIN ")).toBe(true); + expect(isMainPackageTarget("beta")).toBe(false); + + expect(isExplicitPackageInstallSpec("github:openclaw/openclaw#main")).toBe(true); + expect(isExplicitPackageInstallSpec("https://example.com/openclaw-main.tgz")).toBe(true); + expect(isExplicitPackageInstallSpec("file:/tmp/openclaw-main.tgz")).toBe(true); + expect(isExplicitPackageInstallSpec("beta")).toBe(false); + + expect(canResolveRegistryVersionForPackageTarget("latest")).toBe(true); + expect(canResolveRegistryVersionForPackageTarget("2026.3.14")).toBe(true); + expect(canResolveRegistryVersionForPackageTarget("main")).toBe(false); + expect(canResolveRegistryVersionForPackageTarget("github:openclaw/openclaw#main")).toBe(false); + }); + it("detects install managers from resolved roots and on-disk presence", async () => { const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-global-")); const npmRoot = path.join(base, "npm-root"); diff --git a/src/infra/update-global.ts b/src/infra/update-global.ts index 4df88cc2221..e0dc9045f67 100644 --- a/src/infra/update-global.ts +++ b/src/infra/update-global.ts @@ -14,12 +14,41 @@ export type CommandRunner = ( const PRIMARY_PACKAGE_NAME = "openclaw"; const ALL_PACKAGE_NAMES = [PRIMARY_PACKAGE_NAME] as const; const GLOBAL_RENAME_PREFIX = "."; +export const OPENCLAW_MAIN_PACKAGE_SPEC = "github:openclaw/openclaw#main"; const NPM_GLOBAL_INSTALL_QUIET_FLAGS = ["--no-fund", "--no-audit", "--loglevel=error"] as const; const NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS = [ "--omit=optional", ...NPM_GLOBAL_INSTALL_QUIET_FLAGS, ] as const; +function normalizePackageTarget(value: string): string { + return value.trim(); +} + +export function isMainPackageTarget(value: string): boolean { + return normalizePackageTarget(value).toLowerCase() === "main"; +} + +export function isExplicitPackageInstallSpec(value: string): boolean { + const trimmed = normalizePackageTarget(value); + if (!trimmed) { + return false; + } + return ( + trimmed.includes("://") || + trimmed.includes("#") || + /^(?:file|github|git\+ssh|git\+https|git\+http|git\+file|npm):/i.test(trimmed) + ); +} + +export function canResolveRegistryVersionForPackageTarget(value: string): boolean { + const trimmed = normalizePackageTarget(value); + if (!trimmed) { + return true; + } + return !isMainPackageTarget(trimmed) && !isExplicitPackageInstallSpec(trimmed); +} + async function resolvePortableGitPathPrepend( env: NodeJS.ProcessEnv | undefined, ): Promise { @@ -68,7 +97,14 @@ export function resolveGlobalInstallSpec(params: { if (override) { return override; } - return `${params.packageName}@${params.tag}`; + const target = normalizePackageTarget(params.tag); + if (isMainPackageTarget(target)) { + return OPENCLAW_MAIN_PACKAGE_SPEC; + } + if (isExplicitPackageInstallSpec(target)) { + return target; + } + return `${params.packageName}@${target}`; } export async function createGlobalInstallEnv( diff --git a/src/infra/update-runner.test.ts b/src/infra/update-runner.test.ts index bb9be0d5be7..35716f84c2f 100644 --- a/src/infra/update-runner.test.ts +++ b/src/infra/update-runner.test.ts @@ -441,6 +441,20 @@ describe("runGatewayUpdate", () => { expect(calls.some((call) => call === expectedInstallCommand)).toBe(true); }); + it("updates global npm installs from the GitHub main package spec", async () => { + const { calls, result } = await runNpmGlobalUpdateCase({ + expectedInstallCommand: + "npm i -g github:openclaw/openclaw#main --no-fund --no-audit --loglevel=error", + tag: "main", + }); + + expect(result.status).toBe("ok"); + expect(result.mode).toBe("npm"); + expect(calls).toContain( + "npm i -g github:openclaw/openclaw#main --no-fund --no-audit --loglevel=error", + ); + }); + it("falls back to global npm update when git is missing from PATH", async () => { const { nodeModules, pkgRoot } = await createGlobalPackageFixture(tempDir); const { calls, runCommand } = createGlobalInstallHarness({