Skip to content

Workspaces: add tab-scoped widget pub/sub#101841

Open
100yenadmin wants to merge 3 commits into
openclaw:mainfrom
100yenadmin:feat/dashboard-pubsub
Open

Workspaces: add tab-scoped widget pub/sub#101841
100yenadmin wants to merge 3 commits into
openclaw:mainfrom
100yenadmin:feat/dashboard-pubsub

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Approved custom widgets could not coordinate within a workspace tab. A filter widget could not drive a chart or table without introducing gateway persistence or cross-tab reach.

Why This Change Was Made

This rebuild ports the original #101841 feature delta onto the Workspaces architecture landed by #104139. It adds a parent-owned, in-memory broker and a bus:pubsub manifest capability. The host binds every connection to the rendered tab and widget identity; iframe messages can provide only a channel and strict JSON payload.

The rebuild also closes the old payload-limit bypass: values are validated as strict JSON, normalized before fanout, capped at 8 KiB on the exact forwarded representation, and rate-limited to 60 publishes per minute. Structured-clone-only values such as ArrayBuffer, cycles, and unsupported JSON values are rejected.

User Impact

  • Widgets on the same tab can publish and subscribe to shared channels.
  • Messages never cross tabs and never echo to the publisher.
  • Removing a widget or tab, moving a widget, or closing Workspaces tears down or rebinds its broker connection.
  • No gateway method, persistent store, dependency, or network permission is added.

Evidence

  • Rebased onto upstream main at 843e3c787806389cdaac884300e671fba658dab6 during the final recovery pass; all three commits range-diff identically while preserving current main's private capability constant and adding bus:pubsub.
  • Final-head focused Vitest: 26 extension + 65 UI tests passed (manifest, bridge, bus, iframe host, and workspace view).
  • Final-head extension/UI/UI-test TypeScript checks, scoped formatting, oxlint, and git diff --check passed.
  • Independent adversarial review found the structured-clone size bypass; the regression was fixed and covered.
  • Repository autoreview rerun after the fix: clean, no accepted/actionable findings.

Closes #101147.

@100yenadmin
100yenadmin requested a review from a team as a code owner July 7, 2026 17:57
@100yenadmin

Copy link
Copy Markdown
Contributor Author

On the dependency-guard check: stacked on the not-yet-merged Wave 1 (#101098), inheriting its single new-plugin pnpm-lock.yaml importer entry. No new dependency. Verified by the submitting orchestrator's own gate + adversarial security review: the 59 bus/bridge/host tests pass, tab-isolation is structural (a publish only ever consults the publisher's own tab bucket; tabSlug+subscriberId are host-bound, never child-supplied), ui:build + full oxlint clean. The 6 unrelated failures in the full suite are pre-existing browser-fixture flakes (terminal-panel / form-controls), reproduced on the clean base.

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@openclaw-barnacle openclaw-barnacle Bot added the app: web-ui App: web-ui label Jul 7, 2026
@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Dependency graph guard cleared

This PR no longer has blocked dependency graph changes. A future dependency graph change requires a fresh /allow-dependencies-change comment after the guard blocks that new head SHA.

  • Current SHA: 9fc036d9884fca4d5e1a0d7582e3cff44ad89912

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 13, 2026, 9:12 AM ET / 13:12 UTC.

Summary
Adds capability-gated, tab-scoped publish/subscribe messaging between approved Workspaces custom widgets.

PR surface: Source +324, Tests +338, Docs +5. Total +667 across 12 files.

Reproducibility: yes. for the review defect. The unchanged head retains a bridge-local limiter while the host can recreate the bridge for the same parent-owned widget connection, making reload a reproducible quota reset from source.

Review metrics: 1 noteworthy metric.

  • Widget protocol surface: 1 capability added; 3 inbound and 1 outbound message types added. The patch expands the approved hostile-widget contract, so compatibility and security semantics need explicit review before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #101147
Summary: This PR is the direct implementation candidate for the focused pub/sub issue; the roadmap and merged foundation provide context but do not replace it.

Members:

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

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Move publish quota state into the parent-owned widget connection and add reload regression coverage.
  • [P1] Add redacted real-browser proof of same-tab delivery, cross-tab isolation, no echo, reload handling, and teardown.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Tests and CI are supplemental only; the available PR body and comments do not provide inspectable after-fix browser proof of real widgets communicating with isolation, no echo, reload handling, and teardown. Add a redacted recording or linked artifact, update the PR body to trigger re-review, and ask a maintainer to comment @clawsweeper re-review if it does not run automatically.

Risk before merge

  • [P1] A hostile approved widget can reload its iframe between bursts and reset the bridge-local 60-publishes-per-minute limiter, weakening the stated abuse boundary.
  • [P1] The new widget manifest capability and postMessage protocol become a compatibility-sensitive extension contract once third-party widgets depend on their exact message, error, and lifecycle semantics.
  • [P1] The broker controls delivery targeting; real-browser evidence has not yet demonstrated same-tab delivery, cross-tab isolation, no echo, reload handling, and teardown together.

Maintainer options:

  1. Move quota ownership before merge (recommended)
    Store the rolling publish window in the parent bus connection and add reload regression coverage plus browser proof.
  2. Accept the weaker boundary
    Merge only after a Workspaces owner explicitly accepts and documents iframe reload as a fresh hostile-widget quota window.
  3. Pause pub/sub
    Remove or defer the manifest capability until its security and delivery lifecycle contracts have sufficient proof.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Preserve the 60-publishes-per-minute quota across iframe bridge recreation by owning quota state in the parent widget bus connection; add focused reload regression coverage without changing tab isolation, no-echo, payload limits, or teardown semantics.

Next step before merge

  • [P1] The quota-lifetime defect has a narrow mechanical repair suitable for automation, while real browser proof must still be supplied from an actual setup afterward.

Maintainer decision needed

  • Question: Should the 60-publish quota remain effective for the same rendered widget across iframe reloads?
  • Rationale: Agent-authored iframe code is treated as hostile, but the current limiter lifetime makes reload a quota reset; maintainers must confirm the permanent abuse-boundary contract.
  • Likely owner: steipete — The merged Workspaces foundation establishes the hostile-widget host and lifecycle boundary affected by this decision.
  • Options:
    • Persist quota in the parent (recommended): Own rolling quota state in the host-created bus connection until the widget is moved, removed, or its Workspaces view stops.
    • Accept reload resets: Document each iframe reload as a new quota window and explicitly accept the resulting higher effective publish rate.
    • Defer the capability: Keep bus:pubsub unavailable until the quota lifetime and browser proof are settled.

Security
Needs attention: Tab binding and strict-JSON forwarding are defensible, but reload-reset publish accounting weakens the hostile-widget abuse boundary.

Review findings

  • [P2] Keep the publish quota across iframe reloads — ui/src/components/workspace-custom-widget.ts:199
Review details

Best possible solution:

Make the parent-owned widget bus connection the canonical owner of identity, subscriptions, and rolling publish quota across iframe reloads, then prove the complete lifecycle with two real widgets in a browser.

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

Yes for the review defect. The unchanged head retains a bridge-local limiter while the host can recreate the bridge for the same parent-owned widget connection, making reload a reproducible quota reset from source.

Is this the best way to solve the issue?

No, not yet. Parent-brokered tab scoping is the right ownership model, but quota accounting must share that parent-owned identity and lifetime instead of living inside a reloadable bridge.

Full review comments:

  • [P2] Keep the publish quota across iframe reloads — ui/src/components/workspace-custom-widget.ts:199
    The host retains one parent bus connection but recreates createWidgetBridge when the iframe reloads, resetting bridge-local publish accounting. An approved hostile widget can therefore reload between bursts and exceed the stated 60-per-minute boundary. Move quota state into the parent-owned connection and cover bridge recreation in a regression test.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.91

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model internal, reasoning high; reviewed against 2a7132a43f53.

Label changes

Label justifications:

  • P2: This optional Workspaces feature has bounded scope, but its hostile-widget quota defect and missing browser proof should block merge.
  • merge-risk: 🚨 compatibility: The PR creates a new widget manifest capability and postMessage contract that external custom widgets may depend on.
  • merge-risk: 🚨 message-delivery: The new broker determines message recipients and must preserve tab isolation, no echo, and teardown across every lifecycle transition.
  • merge-risk: 🚨 security-boundary: The PR expands the interface available to hostile agent-authored iframes, and its current rate limit can be reset by iframe reload.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Tests and CI are supplemental only; the available PR body and comments do not provide inspectable after-fix browser proof of real widgets communicating with isolation, no echo, reload handling, and teardown. Add a redacted recording or linked artifact, update the PR body to trigger re-review, and ask a maintainer to comment @clawsweeper re-review if it does not run automatically.
Evidence reviewed

PR surface:

Source +324, Tests +338, Docs +5. Total +667 across 12 files.

View PR surface stats
Area Files Added Removed Net
Source 6 330 6 +324
Tests 5 342 4 +338
Docs 1 5 0 +5
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 12 677 10 +667

Security concerns:

  • [medium] Reload resets hostile-widget publish quota — ui/src/components/workspace-custom-widget.ts:199
    Untrusted iframe code can trigger bridge recreation while retaining the same rendered widget context, allowing repeated publish bursts beyond the documented per-minute limit.
    Confidence: 0.98

Acceptance criteria:

  • [P1] pnpm test ui/src/lib/workspace/bus.test.ts ui/src/lib/workspace/bridge.test.ts ui/src/components/workspace-custom-widget.test.ts.
  • [P1] pnpm check:changed -- ui/src/lib/workspace/bus.ts ui/src/lib/workspace/bus.test.ts ui/src/lib/workspace/bridge.ts ui/src/lib/workspace/bridge.test.ts ui/src/components/workspace-custom-widget.ts ui/src/components/workspace-custom-widget.test.ts.
  • [P1] Run a real browser scenario with two approved widgets proving same-tab delivery, no publisher echo, cross-tab denial, quota persistence after iframe reload, and teardown after widget or tab removal.

What I checked:

  • Current-main gap: Current main's Workspaces widget manifest and bridge support data and prompt capabilities but not the proposed bus capability, so the linked feature remains necessary. (extensions/workspaces/src/manifest.ts:203, 2a7132a43f53)
  • Unresolved prior finding: The live PR head is the same SHA reviewed when ClawSweeper found that iframe bridge recreation resets the publish quota; no subsequent commit can have repaired it. (ui/src/components/workspace-custom-widget.ts:199, 9fc036d9884f)
  • Architecture provenance: The current custom-widget host and Workspaces lifecycle were introduced through the merged Workspaces foundation, which this PR extends rather than supersedes. (ui/src/lib/workspace/bridge.ts:1, 0af846713749)
  • Proof gap: The PR body supplies focused tests, checks, and review claims but no linked after-fix browser recording or artifact demonstrating real widget delivery, isolation, reload behavior, and teardown. (9fc036d9884f)
  • Prepared artifact inspection blocked: The supplied proof manifest and contact sheets could not be opened because the read-only sandbox helper failed with bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted; the available GitHub context did not expose equivalent inspectable media.

Likely related people:

  • steipete: Authored and merged the current Workspaces foundation that owns the custom-widget bridge, hostile-iframe boundary, and view lifecycle extended by this PR. (role: introduced current behavior; confidence: high; commits: 0af846713749; files: ui/src/lib/workspace/bridge.ts, ui/src/components/workspace-custom-widget.ts, ui/src/pages/plugin/workspace-view.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.
Review history (15 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-10T08:48:58.111Z sha 46f8afc :: needs real behavior proof before merge. :: [P1] Rebind the bridge when host context changes | [P3] Remove the local carve spec from the branch
  • reviewed 2026-07-12T20:22:19.288Z sha 1603b86 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-12T20:31:24.599Z sha b4e8cd4 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-12T20:39:45.825Z sha b4e8cd4 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-13T07:24:13.656Z sha 18a5876 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-13T09:46:17.247Z sha 9a26d8e :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-13T12:39:27.129Z sha 9fc036d :: needs real behavior proof before merge. :: [P2] Keep the publish quota across iframe reloads
  • reviewed 2026-07-13T12:56:00.427Z sha 9fc036d :: needs real behavior proof before merge. :: [P2] Keep the publish quota across iframe reloads

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 7, 2026
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Fixed the P1 file-binding contract issue flagged here. resolveBinding (ui/src/lib/dashboard/index.ts) now calls dashboard.data.read with { binding } — the gateway's readParams whitelist accepts only that key, so the previous { path, pointer } call threw at runtime — and it returns the server's already-pointer-resolved data verbatim (the server applies the JSON pointer in resolveFileBinding; the client had been re-applying it, a double-resolve). The unit test had encoded the wrong contract (mocked the whole doc, asserted { path, pointer }); it's rewritten to assert the real gateway shape so a regression fails. The fix is in this PR's diff now and at the base #101098 the series stacks on.

The dependency-guard red and the large cumulative diff are both inherent to the base-first split (this stacks on the unmerged #101098; no new package enters the resolved graph — just the new plugin's lockfile importer entry needing the standard head-SHA authorization).

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@100yenadmin
100yenadmin force-pushed the feat/dashboard-pubsub branch from 46f8afc to 1603b86 Compare July 12, 2026 20:14
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation plugin: workspaces Agent-composable Workspaces plugin and removed size: XL labels Jul 12, 2026
@100yenadmin 100yenadmin changed the title Dashboard: inter-widget pub/sub — a tab-scoped, parent-brokered message bus Workspaces: add tab-scoped widget pub/sub Jul 12, 2026
@github-actions github-actions Bot removed the dependencies-changed PR changes dependency-related files label Jul 12, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 12, 2026
@100yenadmin
100yenadmin force-pushed the feat/dashboard-pubsub branch from 1603b86 to b4e8cd4 Compare July 12, 2026 20:24
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 12, 2026
@100yenadmin
100yenadmin force-pushed the feat/dashboard-pubsub branch from b4e8cd4 to 18a5876 Compare July 13, 2026 06:36
@clawsweeper clawsweeper Bot added the feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. label Jul 13, 2026
@100yenadmin
100yenadmin force-pushed the feat/dashboard-pubsub branch from 18a5876 to 9a26d8e Compare July 13, 2026 09:03
@100yenadmin
100yenadmin force-pushed the feat/dashboard-pubsub branch from 9a26d8e to 9fc036d Compare July 13, 2026 11:27
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 docs Improvements or additions to documentation feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. plugin: workspaces Agent-composable Workspaces plugin rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: L status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard: inter-widget pub/sub — a tab-scoped message bus

1 participant