# A fragment that names itself, 2026-09-10 > A design note from the engineering record: the framework layer for an > application written in Mojo, built app-first under a wire gate. What was > built, what each lift found, what was refused, and what is not claimed. > **D12 is retired (2026-09-18).** The page shell below is a `thin` > function over a separate context struct, because an app's conformance to > a trait behind a `.mojoc` got no witness table on Mojo 1.0. The > discriminant was the package's name against its source directory, fixed > in Mojo 1.1.0; `page_or_fragment` now takes a `PageShell` and > `check-mojoc-trait` guards the fix rather than counting down to it > ([the-page-shell-becomes-a-trait](https://m0serve.dev/notes/the-page-shell-becomes-a-trait.md)). > The rest of the note stands as written. Every one of the 172 rows `docs/SPEC.md` carried at 1.0.0 was about serving Python. The tree's own Mojo apps were seven `server.mojo` files that each routed by `if path ==` or a handler-id chain, wrote every byte of HTML as a `String(...)` call, spelled every URL as a literal, and could not read a `
` at all, because nothing in the tree decoded a urlencoded body. This note is what it took for an htmx app in Mojo to be something a person, or a coding agent, would write on purpose. ## The pattern, stated once > A fragment owns its own root id. The attribute that targets it is > generated from that same id. The view does not branch on which one to > send; the framework decides from a request header whether to wrap the > fragment in a page. The objection to htmx that this dissolves is that it writes behaviour twice: an attribute in a template and a handler that answers it, with nothing checking that the two agree. That objection is to **hand-written attributes**. `dj-fixi`'s `FxForm(action, target, swap)` already emits the `fx-*` attributes server-side from its own arguments, so the target is one Python value used twice; FastHTML's `is_full_page` already lets a view return the same components whether or not the request came from htmx. In Mojo both get stricter, because the page is code and the compiler checks the two uses. Three things follow. The id is written once, by `Fragment("notes")`, and `swap("post", "/notes")` on an element inside it generates `hx-target` from that value; nothing in `apps/fragment_notes` types `#notes`. The view returns one thing — the fragment — and `page_or_fragment` reads `HX-Request` to decide whether to wrap it. And `Vary` stops being optional: one URL now has two representations, so a shared cache that stored the fragment would replay it to a direct navigation, and both answers say `Vary: HX-Request`. ## Built app-first, and gated on the wire before the first lift The repo's rule is that an API with no call site is a defect, and `reply.mojo`'s docstring records that its helpers were *lifted rather than invented* from three apps that each carried a copy. So the sequence was: 1. **`apps/fragment_notes`, written deliberately ugly** against `main` as it stood — `hx-*` attributes by hand in eight places, `String(...)` concatenation, literal URLs, a `comptime H_*` id chain, an inline urlencoded parser twice, every view branching on the header itself. 2. **A smoke gate pinning wire output only** (`smoke-fragment-notes`, SPEC N1): the `Café` round-trip through a form, an escaped `