Now live in production
Content SDK · Agentic flow · Now live in production

An agentic flow for SitecoreAI head apps.

A full agentic workflow for Sitecore Content SDK head applications — its own subpipeline (discover, provision, build, author, publish), a delivery loop that verifies each component as it lands, and a preview-first / publish-last go-live. It has now carried a complete brand site all the way from an idea to a published, live head app — without leaving the IDE. This page is the playbook.

Read the Velaro runBack to Sitecore
Status
It now runs end-to-end — to a published, live site. The flow has grown its own Sitecore subpipeline — discover, provision, map, author, publish — plus two new agents and a per-component delivery loop, and it has taken a brand site (Velaro) from idea to a published, live head app without leaving the IDE. Preview-first / publish-last: everything is built and authored against preview, and one operator-confirmed publish flips it live. Since the packs refactor, none of this is spelled inline in the shared engine: it is a platform pack the stages resolve as a generated brief. What you see below is the playbook — the wins, the open questions, and what is deliberately deferred.
Three dials, not eleven flows

What actually changes, and why.

A run answers three independent questions, and the answers compose rather than multiply. Two of them usually stay at their default, and a default has no pack at all — a missing directory IS the null value, so there is nothing empty to maintain. Twelve combinations exist and ten are runnable; the two invalid ones are refused by name at resolution time rather than discovered halfway through a build.

platform

What are you building on?

nonedefault

The engine with no platform knowledge at all — no scaffold, no provisioning, no publish. Idea to shipped code for anything that is not Sitecore. Everything else on this page is what a platform pack adds on top of it, and proving this still runs clean is the test that the domain really did leave the engine.

content-sdkopt in

The six Sitecore stages, two dedicated agents, the skill stack, the CM + editing-host workspace, the three tranche-exit audits and the preview-first / publish-last release. In other words, everything on this page.

marketplaceopt in

Cloud Portal extension apps instead — extension-point routes, a host-frame visual smoke inside a real iframe, and app registration as what "deployed" means. That pack owns zero stages: its entire behaviour is data.

method

Where does the specification come from?

greenfielddefault

The null of this dimension — nothing is injected. The spec comes from a one-question-at-a-time interrogation of the operator, and /design diverges into up to three UI variants because there is nothing to copy.

cloneopt in

The source site IS the spec. A crawl runs before the spec stage, /design collapses to a parity phase (the ui_variants dial is forced to skip — there is nothing to diverge from), and "done" stops being a feature list: every page is scored on pixel, content, design and component fidelity, per required viewport, and the loop keeps running until every criterion clears 95 or it stops for a stated reason.

audience

Who is operating the run?

developerdefault

Every artifact is surfaced as written — the spec, the ADRs, the task breakdown, the code-review and test reports — and the scope dial is answered by the operator at kickoff.

marketeropt in

Additive only, and never a stage override — that is a contract the validator enforces, not a convention. A brief instead of a PRD, seven plain-language discovery questions, and the answers a developer would be asked for (router, deploy project name, NEW vs EXISTING model) derived instead of surfaced. What it does not do is remove gates: all five stay on, and the build and final stops split into a human half (does this look right, does it say the right thing) and a blocking machine half — route crawl, destination distinctness, responsive, containment, motion, the robots gate, the live link crawl.

One engine, four shapes

What each dial actually does to the run.

Same thing, concretely. Step one is the engine with every dial at its default; each step after it turns exactly one dial and marks what that dimension added, replaced or dropped. The restrictions are the interesting part — the platform owns the beginning and the end and never the build span, the method is the only dimension permitted to remove a stage, and the audience adds and removes nothing at all.

  1. core

    The engine, with every pack at its default

    No platform, greenfield, developer. Eight stages, five operator gates and a delivery loop that runs per tranche. This is what is left when the domain has been taken out of it — and proving it still runs clean is the test that the domain really left.

    /create-prd (unchanged)/architect (unchanged)/design (unchanged)/task-breakdown (unchanged)/implement (unchanged)/code-review (unchanged)/test (unchanged)/ship (unchanged)
  2. + platform: content-sdk

    Six stages appear, and the release step changes meaning

    The platform is what you build ON, so it owns the beginning and the end: read the content model before designing against it, stand the cloud up before building, and — because authoring happens against preview — put the whole content phase after ship, with one operator-confirmed publish as the only thing that goes live.

    /discover-sitecoreai (added)read the real content model first/create-prd (unchanged)/architect (unchanged)/design (unchanged)/task-breakdown (unchanged)/provision-sitecoreai (added)CM + editing host, idempotent/implement (unchanged)/code-review (unchanged)/test (unchanged)/ship (replaced)code only, deployed against preview/discover-components (added)a visual map for the author/author-content (added)copy and imagery into the tenant/test-content (added)an independent content audit/publish (added)the only step that goes live
  3. + method: clone

    The spec stops being written and starts being measured

    The method is where the specification comes FROM. Point it at a public site and the crawl replaces the interrogation outright — eleven questions, none of them greenfield. Design has nothing to diverge from, so it collapses into a parity phase, and "done" becomes a score per page per viewport instead of a feature list.

    /source-analysis (added)the crawl becomes the blueprint/create-prd (replaced)the greenfield questions are dropped/architect (unchanged)/design (dropped)the source site IS the designparity loop (added)bounded, with its own stop reason/task-breakdown (unchanged)/implement (unchanged)/code-review (unchanged)/test (replaced)+ a 4-criterion parity matrix/ship (unchanged)
  4. + audience: marketer

    The same spine, a different conversation

    Additive only — this dimension may never override a stage body, and a validator enforces that rather than a convention. Nothing is added or removed from the flow. What changes is what reaches the operator: a brief instead of a PRD, plain-language questions, technical answers derived instead of asked, and five dials preset so none of them ever gets surfaced.

    /create-prd (replaced)a brief, and 7 plain questions/architect (unchanged)/design (unchanged)/task-breakdown (unchanged)/implement (unchanged)/code-review (unchanged)/test (replaced)human half + a blocking machine half/ship (replaced)nothing technical surfaced

+ added · ⇄ replaced · − dropped · everything unmarked is the same stage the engine already ran.

The pipeline

The standard flow, and the Sitecore branch.

Every project rides the same governed pipeline. Think of it as two transit routes that share their stations: the Standard line runs on every project, and the Content SDK line stops everywhere the Standard line does — then makes five extra Sitecore stops, to discover the model, provision the cloud, map the components, author the content, and publish it live.

Prime
Intake
Discover model
Architect
Design
Task
Provision
Implement
Review
Test
Ship
Discover Components
NEW
Author
Publish
NEW
Prime
Intake
Discover model
/discover-sitecoreai
Architect
Design
Task
Provision
/provision-sitecoreai
Implement
Review
Test
Ship
Discover Components
/discover-componentsNEW
Author
/author-content
Publish
/publishNEW
Standard line — runs on every projectContent SDK line — five extra Sitecore stops

Discover the model

/discover-sitecoreai
Read-only

Reads the existing CM's content model — templates, renderings, field contracts — so /architect designs against real shapes, not assumptions. Runs before /architect.

Provision the cloud

/provision-sitecoreai
DevOps Engineer (13)

Stands up the decoupled CM + editing host and deploys the baseline — non-interactive, idempotent, from one deploy-admin client. Runs before /implement.

Map the components

NEW
/discover-components
Content Author (14)

A visual Components Map — every component, its variants, its fields, and a real screenshot — so the Content Author knows when to use which component and which variant. Proven on Umbra Roasters. Runs before authoring.

Author the content

/author-content
Content Author (14) + Content QA (07)

Writes on-brand copy in a chosen voice and lands it in Sitecore via the Marketer MCP — and commissions on-brand imagery for empty slots. A Content QA gate confirms it actually rendered. The content phase now runs AFTER /ship, against preview.

Publish it live

NEW
/publish
DevOps Engineer (13)

The final live step. Publishes everything — layout, content, media — onto a LIVE edge context, ser-pulls the authored items back into the CM code base for git durability, and redeploys the public host. Preview-first / publish-last: nothing goes live before this operator-confirmed gate.

Special flows for special jobs

Seven exports, generated from one engine.

Of the ten runnable compositions, seven are published as self-contained flow repos. An export is a composition, not a copy: the closure walks the dependency graph that already exists, so there is no hand-maintained file list to go stale, and the README, the command set and the docs are projected rather than subset-copied. Generated, never forked — a forked public repo would put the engine in two places and hand the sync problem straight back. Skills ship vendored, so a consumer clones one repo and has everything with no install step. And each export is correct only if the framework validator passes inside it, which is how a missed file surfaces as an unresolvable reference instead of a quietly broken flow.

core.greenfield.developer

Project build

The generic pipeline with no platform knowledge at all — idea to shipped code for anything that is not Sitecore. This is what is left when every pack sits at its default.

content-sdk.greenfield.developer

Head app

Everything on this page, packaged: CM and editing-host provisioning, the component-vertical build, the content phase, preview-first delivery and the live publish. The flow the eight brand sites were built with.

content-sdk.clone.developer

Website clone

Rebuild an existing public site on SitecoreAI. Deliberately a superset of the head-app flow rather than a sibling of it — a clone has no deploy target of its own, so it always has to land somewhere.

content-sdk.greenfield.marketer

Head app, guided

The same head-app journey driven by someone who is not a developer. Same gates, same audits, same artifacts produced — a different set of questions asked and a different set of things shown.

content-sdk.clone.marketer

Website clone, guided

"Here is our current site, rebuild it, I am not a developer." The most plausible non-developer scenario there is, and the reason the audience dimension was kept additive: an audience pack that overrode the spec and design stages would have collided with clone and foreclosed exactly this combination.

marketplace.greenfield.developer

Marketplace app

Cloud Portal extension apps — the extension-point routes, the iframe host-frame visual smoke against the approved clickdummy, and the app-registration lifecycle. Same engine, a different idea of what "deployed" means.

marketplace.greenfield.marketer

Marketplace app, guided

The same app build with the technical questions derived rather than asked. Clone is absent here on purpose: marketplace × clone is declared incompatible and refused by name, because "rebuild this website as a portal extension" is not a coherent request.

What's built so far

Eleven skills that earn their keep.

These aren't a wishlist — they're the eleven my agents reach for most, out of 67 published across eight clusters. Ranked by how often they actually get pulled into real runs; the never-loaded ones are pruned on purpose. Each was distilled from a session — a trap I hit, a pattern worth keeping — and auto-surfaces by description match. An agent invokes one by bare name, so a reference never depends on how the skill happens to be packaged. Which ones earn their keep is measured, not guessed.

content-sdk-app-router-theme-hydration-pattern#1 most loadedcontent-sdk-app-router cluster

The most-loaded skill of them all. Dark+light+system theme stack — public/theme-init.js preflight, useSyncExternalStore provider, mounted-flag for SSR-safe styling, Tailwind v4 @theme tokens.

content-sdk-resolver-patterns#2 most loadedcontent-sdk cluster

Catalog of Sitecore data-delivery patterns. Key insight: 4 SXA content-resolver variants (Datasource/Context × Item/Children) collapse to only 2 React-side shapes.

content-sdk-website-build-flow#3 most loadedcontent-sdk cluster

The umbrella. Canonical phase sequence, NEW-vs-EXISTING fork, baseline-copy + token-replacement mechanics, upfront operator question batch, per-component cycle template.

content-sdk-component-naming-trapscontent-sdk cluster

Five gen-map traps. The big one: only the Sitecore-registered .tsx (and variants) live under src/components/<X>/; types, queries, sub-components must live elsewhere or they auto-register.

sitecoreai-create-componentsitecoreai cluster

Create a Sitecore rendering end-to-end via Authoring GraphQL — clone an existing rendering (copyItem + relink) instead of building it piece-by-piece. The recipe for net-new, authorable components.

content-sdk-variants-vs-siblingscontent-sdk cluster

Decision skill — variant (same rendering, different FieldNames) vs sibling (separate rendering). SDK-verified FieldNames resolution flow + Headless Variant authoring requirement.

sitecoreai-cli-cloud-workflowsitecoreai cluster

Device-flow login → project list → environment list (project-id required) → connect → user.json patch → ser pull. Every CLI trap captured.

content-sdk-debug-layout-probecontent-sdk cluster

/api/layout-debug route + ResolverProbe component + InstrumentedFrame wrapper. The triple-toolkit for any "what is Sitecore actually delivering" question.

sitecoreai-edge-graphql-capturesitecoreai cluster

curl recipe for capturing Edge GraphQL snapshots. Three hard limits documented: 15-depth introspection, complexity-by-pagination, no /schema endpoint.

content-sdk-app-router-component-level-navigationcontent-sdk-app-router cluster

Production navigation pattern — component-level GraphQL fetch (server L1 + lazy L2 per-hover) instead of fighting the SXA Navigation Content Resolver. Scales to any depth.

solo-nextjs-route-handler-vs-server-actionsolo cluster

General Next.js rule: reads → Route Handler, mutations → Server Action. Server Actions auto-trigger router.refresh() which wipes client state on reads — looked like endless loading flicker.

And there are more

67 skills, eight clusters.

The eleven above are the ones that get loaded. Behind them sits the rest of the library, grouped by the surface it covers — because nobody needs all of it. A project installs only the clusters it actually builds on, and a name tells you which plugin it ships in: a skill is named <cluster>-<skill>, so the prefix is the packaging. That naming is deliberate — provenance used to be encoded twice, in the folder name and in the frontmatter, which meant it could drift.

14content-sdk-app-routerApp Router head apps — routing, component maps, editing, theming, caching.
11content-sdk-pages-routerThe same surface for Pages Router projects.
11sitecoreaiThe four SitecoreAI REST APIs, the CLI workflow, GraphQL schemas and auth.
9content-sdkRouter-agnostic Content SDK craft — resolvers, variants, field usage, the build flow.
7marketplaceMarketplace SDK apps — client, XMC, AI skills, lifecycle, host-frame testing.
6soloThe hand-authored ones no product owns — voice, imagery, the Debrief trio.
5blokSitecore's design system — components, theming, setup, MCP.
4setupCross-domain scaffolding — the decision tree and each scaffold path.
The gates

Three audits, and each one can fail.

Every tranche exits through the same three scripts. They are read-only, need no tenant auth and no network, and each exits 1 on an unwaived defect — so a green run is a claim the build has to earn rather than a default. Deliberate exceptions are declared as waivers carrying their own mandatory reason; anything undeclared still fails.

rule 80

Is the content model sound?

audit-sitecore-schema.mjs

Base templates, parameters templates and their dashed-GUID links, folder templates, icons, the Source law, local datasource placement, and the <Site>/ template folder layout. Read-only, no tenant auth.

What it caught

Three false greens were found in the audit itself — each had been passing a schema it never actually checked. A brand with zero renderings exited clean because an empty row set cannot produce defects. Path matching was case-sensitive while Sitecore resolves paths case-insensitively, so all 248 template items of one brand were invisible to every template axis. And module discovery was a flat directory read that found zero manifests once modules moved into folders — so every axis passed on an empty set and the whole CM exited 0.

rule 86

Can an author actually edit it?

audit-component-authorability.mjs

Every registered rendering that renders no SDK field component — and therefore cannot be inline-edited in Pages — plus unmount-on-empty and bare guard patterns. A component is not done when it renders; it is done when an author can find its content and change it.

What it caught

ZEPHIRA passed 704 unit tests, 88 end-to-end tests, four code reviews and a full /test cycle with 17 of its 21 renderings un-editable. Every one of them rendered perfectly. That is the entire reason this audit exists.

rule 87

Is the comment carrying its weight?

audit-comment-density.mjs

Comment walls, header essays and comment-to-code density. A source comment says WHY in a line or two and links out; narrative build history belongs in the product’s tracked build-decisions record, not in a file header.

What it caught

Measured across 1,505 hand-written source files: 28% comment-to-code overall, 183 files carrying a header essay of 25+ lines, and a worst case of 115% — more comment than code. It was accelerating, too: the two newest builds were the two worst.

Live findings

The wins that paid for themselves.

Each of these turned a half-day debug session into a one-line rule the agents now follow — encoded as a skill or an always-on rule, and where possible enforced by one of the audits above. They are not aspirations; they are the operating playbook. Note the shape the newest ones share: every single one of them passed every gate that existed at the time. A page returning 200 while telling crawlers to go away, a dead link resolving to the homepage, a route form that only breaks once it is live — none of those look like failures from the inside, which is exactly why they cost what they cost.

🧮

4 resolver variants → 2 React shapes

Datasource + Context, each in Item + Children form, look like four distinct patterns. They collapse to TWO React-side payload shapes (single-item flat hash; children-list wrapper). Same React code handles both members of each pair.

🚦

Edge has hard, undocumented limits

15-level depth limit kills the standard IntrospectionQuery. Query complexity scales with pagination + nesting — first:100 with nested fields gets rejected, first:10 works. There is no /schema endpoint; POST + per-type introspection is the only path.

🌀

Server Action for reads = endless flicker

Server Actions auto-trigger router.refresh() after returning. For mutations, that is the feature. For client-triggered reads from a hover handler, it wipes every NavBranch state, the dropdown closes, the user re-hovers, repeat. Route Handlers have zero refresh side-effect; that is the right tool for reads.

🧭

Component-level nav > SXA Navigation Resolver

The resolver was returning fields: [] with no clear cause. Replacing it with a custom GraphQL query — server L1 with hasChildren flag, lazy L2 per-hover — is more predictable, type-safe, recursive to any depth, and stays under Edge limits because each branch fetch is independent.

🪤

Support files inside component folders auto-register

Place types.ts, queries.ts, a NavBranch.tsx client child, or an actions.ts under src/components/<X>/ — gen-map registers them as variants of <X> or as standalone Sitecore renderings. Only the rendering .tsx (plus .<Variant>.tsx siblings) belongs in that folder. Everything else lives in src/lib/, src/ui/, or src/app/api/.

🔤

Generic parameter names collide silently

Naming a rendering parameter "Levels" made it disappear from the Pages editor — collision with a base-template field. Renaming to "Level" (singular) made it visible. The rule: namespace your rendering-parameter names or use singular forms; avoid Levels / Depth / Style / Items.

📌

A datasource location pin that nothing catches

A rendering whose Datasource Location is a hard GUID rather than a site-relative query silently binds every site that shares it to one site’s content tree. No test, no code review, no build gate and no serialization validation catches it. On a shared CM, fork the rendering rather than mutating it — in-place remediation is a go-live-class decision needing an operator, a baseline and a non-prod rehearsal.

💥

Sibling modules cannot share an include name

Two serialization manifests in the same directory sharing an include name abort the items-as-resources build — and MSBuild reports 0 Errors first, so it reads as a Sitecore-side failure when it is ours. Nine of fifteen include names collided across all six brand modules; they are conventional names, so any CM serializing brands this way hits it the first time it deploys to a new environment. Fix is one folder per module, which moves zero item files.

🕳️

An empty field can serve a crawler-blocking page at 200

A site whose robots field is never authored does not 404 — it serves a perfectly valid document that says Disallow: /, at a clean 200. Nothing in a build, a test run or a link check has any reason to complain. Measured across the portfolio: five of six shipped sites were excluded from search that way. The robots response is now a named gate at publish — 200 AND no blanket disallow — and the field is seeded at provisioning so it is never empty in the first place.

🔗

A fail-open href is a silent dead link

Writing href={link || '/'} looks defensive and is the opposite: a missing link now points at the homepage and returns 200 forever, so no crawler, smoke check or status assertion will ever tell you it is broken. On one build all seven navigation links resolved to / and every one of them passed. A missing destination has to render as no link at all, or fail loudly — never as a plausible one.

🪞

Preview and live are two runtimes, and preview is the lenient one

Route-path form, media resolution and cache semantics all differ between the preview and live Edge contexts — and every stage of the build, from local dev to the ship deploy, sits on the permissive side by design. So a whole class of defect is structurally invisible until publish. Worse, a preview-side pass can pin the broken value as the expected one: four links 404-ed for real visitors for days while a route smoke test asserted the wrong URL form and passed. Anything that can differ gets one assertion against the strict surface, manual if necessary.

📝

Ungated reports pushed build history into source files

Code-review and test reports were treated as disposable, so the only clone-surviving home for a hard-won finding was a comment header in the code it concerned. Measured across 1,505 hand-written source files: 28% comment-to-code, 183 files carrying a header essay of 25 lines or more, one component at 227 lines of comment around 22 lines of code — and accelerating, since the two newest builds were the two worst. The root cause was structural rather than stylistic, so the fix was too: those reports are tracked now, and each product keeps a component-grained decision record that a source comment can point at in one line.

Honest closer
The flow plugs into my existing agentic pipeline — it just grew a Sitecore-aware branch, and that branch is now a pack rather than a set of conditionals. Six Sitecore commands (/discover-sitecoreai, /provision-sitecoreai, /discover-components, /author-content, /test-content, /publish) and two agents (a DevOps Engineer that provisions the decoupled CM + editing host and owns the live publish, and a Content Author that writes and lands the content) live inside the content-sdk pack, and the shared build-side agents carry no platform knowledge at all — they resolve a generated brief per run. A pack-owned agent is still a first-class agent: same contract, same registry, only a different address. The content phase runs after /ship, and the build span is a per-component delivery loop. The skills hold the domain knowledge; the packs hold the domain wiring; the agents stay framework-neutral. That is the whole architecture.
What's open

The honest roadmap.

What's next, and what's deliberately deferred. Multilingual, fully autonomous runs, and a lot of testing and optimization are the forward bets; personalization and forms wait for a real project to ask. None of it is hidden.

Multilingual support

The big one. Author and publish a head app across multiple languages in one run — next-intl wiring, per-language Edge fetches, dictionary loading, and the content agent writing each locale. The playground already carries four languages on file; making the whole flow language-aware is the next major lift.

Earning a fully autonomous run

The capability landed — all five gate tokens can be unticked, and with none of them on the pipeline runs the whole distance unattended, live publish included. What is still open is the trust, not the mechanism: I have not yet let a real brand go from idea to live without looking. That has to be earned run by run, by the self-checks getting good enough that my looking adds nothing.

Testing & hardening

Broader automated coverage across the Sitecore branch — more edge cases, content-resilience, and real-tenant smoke automation — so a green run means more than it does today. The unglamorous work that makes autonomy safe.

Token-consumption optimization

Make each run leaner and cheaper — trim context, prune the dark skills, tighten agent hand-offs, and measure token spend per stage. Efficiency treated as a first-class goal, not an afterthought.

Personalization

Deferred. @sitecore-content-sdk/personalize integration, A/B variants, audience targeting. Distinctively Sitecore; needs its own probing session.

Forms

Deferred. Sitecore Forms rendering, validation, submission flow. A common requirement for any real site; gets its own skill once the first project needs it.

Watching this take shape?

Want a Content SDK head app built this way?

The flow has now taken a full brand site all the way to a published, live head app on a real tenant, and is being hardened run over run. If you have a head-app project on the horizon and want to be the next dogfood case, reach out.