Arising from int-0002 — Zero-ceremony operation — one binary, no server, no daemon
Surfaces are server-rendered Go templates and static output — no SPA, no dira-operated host
Two questions, one answer, because they share a reasoning core: **nothing dira renders requires a client runtime or a server dira operates.**
`dira ui` — server-rendered templates, not an SPA
Go `html/template` + `embed.FS`, served from the binary on localhost. JavaScript only as progressive enhancement, and only on `/distill` where disposition benefits from keyboard handling. Every page must render and be usable with JS disabled.
This is not a preference. The design that already exists *is* server-renderable: the three screens in `docs/design/screens/` were built with zero JavaScript, and the `.chain-stack` mobile variant is a CSS media query rather than a component swap. An SPA would add a runtime and a JSON API layer to serve markup that is already static — and it would break the one channel the growth loop depends on.
The public renderer — `dira render`, deployed by the user
`dira render` emits static HTML the user pushes wherever they already publish, GitHub Pages being the obvious default since `dec-0005` already established GitHub as the infrastructure the user brings.
**This makes `cst-0004` structural rather than aspirational.** The constraint says dira must never require a network service or hosted tier. With no dira-operated host in the picture, that is not a promise anyone has to keep — there is nothing to require. The audience most likely to check this claim is the audience being pitched.
Consequences worth stating
- **Crawlability is an acceptance criterion, not a nice-to-have.** A rendered decision page must be readable by a client that executes no JavaScript. That is testable and E6 should test it. - **No JSON API is built for the UI.** If one appears later it is for third parties, which is a different decision with a different justification. - **`dec-0005`'s storage interface is untouched.** This narrows how surfaces are *served*; reads still go through the interface, and the `github` backend in E7 is unaffected. - **The hosted tier is not forbidden, only unnecessary.** `dec-0007` still permits a team tier; if it arrives it renders the same templates server-side. The static path extends into a hosted one; the reverse would have required rework.
Alternatives on record — 3
✗An embedded static SPA served from the binary, as design.md §9 originally specifiedrefused Three problems, and the first is fatal to the growth engine.
The rendered decision pages are the long-tail SEO surface named in .agents/product-marketing.md §7 channel 4 — "every rendered decision page is a page answering why did project X choose Y" — and client-side rendering makes them uncrawlable, so the SPA actively undercuts dec-0010. Second, the three built screens in docs/design/screens/ contain zero JavaScript, so an SPA is a runtime added for nothing already designed. Third, on localhost the data is already in-process, so a JSON API layer exists only to serialise to yourself.
revisit ifa surface appears that genuinely needs client-side state — a graph explorer with live filtering, not a document view
✗A hosted renderer at dira.sire.runrefused design.md §9 sketches this as Tier 3 "much later", and dec-0005 already rejected dira-operated infrastructure for sync on ops-burden grounds — no ops, no on-call, no security surface for a solo maintainer already carrying kazi.
That reasoning transfers intact to rendering. It would also make cst-0004 a promise that has to be kept rather than a property of the architecture.
revisit ifteams pull for zero-setup shared rendering, per dec-0007's team tier
✗Ship both — static output now, hosted laterrefused Designing two serving paths before either is validated.
The static path is strictly more constrained, so it can be extended into a hosted one later without rework; the reverse is not true.