- Date: 2026-05-27
- Status: Resolved — decision is to defer. Not pending work. The ADR 0027 open question ("who reads
pages/{id}.layout.json?") is answered: no consumer is built until a user demands a public render URL. Today the artifact is audit-and-restore only. This is a deliberate, final decision per YAGNI — re-open only when a trigger below fires. - Affects:
apps/api/src/deploy.ts— author ofpages/{id}.layout.json- Future: a separate "render template" repo OR an in-ARNO renderer route
- References: ADR 0023 (Deploy pipeline), ADR 0027 (Zones unification),
packages/render-adapter/_index.md
Context
ADR 0027 left an explicit open question: the published pages/{id}.layout.json artifact has no reader.
Current ARNO has two render paths:
- Editor preview iframe —
packages/render-adapterpostMessage protocol. The ARNO parent sends the live composition tree to a sandboxed iframe that mounts real React components from the connected DS bundle. State flows in-memory, not via git. - Deploy button (ADR 0023) — writes
pages/{id}.layout.jsonto the connected repo. Atomic commit, idempotent. Nothing consumes the JSON.
After the user clicks Deploy, the JSON exists on main/staging, but no URL serves the rendered page. Until that gap closes, "Deploy" is a snapshot-without-publication: useful as audit trail and recovery point, but the user does not see a deployed product.
Decision
Defer the consumer choice. Today the JSON is an audit-and-restore artifact. The first user request for "show me my published site" will pick the path from the options below.
Why defer rather than build
- ARNO target audience (frontend builder, non-developers) does not currently ask for a public-facing rendered page — they edit and preview inside ARNO. The Deploy button satisfies a different need (commit-to-git for version control + handoff to engineers).
- Each option below carries non-trivial scope (new repo template, build pipeline, hosting decisions, render adapter coupling). Building speculatively risks lock-in to the wrong choice.
- ADR 0027 already ensures the JSON is correct (full zones, versioned, schema-stable). Whichever consumer we pick later reads the same artifact — no rework on the producer side.
Options on the table
| # | Path | Effort | Trade-offs |
|---|---|---|---|
| A | Static site generator in connected repo. New ARNO render template repo (Next.js / Astro) reads pages/*.json at build time, renders to HTML via the DS bundle, deploys to CF Pages / Vercel. ARNO Deploy = git commit; CI in connected repo = build + publish. | Medium. New repo template, framework choice, CI workflow, hosting per user. | Closest to "user clicks Deploy → sees site". Aligned with Vercel/Netlify pattern. Couples ARNO to a specific SSG choice. Slower to first preview (CI run). |
| B | Runtime fetch via CDN. Published JSON served as static asset (CF Pages serves the connected repo). ARNO itself adds a /render/{projectId}/{screenId} route that fetches the JSON + DS bundle and mounts the render adapter. | Small-medium. One new route in apps/web, no new repo. | Fastest path to "public URL renders the screen". No SSG needed. But ARNO becomes the runtime for user-facing pages — increases our cost surface, ties uptime of user sites to ours. |
| C | Audit-and-restore only. Acknowledge JSON has no runtime consumer. Document recovery procedure (restore composition from git into Postgres). Defer rendering until real demand. | Zero. Already where we are. | Honest about current scope. JSON still has value: version control, code review on changes, rollback via git. Forces explicit decision later (not silently broken). |
| D | GitHub Action codegen → TSX. Render JSON → TSX files in the same repo. Rejected by ADR 0023 spirit ("no codegen"). User-decided settled: ARNO does not produce code. | n/a | Out of scope per product positioning. |
Recommendation when the question becomes live
Option B first, then Option A as the user base grows:
- B is the cheapest path to a working
arno.app/render/{project}/{screen}URL. One Next.js route inapps/web, reuses existing render adapter, reuses existing JSON fetched from raw.githubusercontent.com (public repos) or via the GitHub App proxy (private repos). Users get shareable "see my prototype" links immediately. - A becomes worthwhile when users want custom domains, SEO, or to "own" their deployment outside ARNO infrastructure. That request is post-MVP. By then the JSON shape will have battle-tested under runtime fetch usage.
Do not implement B preemptively. Wait for the request. The first signal will be a user asking "how do I share my prototype with a stakeholder without giving them an ARNO login" — currently /share?token= (Phase 10) covers this for in-ARNO viewing. When that becomes insufficient, B is one route away.
Consequences
Positive:
- Deploy artifact is correct and stable (ADR 0027) — future consumer reads a known shape
- Scope creep blocked: no premature SSG, no premature CDN runtime
- Decision criteria explicit: revisit when user asks for public render URLs
Negative / debt:
- Deploy button semantics remain partly opaque to users ("you clicked deploy — what happened?"). Mitigation: button tooltip and post-deploy modal explain "committed to git, see [PR link]"
- No public-facing rendered URL until B or A lands. Acceptable for dogfood and B2B handoff workflows where the engineer pulls the JSON
Triggers to revisit:
- First user request for "public URL of my screen without ARNO login"
- First user request for "deploy my project to my own domain"
- Connected repo CI feature request (e.g. build-on-push)
- Any of these → re-open this ADR, pick B or A, supersede with ADR 0028a/b