Getting started
This walk-through installs the authoring layer in an existing Evolve project. By the end you can open a page on your storefront, see the editor chrome, and have a chat session that generates and pushes a page to your CMS.
For a production-grade rollout — including the CMS-service module, the gateway plugin, and the storefront wiring in full — follow the installation guide; this page is the quick tour.
Prerequisites
Section titled “Prerequisites”- An Evolve project with a working storefront and federation gateway
- A CMS service (Contentful) mounted on the gateway, with the
authoring module composed in (
ContentfulAuthoringModulefrom@evolve-framework/contentful/authoring) - One AI provider you plan to use for chat (Anthropic, OpenAI, or Google) and an API key for it
- An OAuth app on your CMS provider so editors can sign in with their own permissions (Contentful: Developers > OAuth applications)
1. Install the packages
Section titled “1. Install the packages”Install the four base packages in your monorepo. Pick the workspace that runs your authoring backend (a service following the standard Evolve service anatomy) and the one that runs your storefront (typically a Next.js app):
# In the authoring backend servicepnpm add @evolve-framework/authoring-core \ @evolve-framework/authoring-server \ @evolve-framework/authoring-ai-providers
# In the storefront (Next.js)pnpm add @evolve-framework/authoring-core \ @evolve-framework/authoring-chromeFor headless workflows, also add @evolve-framework/authoring-workflows
in the backend service. You can defer that until you actually want
the addon: the chrome works without it.
2. Configure environment variables
Section titled “2. Configure environment variables”You need at least:
- AI provider:
CHAT_PROVIDER(one ofanthropic,openai,google),CHAT_MODEL(a model id), and the matching API key (ANTHROPIC_API_KEY,OPENAI_API_KEY, orGOOGLE_API_KEY).PROVIDERsets a default for all modalities at once. - CMS access: the editor’s own OAuth token covers reads and
writes; the OAuth app credentials (
CONTENTFUL_OAUTH_CLIENT_ID,CONTENTFUL_OAUTH_CLIENT_SECRET) live on the CMS service, which exchanges auth codes on the authoring server’s behalf - Internal secret:
AUTHORING_INTERNAL_SECRET, a shared secret between the authoring service and the CMS service’s internal OAuth endpoints - Session signing: two 32-byte keys,
SESSION_ENCRYPT_KEYandSESSION_SIGN_KEY, used to encrypt and sign the editor session cookie. Generate withopenssl rand -hex 16. These must be identical across the authoring service, the storefront, and the gateway — all three read the same cookie.
Optional, for AI image and video generation: IMAGE_PROVIDER,
IMAGE_MODEL, VIDEO_PROVIDER, VIDEO_MODEL (falling back to
PROVIDER when unset).
3. Run codegen
Section titled “3. Run codegen”@evolve-framework/authoring-core/codegen is a graphql-codegen plugin
that walks the fragments in your project’s documents and emits a
runtime schema registry the AI uses to know which fields exist on
which content types.
Add it to your storefront’s codegen.ts:
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = { schema: "../../backend/services/graphql-gateway/supergraph.generated.graphql", documents: ["src/**/*.{ts,tsx}"], generates: { "./src/authoring/generated/schema-registry.generated.ts": { plugins: ["@evolve-framework/authoring-core/codegen"], }, },};
export default config;Also generate the same registry into your authoring backend service
so both sides describe the same shapes. The simplest path is a second
generates entry in the same codegen config that writes to the
service’s source tree:
"../../backend/services/authoring/src/generated/schema-registry.generated.ts": { plugins: ["@evolve-framework/authoring-core/codegen"],},Run pnpm codegen to produce the files. They are deterministic from a
single codegen run, so the two outputs cannot drift.
If you plan to expose tools over the MCP endpoint (opt-in
but recommended), add a second pair of codegen configs in the
authoring service that compile an authoring-operations.graphql file
into ready-to-mount MCP tools through @evolve-framework/mcp-core.
The MCP page walks through the full pipeline.
4. Mount the server
Section titled “4. Mount the server”The authoring service follows the standard Evolve service anatomy: a
module whose getHttpConfig() mounts the editor routes, booted with
createDomainService. Register the schema registry at startup, then
mount the editor with mountAuthoringEditor:
import { aiProviderConfigFromEnv,} from "@evolve-framework/authoring-ai-providers";import { mountAuthoringEditor, registerAuthoringCors,} from "@evolve-framework/authoring-server";import { AbstractModule, type HttpConfig } from "@evolve-framework/core";import { config } from "./config.ts";
export class AuthoringServiceModule extends AbstractModule { getHttpConfig(): HttpConfig { return { routes: (parent): void => { parent.register(async (app) => { const applyCorsHeadersRaw = registerAuthoringCors(app, { allowedOrigins: config.ALLOWED_ORIGINS.split(","), });
await mountAuthoringEditor(app, { signerKeys: { SESSION_ENCRYPT_KEY: config.SESSION_ENCRYPT_KEY, SESSION_SIGN_KEY: config.SESSION_SIGN_KEY, JWT_ISSUER: config.JWT_ISSUER, JWT_AUDIENCE: config.JWT_AUDIENCE, }, gatewayUrl: config.GATEWAY_URL, ai: aiProviderConfigFromEnv({ PROVIDER: config.PROVIDER, CHAT_PROVIDER: config.CHAT_PROVIDER, CHAT_MODEL: config.CHAT_MODEL, ANTHROPIC_API_KEY: config.ANTHROPIC_API_KEY, OPENAI_API_KEY: config.OPENAI_API_KEY, GOOGLE_API_KEY: config.GOOGLE_API_KEY, }), contentful: { spaceId: config.CONTENTFUL_SPACE_ID, environmentId: config.CONTENTFUL_ENVIRONMENT, locale: config.CONTENTFUL_LOCALE, }, applyCorsHeadersRaw, }); }); }, }; }}import { createDomainService } from "@evolve-framework/core";import { setSchemaRegistry } from "@evolve-framework/authoring-core/codegen";import { authoringSchemaRegistry } from "./generated/schema-registry.generated.ts";import { AuthoringServiceModule } from "./module.ts";import { config } from "./config.ts";
export const startServer = async (): Promise<void> => { setSchemaRegistry(authoringSchemaRegistry); const service = await createDomainService({ name: config.COMPONENT_NAME, module: new AuthoringServiceModule(), http: { address: { host: config.HTTP_HOST, port: config.HTTP_PORT }, // Chat bodies carry inline image uploads; raise the 1MB default. bodyLimit: 25 * 1024 * 1024, }, }); await service.start();};To enable the bundled OAuth + login UI, pass an auth block with the
OAuth client id, the CMS service’s internal URL, the shared internal
secret, and your cookie domain. Make sure your CORS allowlist includes
the storefront origin and that cookies are set on a domain the
storefront can read.
The reference implementation lives in
backend/services/authoring/src/module.ts — including the streaming
asset-upload content-type parser and the optional workflows mount.
5. Mount the chrome
Section titled “5. Mount the chrome”In your Next.js layout (a server component), wrap the storefront
content with AuthoringServerMount from the /server sub-export. It
reads the editor cookie itself and short-circuits to children for
anonymous shoppers — they pay zero chrome cost. You provide the
storefront-specific slots: the CMS config, a page loader, slug
routing, and a bindings render-prop that bridges the chrome to your
project’s router and components:
import { AuthoringServerMount } from "@evolve-framework/authoring-chrome/server";import type { ReactNode } from "react";import { StorefrontAuthoringBindings } from "#authoring/host-bindings.tsx";import { loadAuthoringPageByPath } from "#authoring/preview/load-page.ts";import { storefrontSlugRouting } from "#authoring/routing.ts";
export async function AuthoringChromeMount({ locale, children,}: { locale: string; children: ReactNode;}) { return ( <AuthoringServerMount locale={locale} loadPage={loadAuthoringPageByPath} slugRouting={storefrontSlugRouting} cmsConfig={{ spaceId: process.env.CONTENTFUL_SPACE_ID, environment: process.env.CONTENTFUL_ENVIRONMENT ?? "master", }} bindings={(shell) => ( <StorefrontAuthoringBindings authoringServerUrl={env.AUTHORING_SERVER_URL} gatewayUrl={env.CLIENT_API_GATEWAY_URL} currentLocale={locale} storeKey={storeConfig.storeKey} storeCurrency={storeConfig.currency} > {shell} </StorefrontAuthoringBindings> )} > {children} </AuthoringServerMount> );}The bindings provider is where your project’s routing, block renderer,
and locale logic plug in — see
frontend/site/src/authoring/host-bindings.tsx in the platform for
the reference implementation.
The chrome ships its own stylesheet baked into the JS chunk, so there is no separate CSS file to import or serve. Shoppers never download the chrome: the editor surface is loaded lazily after the session resolves.
6. First editor session
Section titled “6. First editor session”Restart your services and visit any page on your storefront while signed in. You should see:
- A profile badge in the top-right corner showing your editor name
- A floating prompt bar at the bottom of the page, with quick actions to open the chat panel or the page browser
- A drawer on the left listing the pages, entries, and assets in your CMS
Open the chat panel, type make this page about summer barbecues,
and watch the page update inline. When you’re happy with the draft,
click Push to write the result to your CMS.
If you see the chrome but the AI doesn’t respond, check the network
tab for the /chat request and confirm your AI provider API key is
reaching the authoring server. The /ai/info endpoint (visible in
your Swagger docs) reports which provider and model are active.
Where to next
Section titled “Where to next”- Packages: what each
@evolve-framework/*package does in detail, with API surfaces - MCP endpoint: serve the same tools to headless AI
clients with a project-owned
authoring-operations.graphql - Workflows (optional): the opt-in addon for headless, long-running content jobs
- The package READMEs on npm have per-package configuration tables and security notes

