Summary
olon.it already positions OlonJS publicly as the "contract layer for the agentic web", "the website your AI agent can read AND operate", built for agencies running 20 to 500 client sites. The internal codebase and docs, however, still describe and build the project as a CMS engine (see CLAUDE.md). This RFC does not ask the project to reposition. It asks the internals (architecture, CLI, docs) to catch up to the positioning the product already sells.
Three architectural commitments would close that gap:
- Projection over generation. Every artifact that is not genuine creative work (
schema.ts, types.ts, index.ts, the theme-compliant view frame, the discovery manifests, and the agent-facing manual itself) is projected deterministically from a single source of truth (a section "Model"). The CLI stops cloning apps and becomes a set of projection workflows.
- Standards from day zero. The discovery and authentication surface an agent uses to find, orient and operate a site is expressed in open standards (the agentic-web RFC basket), not in proprietary
olonjs-* formats. An OlonJS site is agent-ready by construction, conformant to the public checklist (for example https://isitagentready.com/) the day it ships.
- Extensibility by injection. The framework exposes explicit extension seams (dependency injection and adapter ports) so capabilities, libraries and the discovery layer itself can be added or swapped without forking the core.
This is a directional proposal intended to provoke a decision, not a finished spec. It deliberately lists its own open risks (Section 7) so they can be argued rather than discovered later. If accepted, it spawns the ADRs listed in Section 9.
Two axes, not one
There are two separate axes here, and only one of them is already settled.
- The agentic axis: an agent can read and operate the site. olon.it already sells this ("contract layer for the agentic web", "read AND operate"). This RFC does not argue for it. It is done.
- The product-nature axis: CMS vs framework. A CMS renders and edits content. A framework is something developers build agent-operable systems on: they author section types, pages and middleware, and extend it by dependency injection without forking the core. olon.it ships the agentic capability as a managed product. It does not yet claim to be a framework you build and extend on.
This RFC is about the second axis. The shift it proposes is a change of product nature, from CMS to framework, so that the agentic capability becomes something developers author and extend, not only something they consume. Settling the first axis (agentic) does not settle the second, and conflating the two is how the "internal alignment" framing below understates the actual change.
What we assumed vs. what olon.it already ships
This RFC was drafted from a reading of the open-source repo (apps/tenant-alpha and packages/*). A later review of olon.it corrected three assumptions. They are recorded here so the proposal is honest about what is already solved.
- Positioning (agentic axis). We initially framed this as "stop being a CMS, become an agentic framework", as if the agentic part were also missing. The agentic positioning is already public on olon.it, so this RFC does not preach it. The CMS-vs-framework change (the product-nature axis in the section above) is a separate matter and remains the actual ask.
- OAuth-scoped MCP Gateway. olon.it advertises a "MCP Gateway" with OAuth-scoped agent access for reading, updating and form submission, described as live in production. That gateway is not present in the open-source repo: the only
@olonjs/mcp here is a local stdio server driving the Studio through a Playwright bridge, with no OAuth, scope or .well-known code anywhere. So the auth-scope work this RFC discusses may already exist in a closed or managed component. The proposal treats it as "absent in OSS, confirm before assuming a gap", not as a missing feature.
- Target audience. "Agencies running 20 to 500 client sites" is the product's stated ICP, not a discovery of this analysis. The multi-tenant work in the repo is consistent with it.
Problem
P1. The CLI is deterministic in the dumbest possible way
Today a template is a cloned app: the CLI copies tenant-alpha as a shell archive (src2Code.sh and DNA injection). A second template means a second app to maintain. This does not scale and does not compound, because every clone is an organism that drifts on its own. Templates were (correctly) killed for this reason, but killing them left no positive answer to "how do we generate sites that share a spine and still diverge where they should?"
P2. The agentic surface is reinvented, not standardized
OlonJS already emits a real discovery surface, but mostly in custom shapes:
| Concern |
Today in OlonJS (OSS) |
Open standard it should map to |
| Bot rules |
yes, robots.txt (robots.mjs), AI-bot allowlist |
RFC 9309 |
| Sitemap |
yes, sitemap.xml (sitemap.mjs) |
Sitemaps protocol |
| LLM discovery |
yes, llms.txt |
llms.txt convention |
| Structured data |
yes, JSON-LD WebPage with a custom additionalType: "mcp-manifest" |
schema.org |
| MCP server discovery |
custom mcp-manifest.json, kind: "olonjs-mcp-manifest-index" |
MCP Server Card / SEP-2127, .well-known |
| Link relations |
only <link> in <head> |
RFC 8288 HTTP Link: header |
| API catalog |
no |
RFC 9727 .well-known/api-catalog |
| Linkset |
no |
RFC 9264 application/linkset+json |
| Auth discovery |
no metadata endpoint in OSS, /admin is custom EC P-256 JWT (see gateway caveat above) |
RFC 9728 (OAuth Protected Resource Metadata), RFC 8414 / OpenID Connect Discovery |
| Service binding |
no |
RFC 9460 (SVCB/HTTPS DNS records) |
The cost: an agent that already speaks the standards has to learn OlonJS dialect to discover what is, structurally, generic information. And the discovery half of OlonJS, the half with the broadest near-term demand, is build-time static plumbing (generate-llms-txt.mjs, bake.mjs, sitemap.mjs, robots.mjs) with no technical reason to be coupled to the framework.
P3. The internal "CMS engine" framing undersells the contract
Internally the project is documented and structured as a CMS engine. Framed that way, the unique asset (the typed contract that lets an agent operate the system) reads like a feature on top of a category (Sanity, Contentful, Builder, TinaCMS) where OlonJS is the least mature entrant. The public site already avoids this trap. The internals should too, so that contributors and the CLI optimize for the contract, not for the editor.
P4. The OSS write/operate story stops at content editing
In the open-source repo the WebMCP write tools (update-section, save) are registered only inside StudioRoute (/admin), behind EC P-256 JWT auth. That is correct for security, but in OSS it means the demonstrable "agent-operable" capability is "an authenticated admin agent edits content". The managed MCP Gateway may go further (see caveat above). The framework's deeper, harder-to-copy capability, letting an agent author new capability (a section type, a page, a middleware) under a contract that keeps the result valid by construction, is not yet a public OSS surface.
Proposal
Make OlonJS a framework for building agent-operable systems, not a CMS that happens to be agent-readable. This is the product-nature shift from Section "Two axes": developers author capability (section types, pages, middleware) and extend the system by injection, instead of consuming a fixed editor. The Studio/CMS becomes one consumer of the contract, not the identity of the project. The following pillars are additive and independently shippable.
1. Projection over generation (the "Model")
A section is a capsule today: View.tsx, schema.ts, types.ts, index.ts. Promote the capsule's non-view artifacts to a single declarative Model that is the source of truth. From the Model, project (execute, do not scaffold once):
- the Zod
schema and inferred types
- the capsule
index re-exports
- the view frame (see Pillar 2)
- the IDAC bindings
- the discovery manifests (Pillar 3)
- the agent manual (Pillar 6)
Projection is recomputed from the Model every build, so it cannot drift. Generation scaffolds once and drifts. This is the property that makes the system compound: improve the frame projector once and every section inherits it for free, the opposite of cloned templates.
Consequences:
- A template stops being an app. A template is a set of Models, composable, versionable, diffable, not a cloned codebase. This resolves P1.
- CLI commands become projection workflows.
olonjs add page and olonjs add section are deterministic projections plus a single bounded creative step (Pillar 2), not file copies.
- One source of truth serves humans and agents.
Open question (carried to Section 7): what exactly is the Model, and in what language? It must be thinner than the four files it replaces, or it becomes another protocol to learn.
2. The view splits: deterministic frame, creative slot
The view is the only place genuine design judgement lives. Split it:
- Frame (projected, deterministic). The section root plus the
--local-* block, computed as a pure function of which theme concerns the Model declares it owns. Same shape for every section type. Because the frame is projected, it is theme-chain compliant (per Architecture Spec and CIP) and carries its IDAC bindings before any design is written. An agent cannot violate the theme chain in the frame, because it does not author the frame.
- Slot (authored, bounded creativity). Inside the frame sits a slot. Only here is the agent (or human) creative: layout, JSX, classes, composition. It inherits a frame that is already compliant.
The contract is guaranteed by construction: projected schema and types, the computed --local-* block, IDAC bindings, theme-chain compliance, green build. Creativity in the slot, determinism in the frame and the contract.
This is what makes agent authoring safe, and it is the defensible answer to P4. An agent can create a new section type by writing only the slot, inside a frame that already guarantees the rules.
Two seams that must be specified (carried to Section 7):
- IDAC binding. Editable fields must carry
data-jp-field and data-jp-item-id inside the slot's JSX. If the agent places them, determinism leaks back into the slot. The framework instead needs a declarative binding (the Model says "field title renders here") that projection injects. That bounds slot creativity to "every editable field must be locatable", which is a healthy constraint but must be explicit.
- Slot drift gate. The slot is generated, not projected. If the Model gains a field, the frame re-projects but the slot does not. Green build catches structural drift; it does not catch semantic drift (the slot ignoring the new field). The slot therefore requires a verification gate (lint, tsc, contract conformance, and a "slot stale vs Model" diff), not just a passing build.
3. Standards from day zero
Express the agent-facing discovery and auth surface in open standards, mapping the P2 table to concrete outputs:
- Discovery: RFC 9309 robots (have), Sitemaps (have), schema.org JSON-LD (have, drop the custom
additionalType), RFC 8288 HTTP Link: headers, RFC 9727 .well-known/api-catalog, RFC 9264 linkset, and the MCP Server Card / SEP-2127 in place of the custom olonjs-mcp-manifest-index.
- Auth: RFC 9728 (Protected Resource Metadata) for
/admin, with RFC 8414 / OpenID Connect Discovery metadata, so an agent learns how to authenticate generically instead of reverse-engineering the JWT scheme. Confirm first whether the managed Gateway already covers this.
- Service binding (optional, infra level): RFC 9460 SVCB/HTTPS records (the "DNS-AID" item on isitagentready).
Conformance target: the public agent-ready checklist (isitagentready.com). An OlonJS site passes it on first deploy. The standards layer is deliberately the thin, portable interop shell. It is the part with the least lock-in, by design.
4. The two-agent model (make it explicit)
The work that produced this RFC kept conflating two agents. The framework must serve both, from the same SOT:
|
Authoring agent (for example Claude Code in the repo) |
Runtime agent (browser agent on the live site) |
| Wants |
how do I add a page, create a section, wire a middleware |
how do I discover and authenticate here |
| Consumes |
the projected manual (Pillar 6) plus the JSON contracts |
the standards (.well-known, Link, MCP card, RFC 9728) |
| Capability |
creates capability (slot inside frame, new pages, scoped middleware) |
reads and operates (writes gated behind auth) |
| Maturity |
real, near-term, the actual win |
narrower today in OSS |
5. Extensibility by injection
The framework exposes explicit ports so the tenant adds or swaps capability without forking core:
- Dependency-injected services at bootstrap (
JsonPagesConfig level): persistence, asset resolution, auth verifier, discovery emitter, telemetry.
- Adapter ports for the discovery layer specifically, so the standards emitter (Pillar 3) can run as a pluggable adapter, including over a non-OlonJS site. This is what lets the agent-ready capability also exist as a portable tool or skill without the framework, capturing the existing-site market the full-framework rewrite otherwise excludes.
- Capability registry for agent-authored capability (sections, then pages, then, under Section 7's permission model, middleware).
6. The agent manual is a projection, not the product
Project a vendor-neutral capability description from the SOT (this is largely what the MCP Server Card plus JSON Schema contracts already are). Render it into vendor-specific manuals (skill.md for the Claude family, AGENTS.md, and so on) as views of that description.
The framework does not become a skill. It emits the skill that teaches an agent to drive it. Because the manual is projected from the same SOT as the schema, types and frame, the manual cannot lie about the system. A hand-written manual drifts. A projected one cannot. This keeps faith with the founding principle: the contract is the SOT, the manual is a view.
Non-goals
- Not deprecating the Studio/CMS. It remains a first-class consumer of the contract.
- Not a bolt-on for arbitrary existing sites at the framework level. That capability is delivered specifically via the discovery adapter of Pillar 5, not by the full framework.
- Not a commitment to agent-authored middleware in phase 1 (see Section 7 and the phasing in Section 8).
Risks & open questions
- Lock-in is the explicit bet. The only portable part is the standards shell (Pillar 3), intentionally thin. All value is captured in the projection engine. This is a legitimate strategy, the same one every good framework makes, but it means the projection engine must be excellent. That is the whole wager. State it plainly rather than hide it.
- Middleware authoring is a different risk class than section authoring. A section is sandboxed (frame, slot and schema cannot escape the theme chain). A middleware runs server-side and touches auth, routing and requests, which is arbitrary code execution. The green-build gate that suffices for a slot does not suffice for middleware. This is where RFC 9728 and OAuth scopes become load-bearing: the agent token's scope decides what it may author and run. If the managed Gateway already implements scopes, this pillar is about exposing that model to OSS authoring rather than building it from scratch. Until a scope model is available in this layer, capability authoring stops at sections and pages.
- The Model meta-schema must stay thin. A new SOT above Zod risks adding to the protocol surface that is already a documented adoption barrier (many versioned protocols plus a long spec). The Model must consolidate the four capsule files into less to learn, not more.
- Projected artifacts must be build outputs, never committed.
types.ts is needed by tsc and the IDE, so projection must run in dev. Precedent exists: the Vite middleware already projects mcp-manifest.json and schemas on the fly. Commit a projected file and drift re-enters through the first distracted PR.
skill.md is one vendor's format. Project the neutral capability description first and treat skill.md as a rendering. Do not let a vendor format become the SOT.
Migration / phasing
- Phase 1. Standardize discovery (cheap, non-breaking). Add RFC 8288
Link: headers, .well-known/api-catalog (9727), linkset (9264), the MCP Server Card (SEP-2127) and RFC 9728 auth metadata alongside the existing olonjs-* artifacts. Pass isitagentready.com. No contract break. Extract the discovery emitter as the Pillar 5 adapter.
- Phase 2. Projection engine for sections. Introduce the Model, project schema, types, index and frame, and define the IDAC declarative binding and the slot verification gate (the Section 2 seams).
olonjs add section becomes a workflow.
- Phase 3. Projected manual. Emit the vendor-neutral capability description and render
skill.md and AGENTS.md from it. olonjs add page becomes a workflow.
- Phase 4. Scoped capability authoring. Confirm or build the capability scope model (RFC 9728 and OAuth scopes) and, gated by it, enable agent-authored middleware and capability.
Decision required
Commit to aligning the internal architecture, CLI and docs with the agent-native positioning the product already sells, with projection over generation as the core engine principle and open-standard agent-readiness from day zero as a product invariant. Approve Phase 1 (standards alongside, non-breaking) as the first concrete step.
ADRs this RFC would spawn
- ADR. Discovery emitted in open-standard formats (and as a pluggable adapter).
- ADR. The Model meta-schema (what the section SOT is, and its thinness budget).
- ADR. The frame/slot contract, the IDAC declarative binding, and the slot verification gate.
- ADR. The projected vendor-neutral capability description and its
skill.md and AGENTS.md renderings.
- ADR. The capability scope and permission model for agent-authored capability (sections, then pages, then middleware), reconciled with the managed Gateway.
Summary
olon.it already positions OlonJS publicly as the "contract layer for the agentic web", "the website your AI agent can read AND operate", built for agencies running 20 to 500 client sites. The internal codebase and docs, however, still describe and build the project as a CMS engine (see
CLAUDE.md). This RFC does not ask the project to reposition. It asks the internals (architecture, CLI, docs) to catch up to the positioning the product already sells.Three architectural commitments would close that gap:
schema.ts,types.ts,index.ts, the theme-compliant view frame, the discovery manifests, and the agent-facing manual itself) is projected deterministically from a single source of truth (a section "Model"). The CLI stops cloning apps and becomes a set of projection workflows.olonjs-*formats. An OlonJS site is agent-ready by construction, conformant to the public checklist (for example https://isitagentready.com/) the day it ships.This is a directional proposal intended to provoke a decision, not a finished spec. It deliberately lists its own open risks (Section 7) so they can be argued rather than discovered later. If accepted, it spawns the ADRs listed in Section 9.
Two axes, not one
There are two separate axes here, and only one of them is already settled.
This RFC is about the second axis. The shift it proposes is a change of product nature, from CMS to framework, so that the agentic capability becomes something developers author and extend, not only something they consume. Settling the first axis (agentic) does not settle the second, and conflating the two is how the "internal alignment" framing below understates the actual change.
What we assumed vs. what olon.it already ships
This RFC was drafted from a reading of the open-source repo (
apps/tenant-alphaandpackages/*). A later review of olon.it corrected three assumptions. They are recorded here so the proposal is honest about what is already solved.@olonjs/mcphere is a local stdio server driving the Studio through a Playwright bridge, with no OAuth, scope or.well-knowncode anywhere. So the auth-scope work this RFC discusses may already exist in a closed or managed component. The proposal treats it as "absent in OSS, confirm before assuming a gap", not as a missing feature.Problem
P1. The CLI is deterministic in the dumbest possible way
Today a template is a cloned app: the CLI copies
tenant-alphaas a shell archive (src2Code.shand DNA injection). A second template means a second app to maintain. This does not scale and does not compound, because every clone is an organism that drifts on its own. Templates were (correctly) killed for this reason, but killing them left no positive answer to "how do we generate sites that share a spine and still diverge where they should?"P2. The agentic surface is reinvented, not standardized
OlonJS already emits a real discovery surface, but mostly in custom shapes:
robots.txt(robots.mjs), AI-bot allowlistsitemap.xml(sitemap.mjs)llms.txtWebPagewith a customadditionalType: "mcp-manifest"mcp-manifest.json,kind: "olonjs-mcp-manifest-index".well-known<link>in<head>Link:header.well-known/api-catalogapplication/linkset+json/adminis custom EC P-256 JWT (see gateway caveat above)The cost: an agent that already speaks the standards has to learn OlonJS dialect to discover what is, structurally, generic information. And the discovery half of OlonJS, the half with the broadest near-term demand, is build-time static plumbing (
generate-llms-txt.mjs,bake.mjs,sitemap.mjs,robots.mjs) with no technical reason to be coupled to the framework.P3. The internal "CMS engine" framing undersells the contract
Internally the project is documented and structured as a CMS engine. Framed that way, the unique asset (the typed contract that lets an agent operate the system) reads like a feature on top of a category (Sanity, Contentful, Builder, TinaCMS) where OlonJS is the least mature entrant. The public site already avoids this trap. The internals should too, so that contributors and the CLI optimize for the contract, not for the editor.
P4. The OSS write/operate story stops at content editing
In the open-source repo the WebMCP write tools (
update-section,save) are registered only insideStudioRoute(/admin), behind EC P-256 JWT auth. That is correct for security, but in OSS it means the demonstrable "agent-operable" capability is "an authenticated admin agent edits content". The managed MCP Gateway may go further (see caveat above). The framework's deeper, harder-to-copy capability, letting an agent author new capability (a section type, a page, a middleware) under a contract that keeps the result valid by construction, is not yet a public OSS surface.Proposal
Make OlonJS a framework for building agent-operable systems, not a CMS that happens to be agent-readable. This is the product-nature shift from Section "Two axes": developers author capability (section types, pages, middleware) and extend the system by injection, instead of consuming a fixed editor. The Studio/CMS becomes one consumer of the contract, not the identity of the project. The following pillars are additive and independently shippable.
1. Projection over generation (the "Model")
A section is a capsule today:
View.tsx,schema.ts,types.ts,index.ts. Promote the capsule's non-view artifacts to a single declarative Model that is the source of truth. From the Model, project (execute, do not scaffold once):schemaand inferredtypesindexre-exportsProjection is recomputed from the Model every build, so it cannot drift. Generation scaffolds once and drifts. This is the property that makes the system compound: improve the frame projector once and every section inherits it for free, the opposite of cloned templates.
Consequences:
olonjs add pageandolonjs add sectionare deterministic projections plus a single bounded creative step (Pillar 2), not file copies.Open question (carried to Section 7): what exactly is the Model, and in what language? It must be thinner than the four files it replaces, or it becomes another protocol to learn.
2. The view splits: deterministic frame, creative slot
The view is the only place genuine design judgement lives. Split it:
--local-*block, computed as a pure function of which theme concerns the Model declares it owns. Same shape for every section type. Because the frame is projected, it is theme-chain compliant (per Architecture Spec and CIP) and carries its IDAC bindings before any design is written. An agent cannot violate the theme chain in the frame, because it does not author the frame.The contract is guaranteed by construction: projected schema and types, the computed
--local-*block, IDAC bindings, theme-chain compliance, green build. Creativity in the slot, determinism in the frame and the contract.This is what makes agent authoring safe, and it is the defensible answer to P4. An agent can create a new section type by writing only the slot, inside a frame that already guarantees the rules.
Two seams that must be specified (carried to Section 7):
data-jp-fieldanddata-jp-item-idinside the slot's JSX. If the agent places them, determinism leaks back into the slot. The framework instead needs a declarative binding (the Model says "fieldtitlerenders here") that projection injects. That bounds slot creativity to "every editable field must be locatable", which is a healthy constraint but must be explicit.3. Standards from day zero
Express the agent-facing discovery and auth surface in open standards, mapping the P2 table to concrete outputs:
additionalType), RFC 8288 HTTPLink:headers, RFC 9727.well-known/api-catalog, RFC 9264 linkset, and the MCP Server Card / SEP-2127 in place of the customolonjs-mcp-manifest-index./admin, with RFC 8414 / OpenID Connect Discovery metadata, so an agent learns how to authenticate generically instead of reverse-engineering the JWT scheme. Confirm first whether the managed Gateway already covers this.Conformance target: the public agent-ready checklist (isitagentready.com). An OlonJS site passes it on first deploy. The standards layer is deliberately the thin, portable interop shell. It is the part with the least lock-in, by design.
4. The two-agent model (make it explicit)
The work that produced this RFC kept conflating two agents. The framework must serve both, from the same SOT:
.well-known,Link, MCP card, RFC 9728)5. Extensibility by injection
The framework exposes explicit ports so the tenant adds or swaps capability without forking core:
JsonPagesConfiglevel): persistence, asset resolution, auth verifier, discovery emitter, telemetry.6. The agent manual is a projection, not the product
Project a vendor-neutral capability description from the SOT (this is largely what the MCP Server Card plus JSON Schema contracts already are). Render it into vendor-specific manuals (
skill.mdfor the Claude family,AGENTS.md, and so on) as views of that description.The framework does not become a skill. It emits the skill that teaches an agent to drive it. Because the manual is projected from the same SOT as the schema, types and frame, the manual cannot lie about the system. A hand-written manual drifts. A projected one cannot. This keeps faith with the founding principle: the contract is the SOT, the manual is a view.
Non-goals
Risks & open questions
types.tsis needed bytscand the IDE, so projection must run in dev. Precedent exists: the Vite middleware already projectsmcp-manifest.jsonand schemas on the fly. Commit a projected file and drift re-enters through the first distracted PR.skill.mdis one vendor's format. Project the neutral capability description first and treatskill.mdas a rendering. Do not let a vendor format become the SOT.Migration / phasing
Link:headers,.well-known/api-catalog(9727), linkset (9264), the MCP Server Card (SEP-2127) and RFC 9728 auth metadata alongside the existingolonjs-*artifacts. Pass isitagentready.com. No contract break. Extract the discovery emitter as the Pillar 5 adapter.olonjs add sectionbecomes a workflow.skill.mdandAGENTS.mdfrom it.olonjs add pagebecomes a workflow.Decision required
Commit to aligning the internal architecture, CLI and docs with the agent-native positioning the product already sells, with projection over generation as the core engine principle and open-standard agent-readiness from day zero as a product invariant. Approve Phase 1 (standards alongside, non-breaking) as the first concrete step.
ADRs this RFC would spawn
skill.mdandAGENTS.mdrenderings.