Guide

Put the Approval Gate at the Side Effect

May 30, 202617 min readUpdated September 13, 2026By OpenClawBlog Team

An OpenClaw assistant may read a ticket, ask a model to draft a reply, update a CRM field, and send a message. When those steps sit in one conversational turn, it is easy to put the human approval in the wrong place. A prompt at the beginning approves an intention. A prompt after the send is an audit notice. Neither is approval of the effect that actually occurred.

The practical boundary is after the last read-only step and after the workflow has resolved its target, but before the first external side effect. At that point a reviewer can inspect the exact action while the workflow still has no effect. This guide uses current OpenClaw documentation checked on 2026-09-13. The workflow designs and tests are proposed patterns; no local OpenClaw runtime was tested for this article.

The short answer: pause after preparation

A useful workflow has a visible handoff between preparation and execution:

  1. Admit the request through the channel, identity, and tool policy that should govern it.
  2. Read only the allowed context and gather the records needed to make a decision.
  3. Resolve the destination, record, operation, audience, and relevant preconditions.
  4. Build a concrete proposal: the message to send or the before-and-after data change.
  5. Run deterministic checks, then pause for approval.
  6. After approval, execute the same approved request. Do not ask the model to recreate it from a summary.
  7. Return a receipt that distinguishes success, refusal, expiry, and partial completion.

Put the gate before target resolution and the reviewer may approve a vague instruction such as send this to the customer. Put it after target resolution but before the send or write and the reviewer can see the recipient, record identifier, content, and proposed delta. Put it after the first effect and the workflow has already crossed the boundary.

This is also why a channel-level approval setting is not a complete design. It may identify who can resolve a prompt, while a tool policy decides whether the model can see a tool at all. OpenClaw describes tools as callable actions and says tool policy is enforced before the model call. If policy removes a tool, the model does not receive that tool schema. That is an early capability gate, not approval of one particular message or data change. See the OpenClaw tools overview.

OpenClaw has several different approval boundaries

The official plugin documentation separates optional tool exposure, plugin permission requests, exec approvals, Codex-native permissions, and MCP approval elicitations. They answer different questions. Treating them as one universal human-in-the-loop switch is how an approval can appear to exist while the actual send or write travels through another path.

MechanismBest place for the gateWhat it does not cover
Optional tool policyBefore the model sees a sensitive toolIt does not review the arguments of a call that is already allowed
Plugin permission requestAfter the model selects a plugin-owned tool, before OpenClaw executes itIt does not replace host exec policy or tool visibility rules
Exec approvalBefore a host command or shell-like operation runs on a Gateway or nodeIt does not automatically intercept every direct provider or message-tool call
Lobster checkpointInside a fixed multi-step pipeline, immediately before its declared side effectIt is optional, not enabled by default, and unavailable in sandboxed tool contexts

The plugin permission requests documentation says plugin approvals do not replace host exec approvals or optional tool allowlists. That separation is useful. It lets you choose a gate based on where authority actually lives instead of adding a generic confirmation message to the conversation.

Use Lobster when the workflow itself should pause

For a predictable sequence of reads, classification, proposal building, and execution, Lobster is the most direct OpenClaw-specific fit. Its documentation describes Lobster as a deterministic multi-step tool pipeline. Side effects such as send, post, and delete halt the pipeline until they are explicitly approved. A halted run returns a resume token, so the earlier read and preparation steps do not need to run again.

A proposed pipeline shape is:

read → classify → resolve target → prepare preview → approve → send or write

The important word is preview. The approval checkpoint should receive the final action list, not the original user request. For a message, the preview can contain the account, channel, recipient, subject, body, links, and attachments. For a data change, it can contain the service, record ID, current value, proposed value, and side effects. If the workflow has two effects, show two itemized effects instead of presenting one opaque button labelled approve workflow.

The documented Lobster result uses a needs_approval status with an approval request and resume token. Resuming with approval continues the pipeline; rejecting it cancels the run. This makes the boundary visible in the workflow state rather than relying on the model to remember that it should wait. See the Lobster documentation.

There are limits. Lobster is an optional plugin and is not installed or enabled by default. The documentation also says the embedded tool is disabled in sandboxed tool contexts. Treat installation, enabling, and the trust boundary of an in-process plugin as separate decisions. Do not describe the presence of a documented checkpoint as proof that every OpenClaw installation can use it.

Use a plugin hook for one custom send or write

If the important action belongs to a plugin, the per-call plugin approval hook is a better boundary than a free-form instruction in the skill text. OpenClaw says that before_tool_call runs after the model selects a tool and before OpenClaw executes it. That is the last point at which the system can show the selected arguments and stop the call.

A proposed custom flow looks like this:

model selects update_customer
before_tool_call checks the target and proposed delta
requireApproval shows the action and risk
allow-once continues with the same call
deny, timeout, cancellation, or missing route blocks it

The plugin API can attach a typed approval scope. The documentation gives message-send as an example with a destination, recipient count, recipient preview, and internal or external audience. It also gives external-post with a destination and public or restricted visibility. These fields help a reviewer understand the blast radius, but the documentation is explicit that scope is display-only. It does not grant permission or change the approval decision.

Keep the approval prompt bounded. The documented limits include a short title and description, and the guidance says not to put secrets, tokens, or private payloads into chat approval surfaces. For an external message or production data change, offer allow-once and deny unless the plugin has a deliberate, documented policy for future calls. A generic plugin hook does not automatically make allow-always a durable trust grant.

Timeouts, cancellation, malformed decisions, and the absence of an approval route fail closed for plugin approvals. The plugin configuration is also independent from approvals.exec. Enabling exec approval forwarding does not route plugin prompts, and enabling plugin forwarding does not change host exec policy. If a direct provider integration is not covered by a plugin hook or Lobster checkpoint, put the approval in the integration or controller that owns the final send function. Do not ask the model to promise that it will wait.

Do not stretch exec approval into a universal send gate

OpenClaw's exec approval documentation defines this mechanism around host commands and shell-like tools running on a Gateway or node. Policy, allowlists, and optional user approval must agree before the command runs. That is the right boundary when the external effect is performed by a host command, such as a carefully scoped CLI wrapper.

It is not a reason to assume that every direct message tool, provider API call, or plugin-owned write will pause. If an integration calls a provider directly, use its plugin approval path, a Lobster checkpoint, or an application-level wrapper. The decision should follow the actual execution path, not the name of the channel.

Exec approvals do contain an important model for binding approval to the reviewed request. For node execution, OpenClaw stores a canonical systemRunPlan containing the command and execution context. If the caller later changes the command, working directory, agent, or session after approval was created, the Gateway rejects the forwarded run as an approval mismatch. That is the behavior a custom message or data wrapper should aim to reproduce: execute the stored approved object, not a newly generated equivalent.

Be careful with persistent approvals. The CLI documentation says an exec allow-always grant is tied to the exact arguments and current working directory. Automation grants can remain until revoked unless an expiry is set. For outbound communication, deletion, permission changes, and production data updates, allow-once is usually the clearer starting decision. Read the advanced exec approval documentation when routing prompts to chat surfaces, and keep plugin approval routing separate.

Worked design: a reply and a record correction

Consider a support workflow. An agent reads a ticket and the matching customer record. It proposes two effects: send a confirmation email and change the customer's address in the support system. The following is a proposed action envelope, not an OpenClaw configuration field:

{"actionId":"support-1842-v3","effects":[{"kind":"message-send","account":"support-mailbox","recipient":"customer@example.invalid","body":"Your address change is ready for confirmation."},{"kind":"record-update","service":"support-system","recordId":"1842","expectedVersion":"17","changes":{"address":"new test address"}}],"expiresAt":"2026-05-30T12:00:00Z"}

The gate belongs after the agent has resolved the mailbox, recipient, record, and expected version. It should not sit before those values are known.

  1. Read. Give the agent only the ticket and record access needed for the proposal. If possible, keep send and write tools out of the model's visible tool set during this stage.
  2. Prepare. Show the exact message and the field delta. Mark inferred values as inferences. Include the account that will send the message and the service that will receive the write.
  3. Review. Ask the authorized operator to approve the two effects together only if the operator intends to approve both. If the email and record change have different owners, use separate approval records.
  4. Execute. Consume the stored proposal. Re-read the record or check its version immediately before writing when the provider supports that operation. If the record changed, reject the old proposal and prepare a new one.
  5. Report. Return separate results for the message and the record. A result that says workflow complete hides the important case where the email succeeded but the write failed.

If the two effects must be atomic, that requirement belongs to the downstream service or integration. An approval screen cannot create a transaction across two providers. Where atomicity is unavailable, design for explicit partial completion and a documented compensation or manual recovery path.

What the reviewer needs to see

An approval card should answer the question what will happen if I allow this now. Include:

  • the action kind and destination;
  • the exact recipient, record, account, or endpoint;
  • the complete message or a readable before-and-after diff;
  • values inferred by the agent and the sources used to derive them;
  • attachments, links, notifications, and other known side effects;
  • the expiry time and the decisions available;
  • the identity approving the action and the identity that will execute it;
  • the rollback or partial-failure path.

Do not confuse a typed scope summary with the payload itself. OpenClaw's plugin documentation calls scope optional and display-only. A summary such as three external recipients is useful, but it does not prove that the body, attachment, or recipient list is correct. For host commands, the exec approval surface shows the command and working directory, while node approvals bind the stored execution plan. Use the same level of specificity for custom actions.

Failure paths to design before the happy path

Timeout or no approval route

A plugin approval timeout or missing route blocks the call. Preserve the proposal if the operator may review it later, but do not silently fall back to an unapproved send path. For a Lobster run, retain the resume token and its state according to the documented runtime. A closed approval surface should produce a held action, not an automatic retry.

Payload drift

If the recipient, record version, account, command, or message body changes after approval, invalidate the decision. For host-node exec, OpenClaw rejects several changed context fields. A custom wrapper should compare the stored proposal with the request it is about to execute, using a stable action ID and, where appropriate, a digest. This is a proposed integration control, not a claim about a built-in universal message transaction.

Duplicate approval

Use the complete approval ID. The OpenClaw approvals CLI reference says repeated resolution with the same decision is treated as already resolved, while a conflicting or expired decision fails. That protects the approval record, but the downstream provider still needs its own idempotency behavior. Keep a provider request ID or equivalent receipt when one exists.

Standing trust grows unnoticed

A durable grant can outlive the person who originally approved it. List and revoke standing grants during maintenance, and do not offer persistent approval for a high-consequence action merely to reduce prompts. If a workflow needs recurring autonomy, define the exact operation, scope, expiry, owner, and revocation path first.

Partial completion

For a bulk update, record the intended count before execution and the result for each item afterward. If five records changed and one failed, leave the failed item visible. Do not rerun the whole batch from the model's memory unless the integration can prove which items were already applied.

Prompt injection

Approval protects the final action only if the reviewer treats the proposal as untrusted input to inspect. OpenClaw's prompt-injection guidance says that emails, documents, browser pages, fetched content, attachments, and pasted logs can carry adversarial instructions even when only one trusted person can message the bot. Keep high-risk tools limited, separate reader work from execution where possible, and never let instructions inside a source document rewrite the approval policy.

Prerequisites and decision checklist

Before adding an approval gate, have these facts written down:

  • which OpenClaw agent, channel, tools, skills, plugins, and external services are involved;
  • which steps are read-only, which prepare a proposal, and which create an external effect;
  • which mechanism owns the final effect: Lobster, a plugin, host exec, or your integration code;
  • which person or role may approve each action type;
  • how proposal state, expiry, approval, execution, and receipts are stored;
  • what the downstream service guarantees about idempotency, record versions, rate limits, and rollback.

Then ask six questions:

  1. Can the reviewer identify the exact target and payload?
  2. Does approval happen before the first send, post, delete, or write?
  3. Will execution use the reviewed payload without model regeneration?
  4. Will a stale record or changed recipient force a new review?
  5. Does timeout, cancellation, or a missing approval route end in no execution?
  6. Can the operator tell the difference between rejected, expired, failed, and partially completed?

If the answer to any of these is no, keep the workflow in draft or read-only mode until the missing boundary is explicit.

Proposed tests and limits

These are proposed acceptance tests, not results from a hands-on OpenClaw run:

  • Approve a message, change its recipient before execution, and confirm that the old approval is rejected.
  • Approve a data update, change the record version, and confirm that the write stops.
  • Submit the same approval twice and confirm one provider-side effect.
  • Let the approval expire and confirm that no send or write occurs.
  • Disable the approval route after proposal creation and confirm that the action remains held.
  • Place an instruction to ignore policy in a synthetic source document and confirm that it cannot change the gate.
  • Make one item in a bulk operation fail and confirm that the result names the partial outcome.

These tests exercise the intended boundary; they do not certify the security of a deployment. OpenClaw documentation cannot establish your provider's transaction semantics, the correctness of your custom wrapper, the permissions of the executing account, or the behavior of a plugin you have not inspected. Lobster's checkpoint, a plugin approval prompt, and an exec approval are useful controls with different scopes. The remaining work is to connect the control to the exact function that can cause the external effect.

Keep the gate where choice becomes effect

Do not interrupt every read. Let OpenClaw collect the permitted context and prepare a bounded proposal. Pause once the target and payload are final, show the reviewer what will happen, and execute only that reviewed object. Use Lobster for a fixed pipeline, a plugin approval hook for a custom tool, and exec approval for a host command. If the final provider call sits outside those mechanisms, put the gate in the integration that owns it. The word approval matters only when the operation that can send or change data cannot pass around it.

Sources

All sources were accessed on 2026-09-13. The official documentation pages used here do not show publication dates, so the publication-date fields are empty.

Reference Trail

Sources and further reading

  1. OpenClaw tools overviewdocs.openclaw.ai
  2. plugin permission requests documentationdocs.openclaw.ai
  3. Lobster documentationdocs.openclaw.ai
  4. exec approval documentationdocs.openclaw.ai
  5. advanced exec approval documentationdocs.openclaw.ai
Back to ArchiveMore: GuidesNext: OpenClaw v2026.5.28: Channel delivery and session identity got safer, operator field notes