Lane 6 · Product proposal
Instead of deploying planning workbooks like this one to ad-hoc static hosts, make “publish a hosted page” a first-class WIN capability. WIN already persists job artifacts to MinIO/S3 and already renders live artifacts in an iframe shell — the missing half is immutable static pages, plus one naming umbrella so the Artifacts page can hold both without confusion.
The Artifacts page gains a Gallery section listing every hosted, viewable piece — each item an exhibit badged by kind: LIVE (backed by a running origin, may change under you) or PAGE (immutable static snapshot). “Live exhibit” and “static exhibit” both read naturally, and neither collides with existing WIN vocabulary (jobs, runs, workflows, skills, deliverables, canvas).
Same structure, warmer word. Slightly weaker: “showcase” suggests curation/best-of, while agents will also publish mundane QA worksheets.
No new noun; add kind: live | page to the artifact record and a filter chip row. Cheapest, but loses the chance to give hosted pages a memorable identity, and “artifact” keeps meaning both “output file” and “hosted page”.
| Piece | Design | Rides on |
|---|---|---|
| Storage | Static exhibit = one HTML file or a directory tree, uploaded content-addressed to MinIO/S3 (exhibits/<hash>/…); record row: slug, title, kind, version list, owner, source job id | MinIO already in compose; artifact persistence already exists |
| Serving | GET /a/:slug[/path] → S3 object, Cache-Control: immutable per version; slug → latest version; directory-shaped exhibits get index.html resolution (multi-page workbooks like this one just work) | Hono server |
| Security (the one hard requirement) | Serve exhibits from a separate origin (e.g. pages.bigwinbeta.olelabs.xyz) or with a strict sandbox CSP so exhibit JS can never read the dashboard’s win_session cookie. Never serve user-authored HTML on the app origin. | Cloudflare Tunnel already does host routing |
| Creation — agents | win artifacts publish ./output/report/ --title "…" --kind page from any job workspace; auto-registers the exhibit and returns the URL in the deliverable | win artifacts CLI namespace exists |
| Creation — users | “Publish as page” on any HTML job artifact; drag-drop upload on the Gallery section | Artifacts page UI |
| Creation — API/MCP | POST /api/me/exhibits (+ an MCP tool later) — keeps the three-audience principle honest | me-routes pattern |
| Versioning | Every publish = new immutable version; version picker in the shell; “what changed” = diff of file lists | content addressing |
| Live kind | Existing LiveArtifactShell items migrate into the Gallery with kind=LIVE unchanged | LiveArtifactShell.tsx |
launch:packet, readiness dashboards) that currently land in /tmp — publishing those as dated pages gives you deploy-time evidence with URLs, for free.Build the "static exhibits" MVP for WIN: first-class hosted static pages living beside the
existing live artifacts.
Scope (three thin slices, one PR each):
1. Spec: claim the next free spec number (bun run specs:numbers) for the exhibit model —
record {slug, title, kind: "live"|"page", versions[{hash, createdAt, files[]}], ownerEmail,
sourceJobId?}; hard requirement: exhibits are served from an isolated origin or sandbox CSP
so exhibit JS can never access the dashboard's win_session cookie. Index the spec in
docs/specs/README.md in the same change.
2. Serving: GET /a/:slug[/*path] on the server — resolves latest (or ?v=hash) version from
MinIO/S3 (exhibits/<hash>/...), directory-shaped exhibits resolve index.html,
Cache-Control immutable per version. Tests: slug resolution, version pinning, path
traversal rejection, index resolution.
3. Publish: `win artifacts publish <file-or-dir> --title ... --kind page` (CLI) calling
POST /api/me/exhibits (multipart or presigned-put) that content-addresses the upload and
creates/updates the exhibit row. Tests: single-file, directory, re-publish appends version.
Defer the Gallery UI and Freeze-to-Page. Follow repo rails (PR records, cross-package
typecheck, no orphan modules — the routes must be mounted).