Skip to content

feat(approvals): add external verification contract#113517

Open
Guardiola31337 wants to merge 3 commits into
openclaw:mainfrom
Guardiola31337:feat/external-verification-approvals
Open

feat(approvals): add external verification contract#113517
Guardiola31337 wants to merge 3 commits into
openclaw:mainfrom
Guardiola31337:feat/external-verification-approvals

Conversation

@Guardiola31337

@Guardiola31337 Guardiola31337 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

OpenClaw plugins can request a generic approval, but they cannot present a bounded provider-neutral path for completing that approval through an external ceremony. RFC #15 accepted that separation: core must own the approval and immutable lifecycle while a plugin owns provider policy and proof handling.

Why This Change Was Made

  • Add the reviewer-safe external-verification approval contract accepted in RFC #15 and tracked by #82336.
  • Add a bounded plugin-owned label and allow-once / allow-always choice model to internal approval requests and Gateway presentation snapshots.
  • Validate and sanitize the projection before it reaches clients; malformed or spoofing-prone metadata fails closed.
  • Keep this first PR additive and independently safe: it does not advertise a new command, suppress existing approval actions, start a verifier, or change approval resolution behavior.

Why this is focused

The earlier implementation branch combined 56–96 files depending on the revision. This PR is now the first slice of a prepared stack:

  1. Contract and projection (this PR): 10 files, 197 additions, 2 deletions; OpenClaw size S (the generated SDK hash is excluded by the repository labeler).
  2. Durable host attempt ledger: prepared on feat/external-verification-state.
  3. Plugin SDK and text-command runtime: prepared on feat/external-verification-runtime.
  4. Generation-bound native/TUI actions: prepared on feat/external-verification-tui.

The full stack keeps World-specific policy, proofs, and secrets in the AgentKit plugin. Core receives only the provider-neutral host contract required by the RFC.

Contract boundary

  • External resolution metadata is trusted in-process plugin metadata; public Gateway callers cannot inject it.
  • Labels are single-line, spoof-resistant, and bounded to 80 Unicode code points after sanitization.
  • Decisions are a unique, non-empty subset of allow-once and allow-always.
  • Gateway and Swift projections expose only the bounded label and choices—never proof material, verifier secrets, or provider-specific payloads.
  • Existing generic approval behavior is unchanged until the later runtime PR lands the executable path and its E2E tests together.

Evidence

  • node scripts/run-vitest.mjs packages/gateway-protocol/src/approvals-validators.test.ts src/infra/approval-presentation.test.ts
    • 20 tests passed across two Vitest shards.
  • pnpm plugin-sdk:api:check
  • pnpm deadcode:exports
  • node scripts/run-vitest.mjs test/scripts/plugin-sdk-surface-report.test.ts
  • Full prepared stack:
    • 86 focused Gateway/TUI/protocol tests passed after rebasing onto current main.
    • pnpm plugin-sdk:api:check passed.
    • pnpm build passed, including all 142 public plugin SDK paths and the Control UI performance gate.
  • $autoreview --mode branch --base origin/main: TruffleHog clean; no accepted/actionable findings.
  • git diff --check passed.

Full-stack behavior proof

The companion AgentKit implementation and prepared core stack were also exercised as a normal user in an isolated OpenClaw home with a physical Pixel 3 and production World App. Allow-once resumed the exact blocked command only after World verification; Deny prevented execution; a failed/expired ceremony could be retried; session trust bypassed the second matching action in the same session; and a new session was gated again. This evidence validates the accepted contract while keeping this first PR reviewably inert.

Behavior addressed: Define the bounded provider-neutral external-resolution metadata that later host-owned attempt and runtime PRs consume.

Real environment tested: This additive contract was tested as part of the full isolated Gateway, TUI, AgentKit, physical Pixel 3, and production World App stack.

Exact steps or command run after this patch: Run the focused contract tests above; on the prepared full stack, ask OpenClaw to execute a protected marker command, select Verify once, scan and approve in World App, then verify terminal output and the proof-free SQLite ledger.

Evidence after fix: Contract tests reject malformed choices and spoofing labels; the full-stack ceremony resumes only the exact host-bound action after successful plugin completion.

Observed result after fix: Existing approval behavior remains unchanged in this PR alone, while the prepared stack successfully provides allow-once, denial, retry, session trust, and cross-session isolation.

What was not tested: No package publish, release, or version bump was performed. This first slice intentionally does not execute an external ceremony by itself; the subsequent focused PRs are required for runtime behavior.

@Guardiola31337
Guardiola31337 requested a review from a team as a code owner July 25, 2026 05:41
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime cli CLI command changes agents Agent runtime and tooling size: XL labels Jul 25, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 25, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 25, 2026
@clawsweeper

clawsweeper Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 26, 2026, 12:28 AM ET / 04:28 UTC.

ClawSweeper review

What this changes

This PR adds sanitized external-verification labels and allow-once/allow-always choices to plugin approval presentations, Gateway protocol schemas, and generated Swift Gateway models without changing current approval resolution.

Merge readiness

⚠️ Ready for maintainer review - 3 items remain

Keep this PR open for maintainer review. The patch is a focused, additive implementation of the accepted external-verification design, but it publishes a new Gateway/native-client approval contract before the companion plugin-SDK and runtime slices land; a maintainer should explicitly confirm that this exact contract is intended to be stable independently.

Priority: P2
Reviewed head: 47c81b002958b074e2016ea3fe5cd5b24dceff6c
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A focused, tested additive contract with credible real-stack evidence; remaining readiness is the maintainer choice to freeze a public Gateway/client shape before its companion runtime slices.
Proof confidence 🐚 platinum hermit (4/6) Sufficient (terminal): The PR body supplies after-fix focused contract-test results and a redacted real isolated Gateway/TUI/physical-World-App run for the prepared full stack; this contract-only slice intentionally leaves the executable ceremony to later PRs.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The PR body supplies after-fix focused contract-test results and a redacted real isolated Gateway/TUI/physical-World-App run for the prepared full stack; this contract-only slice intentionally leaves the executable ceremony to later PRs.
Evidence reviewed 6 items Focused contract boundary: The patch adds a closed Gateway schema containing only a bounded label and a unique non-empty set of allow-once/allow-always decisions; it does not add proof payloads or an external completion endpoint.
Host-side fail-closed projection: Invalid labels and decision lists cause the plugin approval presentation builder to return no presentation, keeping malformed external metadata out of Gateway snapshots.
Protocol and native-client exposure: The new optional field is exported through the protocol registry and generated Swift model, making its shape a compatibility commitment for Gateway consumers.
Findings None None.
Security None None.

How this fits together

Plugins create approval requests that OpenClaw’s host converts into a safe presentation for Gateway clients. This change carries bounded external-verification metadata through that presentation while the host continues to own approval identity, lifecycle, and resolution.

flowchart LR
  Plugin[Plugin approval request] --> Sanitizer[Host sanitizes external metadata]
  Sanitizer --> Presentation[Approval presentation]
  Presentation --> Gateway[Gateway protocol snapshot]
  Gateway --> Clients[Web and native clients]
  Clients --> Host[Existing host approval resolution]
Loading

Decision needed

Question Recommendation
Should OpenClaw publish this provider-neutral external-verification Gateway contract as a stable additive API now, or defer it until the companion plugin-SDK and executable runtime slices are ready? Publish the stable foundation now: Merge the additive contract and treat its bounded label and decision shape as a compatibility commitment for the subsequent implementation slices.

Why: The patch is intentionally inert but exposes generated client-facing protocol data; source review cannot determine whether maintainers want to freeze that public contract independently of the rest of the accepted design.

Before merge

  • Resolve merge risk (P1) - Merging publishes an optional Gateway and generated native-client contract before the companion plugin-SDK and runtime behavior land; future slices must preserve this exact field shape or provide an explicit compatibility path.
  • Complete next step (P2) - A maintainer must decide whether this generated Gateway/client contract should be stabilized independently; there is no narrow mechanical repair to dispatch.
Agent review details

Security

None.

PR surface

Source +62, Tests +111, Generated 0, Other +22. Total +195 across 10 files.

View PR surface stats
Area Files Added Removed Net
Source 6 62 0 +62
Tests 2 111 0 +111
Docs 0 0 0 0
Config 0 0 0 0
Generated 1 1 1 0
Other 1 23 1 +22
Total 10 197 2 +195

Review metrics

None.

Stored data model

Persistent data-model change detected: vector/embedding metadata: src/infra/approval-presentation.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #82336
Summary: This PR is a candidate implementation slice for the canonical external-HITL plugin approval tracker, which explicitly remains open until the core and AgentKit implementations land.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge-risk options

Maintainer options:

  1. Confirm the contract as stable before merge (recommended)
    Approve the generated Gateway and Swift model as an additive public compatibility commitment, with subsequent slices required to preserve it.
  2. Defer the public projection
    Pause this slice and bring the protocol field forward with the first plugin-SDK and runtime implementation that consumes it.

Technical review

Best possible solution:

Land this only after an owner confirms that the bounded externalResolution Gateway shape is the intended stable foundation for the remaining SDK, durable-attempt, and runtime slices; otherwise land the public contract together with the first executable owner path.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this PR introduces an additive approval contract rather than repairing a currently broken behavior. Its focused validator and presentation tests provide a clear source-level verification path for the contract.

Is this the best way to solve the issue?

Unclear pending maintainer intent: the code is a narrow implementation of the accepted design, but publishing its Gateway/native-client shape separately from the SDK and runtime is a product and compatibility-timing choice.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3f27d76ea7dc.

Labels

Label changes:

  • remove merge-risk: 🚨 security-boundary: Current PR review merge-risk labels are merge-risk: 🚨 compatibility.

Label justifications:

  • P2: This is a bounded feature addition to the approval/Gateway surface, with meaningful but non-emergency impact.
  • merge-risk: 🚨 compatibility: The patch adds an exported Gateway schema and generated Swift model that clients may compile against before the executable feature arrives.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • feature: ✨ showcase: ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. The provider-neutral, host-owned approval boundary enables external human-verification plugins without moving verifier secrets or final approval authority into core.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body supplies after-fix focused contract-test results and a redacted real isolated Gateway/TUI/physical-World-App run for the prepared full stack; this contract-only slice intentionally leaves the executable ceremony to later PRs.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies after-fix focused contract-test results and a redacted real isolated Gateway/TUI/physical-World-App run for the prepared full stack; this contract-only slice intentionally leaves the executable ceremony to later PRs.

Evidence

What I checked:

  • Focused contract boundary: The patch adds a closed Gateway schema containing only a bounded label and a unique non-empty set of allow-once/allow-always decisions; it does not add proof payloads or an external completion endpoint. (packages/gateway-protocol/src/schema/approvals.ts:75, 47c81b002958)
  • Host-side fail-closed projection: Invalid labels and decision lists cause the plugin approval presentation builder to return no presentation, keeping malformed external metadata out of Gateway snapshots. (src/infra/approval-presentation.ts:45, 47c81b002958)
  • Protocol and native-client exposure: The new optional field is exported through the protocol registry and generated Swift model, making its shape a compatibility commitment for Gateway consumers. (apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift:14457, 47c81b002958)
  • Focused regression coverage: The PR adds protocol validation tests for valid metadata, empty labels, unsupported decisions, and rejected extra proof fields, plus host-presentation sanitization tests. (packages/gateway-protocol/src/approvals-validators.test.ts:61, 47c81b002958)
  • Canonical implementation tracker: The linked tracker describes this PR as one part of the host-owned external-verification implementation and remains open until the core and companion AgentKit implementations land.
  • Review continuity: The previous ClawSweeper cycle at commit 66806d7 found no line-level defect and identified the independent public-contract timing decision; the current head narrows that same contract slice. (66806d77dbb9)

Likely related people:

  • Guardiola31337: Authored this PR, the open external-HITL approval tracker, and the linked companion AgentKit implementation, providing the strongest available ownership signal for this contract proposal. (role: proposal and companion-plugin owner; confidence: high; commits: f9d7f775623c, 66806d77dbb9, 47c81b002958; files: packages/gateway-protocol/src/schema/approvals.ts, src/infra/approval-presentation.ts, src/infra/plugin-approvals.ts)
  • icophy: The discussion supplied a concrete invocation-time approval-policy question that the author answered in terms of the proposed host/plugin boundary. (role: adjacent approval-policy contributor; confidence: medium)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Obtain explicit maintainer confirmation of whether this standalone Gateway contract is the intended stable compatibility surface.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (13 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-25T14:08:22.272Z sha 8dd9604 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-25T15:00:29.467Z sha afd9ce0 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-25T17:55:01.087Z sha 0f46fb4 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-25T18:37:30.375Z sha 0f46fb4 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-25T19:20:37.984Z sha 0f46fb4 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-25T22:44:44.399Z sha d0bb8a7 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-26T01:14:31.606Z sha cac2e38 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-26T03:31:36.422Z sha 66806d7 :: needs maintainer review before merge. :: none

@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from 8b5aeca to 53495d1 Compare July 25, 2026 06:02
@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts and removed triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jul 25, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 25, 2026
@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from 87ece8b to 33e873f Compare July 25, 2026 07:58
@icophy

icophy commented Jul 25, 2026

Copy link
Copy Markdown

This is a meaningful implementation — the "first-answer-wins" resolution model with Gateway-owned approval state is the right boundary for plugin-external verification ceremonies.

One operational pattern we've found useful running OpenClaw with a persistent agent (Cophy) that has a tiered autonomy model: the exact-session grants you mention in the evidence (vs. daily/reset revocation) maps closely to what we call "green/yellow/red zone" actions. Green-zone actions (reading files, running non-destructive commands) need no approval gate at all; yellow-zone actions (sending messages, modifying configs) benefit from an exact-session grant that expires at conversation end; red-zone actions (deleting data, deploying to production) should require a fresh approval per invocation regardless of prior grants.

The practical challenge we've hit: the agent's task context changes what zone an action falls into. Sending a message is normally yellow, but becomes effectively red if it's the first external message to a new recipient. Does the external verification contract in RFC #15 allow plugins to escalate the required grant level at invocation time? Or does the plugin's verifier only confirm/deny a fixed approval category declared at registration?

The reviewer authorization model (signed completion, 401 for unsigned challenge, 200 only over pinned TLS) looks robust — particularly the separation between "who can approve" and "Gateway owns the approval ID." That boundary prevents a class of TOCTOU vulnerabilities where a plugin could issue its own completion.


Context: Running OpenClaw as a persistent agent host; approval boundary design is one of the harder operational problems at longer agent session durations.

@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from 33e873f to 8dd9604 Compare July 25, 2026 08:47
@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from 8dd9604 to af81eb0 Compare July 25, 2026 14:45
@clawsweeper clawsweeper Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jul 25, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. and removed triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jul 25, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 25, 2026
@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from d0bb8a7 to 216261e Compare July 26, 2026 01:01
@openclaw-barnacle openclaw-barnacle Bot removed app: android App: android cli CLI command changes extensions: codex labels Jul 26, 2026
@Guardiola31337
Guardiola31337 force-pushed the feat/external-verification-approvals branch from cac2e38 to 66806d7 Compare July 26, 2026 03:26
@openclaw-barnacle openclaw-barnacle Bot added size: M and removed docs Improvements or additions to documentation scripts Repository scripts agents Agent runtime and tooling size: XL labels Jul 26, 2026
@Guardiola31337 Guardiola31337 changed the title feat(plugins): add external verification approvals feat(approvals): add external verification contract Jul 26, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 26, 2026
@Guardiola31337

Copy link
Copy Markdown
Contributor Author

Yes—the accepted contract allows the plugin to choose the required level at invocation time from the actual before_tool_call context, including tool arguments and plugin-owned policy state.

For a concrete invocation, the plugin can:

  • return no approval requirement for a green action;
  • request external verification with only allow-once for a red action; or
  • offer allow-once plus allow-always for an action eligible for exact-session trust.

So “first message to a new recipient” can be classified differently from later messages even though the tool name is the same. Core intentionally does not define green/yellow/red policy.

The important boundary is that classification happens before the host creates the approval. Once created, the request and selected decision are host-bound and immutable: the verifier can complete only that exact attempt and cannot escalate allow-once into session trust. A changed classification requires a new invocation/approval.

This focused first PR adds only the bounded contract/projection. The prepared runtime PR lands the before_tool_call wiring and executable text-command path together with the invocation-time tests.

@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. label Jul 26, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 26, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. label Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants