Skip to main content
Avocado Studio is the operations layer for a website that already exists. Building the site is the part you have already solved; this is the weekly work that follows — copy, images, sections, metadata, translations — done by the people who own the content rather than the people who own the repository. Six ideas carry the whole product. Blocks are your components. Operations are the only thing anything can do. A plan is a proposal. A draft is what you see before visitors do. Publishing hands content back to wherever it lives. And the operation vocabulary is the safety boundary — not a policy layered on top of one.

A block is a component your site already has

A block is not an Avocado widget you have to adopt. On an existing site it is one of your own components, registered with a schema that declares which of its props are content.
That registration is the boundary you author. name, price and blurb have field metadata, so they appear in the property panel, the AI can edit them, and the preview can mark them for inline editing. badgeVariant is in the schema but has no field entry — it stays a developer concern, and no amount of asking will move it. Three properties of that declaration matter more than they look:
  • The schema decides what is legal. Every write is checked against it before it lands. An AI that tries to set price to a number is rejected, not coerced into something surprising.
  • Undeclared props survive. A block carrying its own bookkeeping — a CMS source snapshot, the locale it was read in, an origin slot a migration recorded — keeps it through an edit. Validation decides what is legal; it does not decide what is kept.
  • Adding a field is one line. When marketing needs something the panel does not expose, you widen the boundary deliberately, in your own repo, through your own review.
Twenty block types ship built in — Hero, FeatureGrid, Testimonials, FAQAccordion, CTA, Card, CardGrid, RichText, Stats, TwoColumn, Footer, SiteHeader, Embed, Banner, Carousel, Gallery, Tabs, Table, Quote and Video. They are a starting catalogue for a site built from scratch. On a site that already exists, the blocks are yours. See custom blocks for the full registration reference and the field table for deriving a schema, a panel, a projection and a merge from one declaration.

Pages, blocks and props

Content is structured data, never raw HTML.
  • PageDoc — one page. It carries id, slug, title, updatedAt, an ordered blocks array and optional meta (title, description, ogImage, path).
  • BlockInstance — one section on that page: an id, a type, and a props object.
  • Props — the fields that make up a block’s content, governed by the Zod schema the block was registered with.
The slug is an identity, not necessarily a URL. A slug is a path beginning with /; the home page is /, never "". When the URL a visitor uses differs from that identity — a locale prefix, a basePath, a CMS that owns its own routing — the URL goes in meta.path and the slug stays the identity. A field-level-i18n CMS keeps one editable page per document per language, so /de/events can be a page identity on a site that serves German at the root. See multilingual sites.

Operations are the safety boundary

An operation is a structured, schema-validated edit action. When someone says “change the hero heading to Welcome”, nothing writes HTML and nothing writes a file. The system produces this:
There are exactly nineteen operations. The list is not a summary of a larger capability — it is the capability, a discriminated union in packages/shared/src/schemas.ts, and every surface writes through it: the AI chat editor, the visual editor, the MCP server, the Jira integration and any direct POST /ops caller all submit operations against the same union. Read that table for what is missing. There is no write_file, no run_command, no install_dependency, no edit_component, no change_route. A model driving Avocado at full confidence with every guardrail switched off cannot express any of them, because the vocabulary has no verb for them. This is the difference between safety that is structural and safety that is procedural: a pull request, a reviewer and an audit log are human steps that can be rushed or skipped, and when they are, the blast radius is your production deploy. A type has no bad day.

Inside the boundary

Block props, list items, block order, page metadata, pages, navigation, theme tokens — validated, previewable, undoable.

Outside the boundary

Components, routes, dependencies, middleware, build config, CI. Not gated — unexpressible.

How an operation is validated

Every operation is checked before it changes anything.
  1. Shape. The operation must parse against operationSchema. A malformed op is rejected with a category, not silently dropped.
  2. Target. The page must exist, the block must exist, the anchor must exist, a list index must be in range.
  3. Props. When the site supplied a block manifest, the resulting props are checked against that manifest’s propsSchema — which is how your custom blocks are enforced. With no manifest entry, the props are checked against the registered Zod schema instead.
  4. Atomicity. A batch either applies in full or leaves the page as it was.
Failures are classified rather than lumped together: schema_violation, not_found, ambiguity, no_effective_change, malformed_output, planner_refusal, incomplete_output, internal_error. Only schema_violation is worth re-prompting a model about, so only that category triggers a repair pass — the rest either need a person or need nothing.

The block manifest

The editor and the orchestrator both need to know what blocks a particular site has, not what happens to be registered in their own process. Your site answers that at GET /api/editor/blocks.
A block definition may also carry listFields, a description, and chrome: true. A chrome block — a site header or footer — is structurally pinned: always present, never added, moved or removed. An agent reading the manifest needs to be told that, or it plans an add_block the engine will refuse. The manifest is the AI’s instruction manual as much as it is the validator’s rulebook. A block with a thin schema is a block the AI edits badly, so completeness here pays for itself. Coverage checks grade how much of it your pages actually expose.

Plans and approval

A chat turn produces an edit plan: an intent, a summary, a change log and a list of operations.
Most plans apply straight away, streaming into the preview as they are generated, and stay undoable. Some are held for explicit approval before anything is applied. The destructive-action gate holds a plan when:
  • it removes a page, always, whatever that page contains;
  • its operations touch more than one page in a single turn;
  • it contains three or more remove_block operations;
  • it would remove more than half the blocks on any one page.
Undo protects recovery. It does not protect intent: it is per page rather than atomic across pages, it does not help if nobody notices until the redo stack is cleared, and a model that deleted the wrong thing deleted it confidently. So these plans stop and wait. Approving a held plan applies the plan that was already produced — no second model call, no re-planning, no chance of a different answer than the one you read. Discarding it drops it.

Draft mode

Draft mode is how your own site renders unpublished changes.
  • Published content — what visitors see, stored in your CMS, database or files.
  • Draft content — what the editor shows, held in the orchestrator’s session state, invisible to visitors.
  • Publishing — promoting draft content to published, on your explicit action.
In draft mode your pages fetch from the orchestrator instead of your content store: GET /draft/pages, /draft/slugs and /draft/site-config, scoped by session and siteId. Your renderers are unchanged — they receive the same PageDoc either way. Two things authorise a draft request in production: Next.js draft mode already being enabled through your secret-gated /api/draft handler, or a valid secret on the request itself. The second exists because the editor renders your site in a cross-origin iframe where the draft cookie is frequently blocked outright. In development the __editor=1 routing hint alone is enough; in production it authorises nothing.

Undo, redo and the version log

Every applied change snapshots the page it touched before writing.
  • Undo and redo are per page, per session, capped at 50 entries in each direction.
  • A chat turn is one entry. A plan with six operations undoes as one action, because a sentence is what the person meant, not the six ops it decomposed into. Direct edits from the visual editor push their own entries.
  • The version log keeps up to 100 entries per session with restorable snapshots, so you can go back to a named point rather than stepping.

The three services

The two editing surfaces are not two products. The AI chat editor is the default: describe the change, watch the plan stream into the live preview, approve or undo. The visual editor — Puck-based, enabled per site — is click-and-drag on the same preview, with the AI chat alongside it. Both emit operations from the same nineteen. See visual editor mode. The site talks back over a postMessage protocol (site-editor/v1): clicking a block tells the editor which block is selected, and the editor pushes liveDraft frames during streaming and a draftUpdated frame when a change lands.

Bring your own model

The orchestrator calls your Anthropic, OpenAI or Google API keys. There is no token resale and no per-seat markup — you pay your own provider for your own usage. Each provider is exposed as four tiers, chosen in the editor per request, and each tier’s model name is overridable by environment variable: Not every request reaches a model at all. Simple, unambiguous edits are answered by a deterministic planner with no model call; a fast intent router handles the next tier up; the full planner runs only when it is needed. See AI providers and how it works.

Where to go next

How it works

A sentence, followed all the way to an applied, reviewable, publishable change.

Architecture

Services, packages and the data flow between them.

Custom blocks

Register your own components and declare which props are content.

Next.js integration

Routes, markers, draft mode, preview and publishing.