* Plugins: add native ask dialog for before_tool_call hooks
Extend the before_tool_call plugin hook with a requireApproval return field
that pauses agent execution and waits for real user approval via channels
(Telegram, Discord, /approve command) instead of relying on the agent to
cooperate with a soft block.
- Add requireApproval field to PluginHookBeforeToolCallResult with id, title,
description, severity, timeout, and timeoutBehavior options
- Extend runModifyingHook merge callback to receive hook registration so
mergers can stamp pluginId; always invoke merger even for the first result
- Make ExecApprovalManager generic so it can be reused for plugin approvals
- Add plugin.approval.request/waitDecision/resolve gateway methods with
schemas, scope guards, and broadcast events
- Handle requireApproval in pi-tools via two-phase gateway RPC with fallback
to soft block when the gateway is unavailable
- Extend the exec approval forwarder with plugin approval message builders
and forwarding methods
- Update /approve command to fall back to plugin.approval.resolve when exec
approval lookup fails
- Document before_tool_call requireApproval in hooks docs and unified
/approve behavior in exec-approvals docs
* Plugins: simplify plugin approval code
- Extract mergeParamsWithApprovalOverrides helper to deduplicate param
merge logic in before_tool_call hook handling
- Use idiomatic conditional spread syntax in toolContext construction
- Extract callApprovalMethod helper in /approve command to eliminate
duplicated callGateway calls
- Simplify plugin approval schema by removing unnecessary Type.Union
with Type.Null on optional fields
- Extract normalizeTrimmedString helper for turn source field trimming
* Tests: add plugin approval wiring and /approve fallback coverage
Fix 3 broken assertions expecting old "Exec approval" message text.
Add tests for the /approve command's exec→plugin fallback path,
plugin approval method registration and scope authorization, and
handler factory key verification.
* UI: wire plugin approval events into the exec approval overlay
Handle plugin.approval.requested and plugin.approval.resolved gateway
events by extending the existing exec approval queue with a kind
discriminator. Plugin approvals reuse the same overlay, queue management,
and expiry timer, with branched rendering for plugin-specific content
(title, description, severity). The decision handler routes resolve calls
to the correct gateway method based on kind.
* fix: read plugin approval fields from nested request payload
The gateway broadcasts plugin approval payloads with title, description,
severity, pluginId, agentId, and sessionKey nested inside the request
object (PluginApprovalRequestPayload), not at the top level. Fix the
parser to read from the correct location so the overlay actually appears.
* feat: invoke plugin onResolution callback after approval decision
Adds onResolution to the requireApproval type and invokes it after
the user resolves the approval dialog, enabling plugins to react to
allow-always vs allow-once decisions.
* docs: add onResolution callback to requireApproval hook documentation
* test: fix /approve assertion for unified approval response text
* docs: regenerate plugin SDK API baseline
* docs: add changelog entry for plugin approval hooks
* fix: harden plugin approval hook reliability
- Add APPROVAL_NOT_FOUND error code so /approve fallback uses structured
matching instead of fragile string comparison
- Check block before requireApproval so higher-priority plugin blocks
cannot be overridden by a lower-priority approval
- Race waitDecision against abort signal so users are not stuck waiting
for the full approval timeout after cancelling a run
- Use null consistently for missing pluginDescription instead of
converting to undefined
- Add comments explaining the +10s timeout buffer on gateway RPCs
* docs: document block > requireApproval precedence in hooks
* fix: address Phase 1 critical correctness issues for plugin approval hooks
- Fix timeout-allow param bug: return merged hook params instead of
original params when timeoutBehavior is "allow", preventing security
plugins from having their parameter rewrites silently discarded.
- Host-generate approval IDs: remove plugin-provided id field from the
requireApproval type, gateway request, and protocol schema. Server
always generates IDs via randomUUID() to prevent forged/predictable
ID attacks.
- Define onResolution semantics: add PluginApprovalResolutions constants
and PluginApprovalResolution type. onResolution callback now fires on
every exit path (allow, deny, timeout, abort, gateway error, no-ID).
Decision branching uses constants instead of hard-coded strings.
- Fix pre-existing test infrastructure issues: bypass CJS mock cache for
getGlobalHookRunner global singleton, reset gateway mock between tests,
fix hook merger priority ordering in block+requireApproval test.
* fix: tighten plugin approval schema and add kind-prefixed IDs
Harden the plugin approval request schema: restrict severity to
enum (info|warning|critical), cap timeoutMs at 600s, limit title
to 80 chars and description to 256 chars. Prefix plugin approval
IDs with `plugin:` so /approve routing can distinguish them from
exec approvals deterministically instead of relying on fallback.
* fix: address remaining PR feedback (Phases 1-3 source changes)
* chore: regenerate baselines and protocol artifacts
* fix: exclude requesting connection from approval-client availability check
hasExecApprovalClients() counted the backend connection that issued
the plugin.approval.request RPC as an approval client, preventing
the no-approval-route fast path from firing in headless setups and
causing 120s stalls. Pass the caller's connId so it is skipped.
Applied to both plugin and exec approval handlers.
* Approvals: complete Discord parity and compatibility fallback
* Hooks: make plugin approval onResolution non-blocking
* Hooks: freeze params after approval owner is selected
* Gateway: harden plugin approval request/decision flow
* Discord/Telegram: fix plugin approval delivery parity
* Approvals: fix Telegram plugin approval edge cases
* Auto-reply: enforce Telegram plugin approval approvers
* Approvals: harden Telegram and plugin resolve policies
* Agents: static-import gateway approval call and fix e2e mock loading
* Auto-reply: restore /approve Telegram import boundary
* Approvals: fail closed on no-route and neutralize Discord mentions
* docs: refresh generated config and plugin API baselines
---------
Co-authored-by: Václav Belák <vaclav.belak@gendigital.com>
* gateway: make session:patch hook typed and non-blocking
* gateway(test): add session:patch hook coverage
* docs(gateway): clarify session:patch security note
* fix: address review feedback on session:patch hook
Remove unused createInternalHookEvent import and fix doc example
to use inline event.type check matching existing hook examples.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: isolate hook payload to prevent mutation leaking into response
Shallow-copy sessionEntry and patch in the session:patch hook event
so fire-and-forget handlers cannot mutate objects used by the
response path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: isolate session:patch hook payload (#53880) (thanks @graciegould)
---------
Co-authored-by: “graciegould” <“graciegould5@gmail.com”>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
- Sort providers alphabetically in docs.json nav
- Sort channels alphabetically in docs.json nav (slack before synology-chat)
- Add install/migrating-matrix to Maintenance nav section (was orphaned)
- Remove zh-CN/plugins/architecture from nav (file does not exist)
- Add Voice Call to channels index page
- Add missing providers to providers index (DeepSeek, GitHub Copilot, OpenCode Go, Synthetic)
- Sort providers index alphabetically
- Update stale claude-3-5-sonnet model reference to claude-sonnet-4-6 in webhook docs
- azure.md: "What you'll do" -> "What you will do"
- standing-orders.md: "Don't" -> "Avoid"
Per CLAUDE.md: avoid em dashes and apostrophes in headings because
they break Mintlify anchor links.
* docs: add delegate architecture guide for organizational deployments
Adds a guide for running OpenClaw as a named delegate for organizations.
Covers three capability tiers (read-only, send-on-behalf, proactive),
M365 and Google Workspace delegation setup, security guardrails, and
integration with multi-agent routing.
AI-assisted: Claude Code (Opus 4.6)
Based on: Production deployment at a 501(c)(3) nonprofit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: address review — add Google DWD warning, fix canvas in deny list
- Add security warning for Google Workspace domain-wide delegation
matching the existing M365 application access policy warning
- Add "canvas" to the security guardrails tool deny list for
consistency with the full example and multi-agent.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: fix Tier 1 description to match read-only permissions
Remove "draft replies (saved to Drafts folder)" from Tier 1 since
saving drafts requires write access. Tier 1 is strictly read-only —
the agent summarizes and flags via chat, human acts on the mailbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: fix oxfmt formatting for delegate-architecture and docs.json
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: fix broken links to /automation/standing-orders
Standing orders is a deployment pattern, not an existing doc page.
Replaced with inline descriptions and links to /automation/cron-jobs
and #security-guardrails anchor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: move hardening to prerequisites before identity provider setup
Restructure per community feedback: isolation, tool restrictions,
sandbox, hard blocks, and audit trail now come BEFORE granting any
credentials. The most dangerous step (tenant-wide permissions) no
longer precedes the most important step (scoping and isolation).
Also strengthened M365 and Google Workspace security warnings with
actionable verification steps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add standing orders guide and fix broken links
Add docs/automation/standing-orders.md covering:
- Why standing orders (agent autonomy vs human bottleneck)
- Anatomy of a standing order (scope, triggers, gates, escalation)
- Integration with cron jobs for time-based enforcement
- Execute-Verify-Report pattern for execution discipline
- Three production-tested examples (content, finance, monitoring)
- Multi-program architecture for complex agents
- Best practices (do's and don'ts)
Update delegate-architecture.md to link standing orders references
to the new page instead of dead links.
Add standing-orders to Automation nav group in docs.json (en + zh-CN).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: address review feedback on standing-orders
- P1: Clarify that standing orders should go in AGENTS.md (auto-injected)
rather than arbitrary subdirectory files. Add Tip callout explaining
which workspace files are bootstrapped.
- P2: Remove dead /concepts/personality-files link, replace with
/concepts/agent-workspace which covers bootstrap files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat(cron): support persistent session targets for cron jobs (#9765)
Add support for `sessionTarget: "current"` and `session:<id>` so cron jobs can
bind to the creating session or a persistent named session instead of only
`main` or ephemeral `isolated` sessions.
Also:
- preserve custom session targets across reloads and restarts
- update gateway validation and normalization for the new target forms
- add cron coverage for current/custom session targets and fallback behavior
- fix merged CI regressions in Discord and diffs tests
- add a changelog entry for the new cron session behavior
Co-authored-by: kkhomej33-netizen <kkhomej33-netizen@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Adds two new internal hook events that fire after media/link processing:
- message:transcribed: fires when audio has been transcribed, providing
the transcript text alongside the original body and media metadata.
Useful for logging, analytics, or routing based on spoken content.
- message:preprocessed: fires for every message after all media + link
understanding completes. Gives hooks access to the fully enriched body
(transcripts, image descriptions, link summaries) before the agent sees it.
Both hooks are added in get-reply.ts, after applyMediaUnderstanding and
applyLinkUnderstanding. message:received and message:sent are already
in upstream (f07bb8e8) and are not duplicated here.
Typed contexts (MessageTranscribedHookContext, MessagePreprocessedHookContext)
and type guards (isMessageTranscribedEvent, isMessagePreprocessedEvent) added
to internal-hooks.ts alongside the existing received/sent types.
Test coverage in src/hooks/message-hooks.test.ts.