Skip to content

Dashboard: widget write-back — a setState bridge capability + persisted widget state #101137

Description

@100yenadmin

Give widgets memory. One primitive that turns every custom widget from a view into a stateful app.

Part of the Modular Dashboard roadmap — see the tracker #101136. Builds on Wave 1 (#101093; PRs #101094 / #101097 / #101098).

Problem

Custom widgets today are read-only: the postMessage bridge lets a widget ask the parent for data, but there is no path to save anything. So an agent can build a chess game, a notes pad, or a kanban as a sandboxed widget — but it resets on every reload. Persistence is the difference between "a neat demo" and "a tool you actually use."

What this adds

  • A new bridge capability, dashboard:setState (+ getState), letting a widget persist a small, opaque blob of its own state.
  • Per-widget, jailed, size-capped storage — a widget can only read/write its own state, never another widget's.
  • Capability- and approval-gated: a widget declares state:persist in its manifest; the operator's existing approval covers it; no ambient grant.
  • State survives reload and rebroadcasts, so a widget open in two browsers stays consistent.

How it'd be built

Add dashboard:setState/getState to the WidgetInboundType union and the handleMessage switch in ui/src/lib/dashboard/bridge.ts (createWidgetBridge) — the bridge is confirmed read-only today, so this is a new, isolated inbound path. Gate it behind a manifest capability mirroring the existing prompt:send gate. Back it with a new gateway RPC pair (dashboard.widget.state.set / .get) in extensions/dashboard/src/gateway.ts that persists to a jailed, size-capped file under <stateDir>/dashboard/state/<widgetId>.json (reuse the store's atomic-write + path-jail idioms), then rebroadcast via broadcastChange. The sandbox is unchanged — the widget still holds no credential and reaches nothing but its own state, through the trusted parent.

Security

This widens the trust surface, so it ships with an adversarial review like the Wave 1 sandbox (#101098): path-jail on <widgetId>, a hard size cap, the capability gate, opaque-origin preserved, and confirmation that no other gateway method becomes reachable from the iframe. Each refuted attack becomes a regression test.

References

Tier 0 — multipliers. Unlocks the stateful notes/todo widget and agent-built games/apps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions