Skip to content

docs(plans): in-pod browser view — scoping note (TASK-060) - #1229

Open
lilyshen0722 wants to merge 2 commits into
mainfrom
plans/in-pod-browser-view
Open

docs(plans): in-pod browser view — scoping note (TASK-060)#1229
lilyshen0722 wants to merge 2 commits into
mainfrom
plans/in-pod-browser-view

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

TASK-060, Sam's idea, assigned to this seat. A scoping note rather than a design — written under the 2026-08-24 UI freeze, so it proposes no v2 visual or layout change and says so up front.

The title's question mark is the right instinct

Widget is the correct taxonomic home — it's a declared ComponentType in backend/models/Installable.ts and ADR-001 describes it as Widget { location, url, scopes }, which is almost literally this feature. Nothing else in the taxonomy fits.

But that file is explicitly "pure scaffolding: schema + types + indexes. No services, routes, adapters", nothing reads components[].type === 'widget', and the Installable refactor is paused under ADR-011 with a reactivation trigger this task doesn't meet. So the decision isn't which component type — it's un-pause ADR-001 with this as the first widget, or build a one-off and migrate later.

The part that decides the feature isn't rendering

An iframe runs on the viewer's machine. That splits "render a live localhost/URL pane" into two features that look identical in a mock:

URL what the viewer sees
localhost:3000 their own localhost — a different machine
public/tunneled the page, if the target permits framing
Commonly-hosted the page

The localhost case works perfectly for a solo operator and silently shows a second viewer the wrong thing — their own dev server, or worse, an unrelated app on the same port presented as the agent's work. That's not a bug to fix later; it's the feature meaning two different things depending on who's looking.

The remote case is bounded by the target's X-Frame-Options / frame-ancestors, not ours, and DENY is the common default.

The reframe, and a cheaper first version

The question is "whose browser is running it, and does the viewer see what the author saw?" — and agents already have a browser. MCP Playwright is live on this seat (verified today by navigating to commonly.me and getting a real snapshot). So: the agent renders in its browser, attaches the image, a refresh action re-captures. One browser, same pixels for everyone, no iframe, no cross-origin question, no new component type.

Strictly less capable — not interactive, not continuously live. That trade is Sam's to make, which is why the note ends on the question rather than answering it:

"Let me watch the thing being built, live, on my screen" (per-viewer, unshareable) or "let the pod see what the agent sees" (shareable, buildable now)?

They pull in opposite directions, and the wrong pick costs a component type.

Incidental

This repo configures no helmet, no CSP, no frame-ancestors — so Commonly itself is framable. That's about us being embedded rather than us embedding, and it's noted in the doc as deserving a separate look, not folded into this.

Docs-only.

🤖 Generated with Claude Code

lilyshen0722 and others added 2 commits August 25, 2026 03:02
Sam's idea, assigned to this seat, and the title's question mark is the right
instinct: `Widget` IS the correct taxonomic home, and it has no runtime. It is a
declared ComponentType in Installable.ts, that file is explicitly scaffolding
only, and the taxonomy refactor is paused under ADR-011 — so the real choice is
un-pause vs one-off, not which type.

The finding that actually scopes the feature is that an iframe runs on the
VIEWER's machine. "Render a live localhost pane" therefore means two different
things depending on who is looking: it works perfectly for a solo operator and
silently shows a second viewer their OWN localhost. That is not a later bug, it
is the feature having two meanings.

Proposes a cheaper first version with no security surface: agents already have a
browser (MCP Playwright, verified live from this seat today), so the agent can
render in ITS browser and attach the image — one browser, same pixels for every
viewer. Strictly less capable, and the trade is Sam's to make, not mine.

Written under the UI freeze: proposes no visual or layout change, and says so.

Docs-only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t hid

@sprint-review checked the reachability half and found the conclusion right
off a wrong premise. "Widget has no runtime" holds — widgetLocation appears
only in its own declaration. "Installable.ts is scaffolding, nothing reads it"
does not: four consumers, one a live production route doing full CRUD.

I checked the surface the feature would render from and treated its emptiness
as a fact about the file. The render side is inert; the storage side ships.

That premise was hiding the thing that actually scopes the task. Marketplace
publish persists components from req.body after a single length check, and
widgetUrl has no scheme check, no allowlist, no length bound. The rows are
inert only because nothing renders them — so shipping a renderer makes every
widgetUrl already in the catalog live at once, and the validation has to land
first and independently rather than alongside the feature.

It also removes "un-pause ADR-001 vs one-off" as a clean either/or: the pause
covers the read path, so a one-off still writes into the live schema.

Finding is @sprint-review's; the wrong premise was mine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant