The Editing Pipeline
When a user types a message like “Add a testimonials section with 3 customer quotes below the hero”, the system goes through a structured pipeline to turn that natural language request into validated, type-safe content changes.Step 1: Intent Detection
The orchestrator first determines what the user wants to do. A fast model (e.g., Claude Haiku) classifies the message:- Structural edit — Add, remove, move, or update blocks
- Page operation — Create, duplicate, or delete a page
- Clarification needed — The request is ambiguous (“make it better” → which block?)
- Off-topic — Not a content editing request
Step 2: AI Planning
For complex requests, the orchestrator sends the full context to a planning model:- System prompt — Instructions for generating structured edit operations
- Block schemas — Zod schemas for all available block types, so the AI knows what fields exist and what values are valid
- Current page state — The full PageDoc with all existing blocks
- User message — The natural language request
- Conversation history — Previous messages for context
Step 3: Validation
Every operation in the plan is validated against the block’s Zod schema:- Are the props valid for this block type?
- Does the target block exist (for updates/removes)?
- Is the position valid (for adds/moves)?
Step 4: Apply Operations
Validated operations are applied to the draft page state in order. Each operation:- Updates the in-memory draft PageDoc
- Records itself in the undo/redo history
- Bumps the preview version number
Step 5: Stream to Content Studio
The orchestrator streams results back to the Content Studio via Server-Sent Events (SSE). The main events are:field_draft, summary_token,
changelog_entry, op_skipped, rollback_started / rollback_done, status,
heartbeat, error, and canceled.
There is no dedicated preview_updated event — preview refresh is driven by the
draft version bump described in Step 6.
The user sees changes appearing progressively — not a loading spinner followed by a wall of changes.
Step 6: Live Preview Update
The site (in the iframe) detects the draft content update and re-renders:- Orchestrator notifies via draft version bump
- Site re-fetches draft pages from orchestrator
- React re-renders only the changed blocks
- Site sends
postMessageto Content Studio confirming the update
Step 7: User Review
The user can now:- Approve — Keep the changes in the draft
- Undo — Roll back the last operation (or the entire plan)
- Continue editing — Send another message to refine the changes
- Publish — Push the draft to production
Streaming & Progressive Updates
Avocado Studio is optimized to minimize perceived latency:Undo / Redo
Every operation is recorded in a per-session history stack. Undo reverses the last operation by restoring the previous page state. Redo re-applies it. The history is operation-level, not plan-level — if a plan contains 3 operations, you can undo them one at a time.Publishing
When the user is satisfied with their edits, they click Publish in the Content Studio. The orchestrator snapshots the current draft pages and pushes them through a publish target — a pluggable interface that connects to your deployment workflow.The PublishTarget Interface
Publishing is defined by a single TypeScript interface:
name— Stable identifier used by the registry and thePUBLISH_TARGETenv var.canHandle()— Optional selection hint. The registry iterates targets on eachPOST /publishand picks the first whosecanHandle(ctx)returns true.publish()— Receives the fullPublishContext(session, scopedSession, pages, siteConfig, siteOrigin, generatedImageDir, logger) and returns aPublishOutcome(ok, httpStatus, tracker, response body).
Built-in Targets
Three targets ship in the box, registered at module load (in order) fromapps/orchestrator/src/publish/publish-target-registry.ts:
site-contract — Selected when the request includes a siteOrigin. POSTs pages + siteConfig + inline image assets to the remote site’s /api/editor/publish contract endpoint. The site owns content storage (json file, CMS, database, etc.). For the legacy avocado-stories siteId this target also records a git snapshot for version history.
git — Selected when no siteOrigin and PUBLISH_MODE=git (default):
- Serializes all draft pages to
apps/site/lib/published-content.json - Copies any generated images to
apps/site/public/generated-images/ - Rewrites localhost image URLs to relative paths
- Commits and pushes to the configured branch (
PUBLISH_GIT_BRANCH, defaults tomain) - If a Vercel deploy hook is configured, the push triggers a rebuild automatically
deploy-hook — Selected when no siteOrigin and PUBLISH_MODE=deploy_hook:
- Calls
VERCEL_DEPLOY_HOOK_URLto trigger a Vercel rebuild - Tracks deployment status by polling the Vercel API (
VERCEL_TOKEN) - Reports back to the Content Studio: triggered → building → ready (or failed)
PUBLISH_TARGET=<name> (e.g. PUBLISH_TARGET=git).
Environment Variables
Implementing a Custom Publish Target
To publish to a different platform (Netlify, AWS, a CMS, or your own CI/CD pipeline), implement thePublishTarget interface and register it before the server starts handling requests:
PageDoc objects — your publish target receives structured JSON, not HTML. Your target decides how to store, transform, or deploy that content.
CMS Publishing (via Site SDK)
For CMS-backed sites (Contentful, Sanity, Strapi), the Site SDK provides publish utilities that handle the common workflow:- Resolve image URLs (rewrite localhost references, upload to CMS)
- SSRF validation on external image URLs
- Deduplicate image uploads within a single publish
- Push page content to the CMS API
examples/contentful-site/, examples/sanity-site/, and examples/strapi-site/ for complete CMS publish implementations.