Whitepaper

Separation that survives: the Composer architecture

Rendering semantic content into finished pages without entangling the four roles that build a website.

Draft v0.3 — 2026-08-20. Status: working draft, open for review.

Abstract

Most web content management systems fail slowly. They ship fine, then degrade over years as content, structure, styling, and behavior grow entangled in the same files. The symptoms are familiar: a "brand refresh" becomes a content migration; editors wait on engineering for changes that are visually trivial; a redesign means touching every page; and the system becomes impossible for multiple roles to work on without colliding.

Composer is a small rendering engine that resists this entropy by construction. It splits a page into four artifacts — a semantic content document, a declarative pattern, plain CSS, and an optional browser-side finisher — each owned by the role best equipped to maintain it, with content flowing in one direction toward a finished page on every request.

That split yields a property the rest of the category lacks: because the pipeline is reversible and machine-verifiable, a static prototype can be turned into CMS-ready, authorable artifacts with no human in the loop — and with no unintended delta from the approved design. Reproducing a design runs unattended; a human's time is spent only on deciding where to improve on it, which is the half worth paying a person for. This paper treats that capability as the architecture's headline benefit, then situates the others around it, and supports the claims with evidence from two independent runs of that loop — a real multi-page site (Experience Managed) built and iterated entirely on Composer, and a deliberately adversarial re-run against a third-party prototype by an agent with no prior exposure to the system. It also states the architecture's deliberate tradeoffs honestly, because a white paper that only lists upsides is a brochure.

The problem: entanglement is the default

Templating systems tend to blur the line between what a page says and how it looks:

Each blur has the same long-run cost. Once content knows about presentation, you can no longer change one without risking the other. The consequences compound:

  1. Redesigns become migrations. If markup structure lives next to the words, restyling means rewriting the words' container — across every page.

  2. Editors depend on engineering. Adding a second card or rearranging a column touches code, so it enters the release train.

  3. Brand integrity erodes. Authors reach for class="featured-red-thing" or inline styles, and bespoke presentation drifts page to page.

  4. Roles collide. Editor, developer, and designer edit the same file; every change ripples across concerns none of them own.

What these have in common is that each is a problem generated by an earlier choice. Build tooling exists because JSX must be compiled. Markup rewriting exists because the platform injects its own wrappers. Image-optimisation expertise exists because the platform hands an author a bare <img>. The trade between authoring comfort and design fidelity exists because the two are checked at different times by different people. Composer's response to most of these is not a better solution but a refusal of the premise: the pattern is the DOM, so nothing needs rewriting; patterns are literal values, so nothing needs compiling; managed media negotiates its own formats, so nobody needs to know how. The problems do not get solved so much as declined.

Nothing in the parts list that follows is novel, and that is the claim rather than an apology for it. XSLT transformed a source tree into an output tree declaratively in 1999. CSS Zen Garden made the case for semantic content and swappable presentation in 2003. Snapshot testing has diffed rendered output against a stored target for a decade. Every headless CMS validates content against a schema. Taken separately these are ordinary, well-understood parts.

Judged separately, every constraint Composer adopts also loses. A render node with five reserved keys is less capable than JSX. A grammar with no expression language is less capable than Handlebars. Literal values only means two patterns cannot share a constant, so repetition replaces abstraction — worse engineering by any ordinary reading. Argued one at a time, on technical merit, each of these is a downgrade, and anyone who wants to dismiss the architecture can do it in a sentence.

They are not separable from what they buy. zum validate can exist because a pattern is literal values that are parsed and never executed: the rendered page is a pure function of document and pattern, so it can be re-derived and diffed. A template language with an evaluator cannot make that offer — not because the tool hasn't been built, but because its output is not recoverable that way. Expressiveness and verifiability trade against each other, and this architecture spends the first to buy the second. Surface area is the same decision from another angle: the entire grammar fits on a page, which is not a pleasant consequence of minimalism but a precondition for §3, since a more powerful grammar offers more ways to be quietly wrong than any gate can check.

So the thesis is not that four artifacts are technically superior. It is a bet about process and ownership: constrain the system until the two questions a senior human normally adjudicates — is this faithful, and is this authorable — can be answered by a command, and the role that adjudicated them stops needing to exist. What changes is not how a page gets built, but who builds it and how many people have to agree before it ships.

The architecture in one direction of flow

Artifact Owner What it holds
Semantic document (content/<page>.html) Editor Plain semantic HTML. One wrapper class per block, plus row/col for layout. No styling, no presentation.
Pattern (patterns/<name>/<name>.js) Developer A literal JS object describing the output tree: which slots pull from which source positions, what tags/classes/attributes the output gets.
Pattern CSS (patterns/<name>/<name>.css) Designer Plain CSS. No tooling, no preprocessor required.
Finisher (default export in the pattern file) Behavior author Optional. Runs in the browser after render for anything declarative can't express.

Composer joins them deterministically on every request — the same library in local dev, at the edge, or in a build step. The split is the product; the rest of this paper is its consequences.

The hidden power: reproducing a design stops being a human job

The benefits in §4 are real, but the architecture's most consequential property is one that's easy to miss because it concerns process, not features: an LLM can take a finished static prototype and produce the CMS artifacts that reproduce it — authorable, lint-clean, and faithful to the design — without a human hand-crafting the translation.

Two scoping notes, stated here rather than buried, because a claim that hides its shape invites the reader to go hunting for the catch. The loop needs a target to diff against, and the unattended part is reproduction: matching a target converges without supervision, while deciding where to depart from it is a judgement call and stays one. Both are examined in §3.5.

A target is not a prerequisite, and the choice of whether to have one is the most consequential decision in the whole process. Three modes, with genuinely different verification:

The authorability translation tax

In a conventional CMS, a prototype is the end of design and the start of a manual, senior, error-prone job: deciding what the design means as authorable content. A human looks at the rendered page and answers, by hand, questions the tooling can't see for them:

This translation is where the cost lives. It is slow, judgment-heavy, and — critically — it has no automatic check that the result still matches the design. The fidelity of the shipped page to the approved prototype rests on a human eyeballing two browser tabs.

The compromises that follow

Because the translation is manual and unverified, teams compromise to "make the CMS happy," and the compromises rhyme across every project:

The root cause is identical in every case: the loop is open. A human is the only thing closing it, and humans are slow, expensive, and inconsistent at diffing markup.

Two machine-checkable gates close the loop

Composer's contribution is to make the two questions a human normally adjudicates mechanically checkable, so the loop can close without one:

Together they bracket the two questions the manual translator was answering by eye: is this legal to author, and is it faithful? The third — is it well modelled? — remains a human's, and is the only one worth a human's attention. Neither gate needs judgment to run; both are deterministic. So an agent can iterate draft → compose → lint → validate → fix to convergence, unattended.

One limit of that guarantee, named rather than left to be found. A slot whose selector matches nothing is skipped silently — required: false is the default, and correctly so, since optional content is ordinary. Validation catches the case that matters: a drifted selector drops content the target contains, and that surfaces as a missing-child diff without any flag. What it cannot catch is a slot that matched nothing at the moment the target was written — see below — or a project with no target at all. zum dev --debug names every zero-match and is worth running before any target is generated.

The inversion: fidelity becomes the pass condition

The deepest change is which way the compromise runs. Conventionally, fidelity is sacrificed to authorability — the design bends until the CMS stops complaining. Under Composer, fidelity is the pass condition: the loop does not terminate until rendered output matches the target. Both constraints are satisfied simultaneously rather than sequentially, and both are machine-verified. "The page in the CMS is the page in the design" stops being an aspiration and becomes a build gate.

What that does not mean is that the two stop interacting, and the difference is measurable. [case study] Compare run two, built to a pixel-perfect target, against a third port — an existing live site re-platformed with no target at all. Run two's patterns carry 5 to 27 slot selectors each, up to 22 of them positional; the untargeted port's carry 4 to 11, at most 7 positional — its most complex pattern is simpler than run two's median. The naming diverges the same way: reproduction yields blocks named for where they sat on a page, composition yields blocks named for what they are.

Both passed zum lint, which is exactly the point — lint proves legality, not quality. So the honest statement is narrower than "no trade": matching a target does not force authorability to fail, but it does constrain its shape, and the constraint is paid in positional selectors and unrolled repetition. Pixel fidelity is worth buying when a design has been signed off and must survive contact with a CMS. It is worth declining when the goal is a well-composed site, and the difference between those two goals should be a deliberate decision at the start rather than a default.

A precise word on "no delta," because honesty matters: the validator does not magically erase differences — it makes every difference explicit. The loop converges to zero unintended delta. Where the rendered DOM legitimately differs from a hand-built prototype — a separator authored as <mark> rather than a styled <span>, gradients moved to a CSS :nth-child rule, a purely decorative element deliberately dropped — each divergence shows up in the diff, gets a reason, and is signed off. There is no silent drift. That is a categorically stronger guarantee than "looks about right," which is all the manual process ever offered.

Worth knowing what happens next, because the gate changes character the first time you improve on the prototype. Any deliberate departure — swapping a CSS background-image for managed media, collapsing three hand-rolled breakpoints into one responsive scaffold — means re-baselining the target from composed output. From that point validation no longer demonstrates fidelity to the original design; it demonstrates that nothing has drifted from the version you approved. Both are worth having. They are not the same claim, and the first is only available once.

The sharper hazard is that re-baselining can encode a defect as the standard. A slot whose selector matched nothing at the moment a target was written bakes that absence into the target, and every run afterwards is green on missing content. This is where a single page misleads worst: one hero without an eyebrow cannot tell you whether the block never takes one or whether that instance simply omitted it, and both readings — deleting the slot, or marking it required — are overconfidence drawn from a sample of one. Only real content variation settles it, which is why required: true is a signal applied after migration rather than inferred during one. Reverse-engineering a prototype does not supply that context, and no gate can invent it.

Do nothing and it is faithful; do a little more and it is good

The useful way to hold the previous section is the way Apple framed Mac Catalyst: do nothing and you have a decent app; put in a little extra work and you have a great one. Run the loop unattended and you get a faithful, lint-clean, authorable site — a real floor, and higher than most projects reach by hand. The distance from there to good is the work a person chooses.

That work divides in two, and knowing which half you are in is the whole skill. Some improvements are free, and provably so: pulling shared selector prefixes forward onto a parent slot, replacing a font stack with self-hosted woff2 and font-display: optional, moving a render-blocking stylesheet out of the head. These change the artifacts and not the output, so validation stays green and proves it. [case study] One refactor restructured a footer's semantic document from a single column into four and rewrote the pattern to match; validation passed untouched, because the rendered tree was byte-identical. The gate does not merely permit authorability refactors — it certifies them.

The rest are trades, and they are the ones worth a human. Moving images onto managed media, collapsing three hand-rolled breakpoint pictures into one responsive scaffold, lifting card photography out of a CSS background-image so it can be both optimised and authored — each changes the DOM, each requires re-baselining, and each should be a decision someone makes on purpose with a measurement in hand. That is why the earlier framing holds: reproducing a design is unattended work, and improving on it is where judgement is worth paying for. The floor is automatic. The ceiling is a choice.

What this looked like in practice

The loop has been run twice, on deliberately unalike inputs. The second run was set up to strip away the advantages the first enjoyed, because a process claim tested only under favourable conditions is a demo.

Run one — Experience Managed

[case study] The four pages of this paper's case study were converted from static prototypes to CMS-ready artifacts by an LLM running exactly this loop. No human hand-crafted the authorability; the human's role was to review the diff and adjudicate the deliberate divergences, not to perform the translation. Each page reached a zum lint-clean semantic document and a zum validate result that was either empty or a short, fully-explained set of intentional divergences — the accepted-convention diffs (a landmark <nav>, :nth-child gradients, <mark> separators) plus, on one page, a single flagged design decision (dropped decorative color swatches the grammar couldn't interleave).

Run two — a hostile prototype and an agent with no prior context

[case study] The second run took a Figma-derived prototype of an Adobe PDF & Productivity page — 2,687 lines, a single 1,318-line <style> block, and some 500 lines of inline JavaScript — and gave it to an agent with no prior exposure to Composer, working only from the published skill, AGENTS.md, and the runnable examples. The prototype had not been written with a CMS in mind: no <main> or <header> landmarks, card photography carried as inline background-image, eighteen uncompressed .otf faces totalling 3.2 MB, a developer-only grid ruler in the markup, dead rules in the stylesheet, and fourteen orphaned assets including an unreferenced 18.3 MB PNG. Its behaviour was not simple either: a scroll-scrubbed hero whose video grows from a bounded box to a full-bleed plate on two different curves, two carousels — one of them infinite, with clone slides — a page-wide reveal system, and a shared smooth-scroll instance.

The output was eleven patterns and three semantic documents: the page itself plus header and footer chrome authored as their own template documents. All three were zum lint-clean, and all three returned an empty zum validate on the first compose, with no ignore flags. The prototype's 1,318 lines of CSS were split across global.css and ten pattern files with zero rule edits — the only change was rewriting a font url() whose file had moved.

That phase took about forty minutes, wall-clock, from the prototype landing in the project to three empty validations — a figure bounded above by the timestamp on the first asset upload that began the next phase. A meaningful share of it was the agent reading the skill, AGENTS.md, and the runnable examples before writing anything. The comparison worth drawing is not against a team's calendar weeks, which contain meetings, handoffs and waiting; it is against the days of senior developer time the translation step alone normally consumes.

A second phase then traded fidelity deliberately, and measurably, for delivery: authored images moved onto managed media, taking page imagery from 26.6 MB to 1.1 MB; the font set moved to self-hosted woff2 with font-display: optional, from 3.2 MB to 173 KB actually fetched. The deployed page scores 100 on Lighthouse desktop (LCP 0.5 s, CLS 0, TBT 0 ms) and 98 on mobile, with no remaining opportunity above 50 ms.

What the two runs together show

Run one Run two
Prototype origin Built in-house for the site Third-party export, no CMS in mind
Agent's prior context Iterating alongside the system's authors None beyond published documentation
Scope Four page templates, ~21 patterns One page plus chrome, 11 patterns
zum lint Clean, all four documents Clean, all three documents
zum validate Empty, or briefly and explicitly divergent Empty on first compose, all three
What it surfaced Two refactors Three defects in the tooling

The grammar is learnable from the documentation. Run one's agent had the system's authors to hand; run two's had a skill file and five examples. That is the condition the §3 claim actually rests on — that the translation does not require someone who already knows the system — and run two is the run that tests it.

Prototype quality decides what gets negotiated, not whether the loop closes. Run one's purpose-built prototypes produced a handful of convention divergences. Run two's produced none at all, and then a series of departures taken on purpose, each carrying a number: a backdrop served three ways at 7.9 MB collapsed to 67 KB; four card photographs moved out of CSS background-image, where they could be neither optimised nor authored, into managed media where they could be both. Under a manual translation a defect in the source is either reproduced silently or corrected silently, and no record survives of which. Between two gates it becomes a decision with a measurement attached.

One grammar limit, two symptoms. Run one dropped decorative colour chips because source content and pattern-owned decoration cannot interleave inside a single element. Run two unrolled six navigation links, three tabs and three pricing cards because a render node holds only literal values and so cannot vary a class or a child count across iterations of a loop. These look like different problems and are the same one: a pattern describes assembly, and per-iteration variation is not assembly. Worth stating plainly rather than discovering twice.

Both runs independently reached the same conclusion about cross-cutting behaviour. The cautionary tale below — fourteen byte-identical reveal finishers consolidated back into one observer — was rediscovered in run two, where a page-level reveal system, a shared smooth-scroll instance and a footer wipe were placed in a single module from the outset rather than distributed across the patterns that appear to own them. Two agents converging on the same placement from opposite directions is better evidence than either arriving there alone.

Where the human's time actually went. Run two divides cleanly in two, and the division is the point. The first phase — prototype to CMS-ready artifacts at full fidelity — took a four-question briefing and nothing else: how faithful the port should be, how much to convert, whether chrome stayed global or became page content, and whether to carry across a developer-only grid overlay. After that the agent ran unattended until it reported three zum lint-clean documents and three empty validations. Nobody adjudicated a diff, because there was no diff. It also solved its own environment problems along the way, including symlinking the asset tree so that images resolving through the content path and fonts resolving through the code path could share one directory.

The second phase — improving on the prototype rather than reproducing it — was collaborative from end to end: which departures from the design were worth taking, when to re-baseline the validation targets, and one performance diagnosis the agent had examined and wrongly dismissed. That is the honest shape of the claim, and it is the better half of it. Reproducing a design runs unattended; beating it is where a human's judgement is worth paying for. No one wants to spend three weeks confirming a border radius. Deciding whether a 7.9 MB backdrop should become 67 KB, and what that costs in fidelity, is an hour well spent.

The economic shape of that is the headline. A task that is normally a multi-day, senior-developer, fidelity-risking manual translation became an unattended loop whose output a reviewer checks rather than produces. The compromises in §3.2 aren't merely mitigated — they stop being structurally necessary. Cycle time collapses because the loop runs at machine speed; authoring ergonomics improve because the grammar, not expedience, dictates the shape; duplication falls because refactors are safe when a diff confirms "still matches"; and presentation drift goes to zero-by-default because matching the design is the termination condition.

Benefits, with evidence

The running case study is Experience Managed (em2), a publication site of four page templates — a homepage, an article, an about/colophon page, and a pillar/category landing — built on Composer across ~21 patterns. A second, narrower case study — the Adobe page port described in §3.5 — supplies the delivery and portability numbers, since it was measured end to end in production. Where a claim is backed by something observed on either, it is marked [case study].

Content that outlives redesigns

Because the semantic document carries no presentation, a redesign rewrites the pattern and the CSS while the content sits still. The "refresh the brand" project becomes an actual brand refresh, not a content migration. The inverse also holds: when the content model changes, patterns update once and content migrates mechanically, while CSS and finishers are untouched.

[case study] Across the four pages, the chrome (navigation and footer) and the about-callout block are authored identically and rendered by a single shared pattern each. Changing the structural treatment of any of these is a one-file change in patterns/, not a sweep through four content files.

A minimal grammar that resists feature creep

A pattern's render node has just five reserved keysselect, tag, children, required, delegate — plus open HTML attributes and string children. There are no conditionals, no loops over computed data, no expression language. When a pattern needs something the grammar can't express, the answer is never "grow the grammar" — it's export default function (root) {…}, a finisher with the full power of the browser, where runtime logic belongs.

The discipline pays off in predictability: a developer reading a pattern is reading a description of assembly, never hidden control flow.

Statically analyzable end to end → portable by default

Pattern files are parsed and never executed — only literal values are accepted. A pattern can therefore be inspected, validated, serialized, shipped to a Worker, or rendered by any runtime that speaks the schema, with no transforms in between. The dev server, an edge Worker, a build-time renderer, and a CI validator all consume the same files. This is the quiet structural reason the system has "one runtime, three deployment targets" rather than an SSR/CSR split to keep in sync.

Reversibility is the property underneath §3

The no-human-in-the-loop loop of §3 rests on one property worth naming on its own: the pipeline is reversible. transform(source, patterns) is deterministic, so zum validate can run it and diff the result against a target — returning tag, class, attribute, and child mismatches as structured data. Most template systems can't do this, because their templates aren't reversible; you take the correspondence between source and output on faith.

[case study] The diff signal earns its keep beyond first authoring. When the engine changed to carry a swapped link's href forward as data-href, zum validate immediately flagged the new attribute on the exact elements, on the exact pages — a regression check no one had to write.

Brand integrity by construction

The semantic document allows only a tight set of classes: the block name (optionally plus a keyword for a block-level variant), plus row and col. Visual variation is signaled by meaning, not style — an author marks emphasis with <strong>, a per-instance variant in a repeating structure with <em> or <mark>, and the pattern's CSS decides what those look like. Authors write content; they never pick colors.

[case study] Two patterns recurred and held the line cleanly: card "·" separators authored as <mark> and tinted in CSS, and a category page's "current pillar" link signaled by wrapping its label in <em> (targeted via a:has(em)), with no class="disabled" leaking into the source.

Composition without growing the grammar

Composition of authored elements needs no primitive at all. Every registered pattern is matched against the whole source tree, so a link the editor wrote is claimed by whichever pattern most-specifically matches it — a host pattern just positions it with a bare slot and the widget pattern owns the output.

The one gap is an element the pattern constructs. It is created during rendering, after the match pass, so nothing can see it. delegate: true closes that gap: a constructed leaf is offered to the registry exactly as an authored element would be — same matching, same specificity, no second class of element. Depth is capped at one hop (a pattern may delegate; a delegated pattern may not), because a chain's intermediate element appears in neither the source nor the output and would be invisible from both ends.

[case study] The site's social-icon lockup appears in three places (nav, footer, end-of-article share). Initially each host pattern inlined the four SVG icons — twelve path declarations duplicated across three files. Refactored into a single social-lockup widget matched by a sentinel link (a[href="…/social"]), the icons collapsed to four declarations in one file. Where the sentinel is editorial (nav, footer) each host is a bare slot; where it is pure template furniture (end-of-article share) the host constructs it with delegate: true and the editor authors nothing at all.

Performance and operations: no framework, no hydration

There is no React/Vue/Svelte at runtime, no virtual DOM, no reactivity system, no router. The page arrives finished — no build step between writing and seeing, no hydration delay between loading and using. The only client-side code is per-pattern finishers, and they run after render, never blocking first paint. For a site of mostly-stateless patterns and a few interactive ones, this is a dramatically smaller surface to keep healthy over five years than a framework upgrade cycle.

[case study] The §3.5 port measures the claim: a page carrying an autoplaying video, two carousels and a scroll-scrubbed hero scores 100 on Lighthouse desktop and 98 on mobile, with a cumulative layout shift of 0 and no total blocking time on either. The only client-side JavaScript is the finishers and one shared scroll module.

[case study] Scroll-reveal — the site's one cross-cutting behavior — lives in a single global observer rather than per-pattern JavaScript. (See §6 for how it briefly didn't, and what that taught.)

Source maps that survive into the DOM

In dev, every rendered element carries a data-source selector resolving to its exact source position. Walk up the DOM, collect the selectors, and any rendered element maps back to the line that produced it — enabling click-to-edit, source-rooted analytics, and visual debugging. It's opt-in, so production payload stays clean.

Role separation as the organizing principle

The deepest organizational benefit is that each artifact has an owner, and the boundaries let owners work without stepping on each other:

The usual complaint about a framework component is that four concerns share one file. That complaint is weak — colocation is a defensible choice, and a team that likes it is not wrong. The real cost arrives one step downstream, where nobody is looking: the component's prop signature becomes the content model.

A link is one thing to the person writing it. They copy it and they paste it, the way they have in a word processor for twenty years. Give a component the signature <CTA href label target variant /> and that link arrives at the author as four fields to fill in, because a headless content type was modelled on a function's parameters. Nothing about that decomposition serves the person typing. It serves the prop passing — and it is routinely sold back to the business as "structured," "portable," "omnichannel," which inverts who the benefit belongs to.

variant is the worst of the four, and a different category of mistake from the rest. The others are pointless decomposition; that one is presentation entering the content model through the back door, asking an author to make a design decision because a component happens to take a prop. It is precisely what §4.5 exists to prevent, arriving under a new name.

The premise underneath all of it is that structured content and HTML are opposites. They are not. HTML is already a structured content format — thirty years old, universally supported, semantically rich, and already emitted by every tool an author touches. <a href="…">Label</a> is the structure, and target has been an attribute since 1996. Splitting it into JSON fields adds nothing; it replaces structure that already existed with structure shaped like a parameter list, and bills the author for the conversion.

A fair line to draw, since decomposition is sometimes right: a field is legitimate when the content has it, not when the component wants it. A product has a price — that field exists regardless of rendering technology, and you will want to query on it. The test is whether the field would survive a change of front-end framework. A price would. variant would not.

The same inversion, in markup rather than fields, is what block libraries do. Gutenberg wraps authored content in wp-block-* containers and alignment classes; AEM's core components emit their own cmp-* structure; Edge Delivery wraps every block in section and wrapper layers. Class-based selectors often survive that. Structural ones do not — every :nth-child, every flex or grid parent-child relationship, breaks the moment a layer is injected between two elements. That is why a prototype's stylesheet has to be rewritten against those platforms rather than transplanted onto them, and why §3.5's zero-rule-edit result is not a small detail.

Composer doesn't ask roles to coordinate through discipline; it removes most of the need to coordinate at all. And as §3 shows, one of those "roles" can now be an agent that produces the developer and content artifacts under machine-checked supervision.

Honest tradeoffs

These are conscious choices. A white paper that hides them is untrustworthy.

A cautionary tale that proves the model

[case study] Each revealing block was initially given its own scroll-reveal finisher — fourteen of them, all byte-identical, each a decomposed copy of one page-level observer the prototypes had carried as a single inline script. Consolidating them back into one global observer didn't just remove redundancy; it restored the prototypes' original design. The lesson generalizes: when the architecture tempts you to decompose a cross-cutting behavior per pattern, that's a smell — cross-cutting behavior wants one home, and the finisher escape hatch should be reserved for behavior that is genuinely per-pattern.

Where Composer fits — and where it doesn't

Composer is not a framework, a templating language, or a build tool. It does one thing: turn semantic content into a finished page on every request, fast enough that nobody thinks about it. It is an excellent fit for content-heavy, editorially-driven, long-lived sites that must survive redesigns and be authored by multiple roles — publications, marketing sites, documentation, brand sites — and especially for teams that want to generate those sites from design prototypes under machine verification rather than hand translation (§3).

It is a deliberately poor fit for highly stateful, app-like surfaces where most of the page is interactive and reactive — there, the finisher would carry most of the weight and the declarative core would buy little. The architecture is honest about this: the grammar is for assembly, and apps are not mostly assembly.

Conclusion

The chronic failures of long-lived web content systems — painful redesigns, editor/engineering bottlenecks, brand drift, role collisions, and the slow, lossy, hand-built translation of a design into a CMS — share a root cause: content entangled with presentation, and a loop that only a human can close. Composer's contribution is to make that entanglement structurally hard by splitting the page into four artifacts with crisp owners and a one-way flow, and then to make the pipeline reversible and machine-verifiable so the loop can close without a human in it.

None of the parts are new, and each constraint is a downgrade on its own terms — which is why the architecture is easy to dismiss in a sentence and hard to dismiss in practice. The constraints are what make the verification possible, and the verification is what removes the adjudicating role. The change is to process and ownership, not to what a page can be made to do.

The headline benefit follows directly: a static prototype can be turned into authorable, faithful, CMS-ready artifacts with no human hand-crafting the authorability — and no unintended delta from the approved design. Scoped precisely: reproducing the design runs unattended, and improving on it is where a human's judgement goes. That is the better half of the bargain, not the fine print on it. The supporting benefits — content that outlives redesigns, brand integrity by construction, composition without grammar growth, and framework-free delivery — are not a feature list. They are what necessarily follows from taking the separation seriously and making it verifiable. The case-study evidence suggests the architecture delivers on that promise in practice, tradeoffs included.

Plain assembly. Clean separations. Verified fidelity. Speed by default.

Appendix: further reading

Draft notes (to expand before publication)