Skip to main content
This page is for looking at Avocado Studio for the first time and deciding whether it deserves a second look. One command, a real site, about ten minutes. It assumes you have no project, no API key and no opinion yet. It is a research preview. Everything described here was measured on a real run rather than imagined, and the last section is a list of things that look like defects and are not. But it is early: expect rough edges, and expect the surface to move between releases. If you have already decided and want Avocado in a site of your own, that is a different job: add it to your site is where it lives. This page spends its length on what the demo shows you.

One command

A directory name on the command line means the demo, with no questions asked — somebody who has typed a name has already answered the only one that mattered. Run it with no argument and it asks which of the two jobs you want first, then the directory name. The first command creates the project and installs it. One measured run on a warm npm cache took 6.1 seconds end to end, wrote 29 files, asked nothing and printed no errors. What lands in node_modules is Next 15.5.15, React 19, the five Avocado runtime packages — site-sdk, orchestrator-core, blocks, shared, preview-adapter — and the editor CLI as a dev dependency. Node 22 or newer; the SQLite binding ships a prebuilt binary for it, and older Node falls through to compiling from source. Both ports are chosen at scaffold time from what is actually free on your machine, starting at 3000 for the site and 4100 for the editor, so this runs happily beside whatever else you have going. npm run dev then starts two processes and prints a banner:
It opens that second URL for you. Opening the site directly shows the finished pages with no editor around them, which reads as “the product did not start”.
The ?siteId= is load-bearing, not decoration. The CLI serves a prebuilt editor bundle and injects the orchestrator and preview origins into it, but not a site id — so without one the bundle falls back to its own built-in default and asks for a session this project never configured. It happens to render anyway, because the orchestrator bootstraps an unknown session from the adapter and gets the same nine pages. That is exactly what makes it worth pinning: the demo looks correct while the id in the URL and the id in the route file are different strings. The id is derived from your directory name, so my-site/ gets siteId=my-site, and the generated route file agrees.
Two processes, both on your machine, no third service to deploy: The orchestrator runs inside the Next.js app rather than beside it. That is library mode, and it is the shape most integrations use.

What to click, and what each click proves

You land on the Avocado Hub: nine pages, sixty blocks, and all eighteen built-in page block types on screen. The two built-in types missing from it are the site header and the footer, which belong to the site rather than to a page — so every type a page can hold is somewhere in here, already filled with real copy.
1

Switch pages in the preview

Nine slugs, from a home page of thirteen blocks down to four-block pages like /oranges and /olives. Every block type you would have to implement on your own site is already rendering in one of them.
2

Turn on the element picker, then click a block

The arrow-and-sparkle button in the chat composer — hover it and it reads Select an element — toggles click-to-select. Click a heading, an image, a card. The overlay highlights the block and the chat learns what you have in mind. Escape turns it back off.This proves the part of an integration that is hardest to get right: a DOM node in the rendered page maps back to a typed block in the content.
3

Edit a field in the property panel

With a block selected, the panel on the side lists its real fields and writes real values. No model is involved — the panel drives the same typed operations the chat does, straight to the orchestrator.
4

Undo it

Every applied change carries an undo in the chat entry that produced it, and a global undo and redo sit directly above the message box (Ctrl+Z, or Cmd+Z on a Mac). Undo is server-side history, not a browser trick.
5

Publish

Publishing is a separate, explicit step. The editor posts to the orchestrator, which hands the current draft to the adapter, which rewrites content/pages.json. A measured run answered {"status":"ready","written":true,"count":9}, the file on disk changed, and the new text appeared in the rendered HTML.
6

Then try the chat

Chat is the one thing that wants a model — and it answers without one. That is the next section.

No API key is needed to look around

Everything above works with nothing configured. Chat does too, with a smaller promise, and the editor says so rather than failing. With no key, a notice sits directly above the message box saying so, and naming the full path of the .env.local to add a key to. The chat is answered by a deterministic planner: a short list of literal matchers, not a small model. So the first-screen suggestions change to the ones that planner can actually execute: Three at most, and each one really edits the page — which is the claim the first screen is making. A clean-room run fired the keyless suggestions on all nine pages: 26 of 26 clicks produced at least one operation and every one applied. The honest limit is the shape of the planner, not its size. It matches literal phrases — “rich text”, “add testimonials”, “set the meta description to …” — so a sentence of your own invention usually comes back asking for a key rather than guessing. The suggestions are curated around that, deliberately.

What a key costs

Chat with a real planner behind it is the thing worth evaluating, and it runs on your key. Avocado never resells tokens, which also means nothing between you and the provider is metering the spend for you.

The three keys

One line in .env.local, in the project root — the same folder as package.json: Restart the dev server after adding one. Keys are read at startup, so a running server will not pick one up, and the symptom is a key that appears to have been ignored.

What a click costs

With a key, the first screen offers different suggestions: Translate the whole page to German always, one add-a-section suggestion chosen from what is already on the page, and Turn the hero into a bold call-to-action when the page has a hero. They are not priced the same, and nothing in the product says so. From the orchestrator’s own per-turn telemetry in a clean-room run on 0.11.3: Two things in that table matter more than the numbers. The three Add … chips are genuinely free, because the deterministic planner answers them without calling anything. And one chip is most of the bill — the one a curious person is most likely to press first. Translating a page rewrites every text-bearing block on it, so its cost scales with the page rather than with the sentence you typed; $0.1685 is its price on the cheapest page in the demo, and a four-block page is the cheapest thing it can be asked to do. Nothing in the UI distinguishes the free chips from that one.
Treat those as one run, not a price list. They come from a single session on one provider and model, against this demo’s page sizes. Your numbers will differ. What generalises is the shape: whole-page rewrites cost roughly an order of magnitude more per click than single-block edits, and the difference is invisible at the moment you click.
Keep a spend limit on the key you paste in, as you would for anything else that calls a model on your behalf.

What you will notice

Four things read as defects on a first run. All four are working as designed, and each one looks broken if nobody says so first. Click-to-select is off until you turn it on. The picker defaults to off, so a correct install looks inert: you click a heading in the preview and nothing happens. The cursor button in the composer is the switch. It defaults off because the preview is a live site — links, tabs and carousels should work when you are reading rather than editing — and a picker that intercepts every click makes the page impossible to browse. The first render of the editor takes a few seconds. On a cold .next, the editor’s first load of the site measured 3.83 seconds to first byte while Next compiled the route. Warm, the same request runs in 45 to 73 ms. The first paint is the compiler, not the product. The cold load itself is clean: 26 requests, none of them a failure. Publishing is a separate step, and the site proves it. Open localhost:3000 directly and you see the published page; the draft appears only under an editor context — the URL the editor’s preview frame uses. So after an edit, the plain site is meant to look unchanged until you publish, and content/pages.json is meant to be byte-identical. Both are true, and both are how you check that publish did something. This paragraph used to say the opposite — that development resolves an editor context for every request, so the bare URL shows unpublished edits. That was true once and is not now, and it was the worst thing on this page to get wrong: it told a reader to distrust the one check that tells them whether publish worked. npm run build && npm start gives you a site that renders and an editor that cannot load. That is the production gate, and it is deliberate. The orchestrator mounted inside your app can edit and publish your content, so with NODE_ENV=production and no credential configured it refuses every request rather than running open. A default that is convenient in development and catastrophic in production has to pick production. It says so once in the build output and once again at boot:
During next build that is a warning, with an added clause noting it was evaluated at build time and that the variables belong in the deployment’s environment. At runtime it is an error, because then it means requests really are being refused. Three things open the gate: ACCESS_PASSWORD_HASH (the sha256 of a password the editor prompts for), ORCHESTRATOR_ACCESS_TOKEN (a fixed bearer token, for scripts and CI), or an auth hook passed to createOrchestrator in code — including auth: () => true, which is a line you type on purpose and cannot arrive at by omission. A few paths stay open either way, because they answer before any caller could hold a credential: /health, /auth/status, /auth/verify, and the generated-images the rendered page loads in <img> tags. Set one of those and the editor reaches the password screen instead of the error. That sentence is newer than it sounds, and it took three releases to make true. A production deployment has to be told where its editor lives, and each of the three ways that could go wrong went wrong in turn: the generated orchestrator route was never told at all (0.11.2), the answer omitted a header the editor sends (0.11.3), and then the right answer went only to one of the two ways the editor’s address can be spelled (0.11.4). Every one of them had the same symptom — the editor reporting it could not reach a server that was answering 200 to curl the whole time — because a response a browser rejects is indistinguishable, from inside the browser, from a server that is down. A project scaffolded on 0.11.4 or later needs none of this explained: it writes EDITOR_CORS_ORIGINS, NEXT_PUBLIC_EDITOR_ORIGIN and ORCHESTRATOR_CORS_ORIGINS into .env.local with a comment on each saying which code reads it, and localhost and 127.0.0.1 are treated as the same address wherever you write either. An older project needs those lines added by hand — see the changelog for which does what, and publishing. What a production build is good for is seeing what a crawler gets: per-page titles, descriptions, Open Graph tags, a canonical link, and a real 404 on an unknown slug. In this demo those come out identically in development, so npm start confirms them rather than being the only way to see them. It is not the way to try the editor. For that, stay in npm run dev, which needs none of the above.

Where to go next

Wire it into an existing site

The quickstart is the other half of this story: a prompt for your coding agent, or the same wiring as one shell block, against a Next.js app you already have.

Bring your real site in

Your components, your CMS, your content. Three honest paths, measured in days rather than minutes.

The SDK

Routes, the page factory, custom blocks, CMS adapters, publishing — every seam an integration has to satisfy.

How it works

What happens between your sentence and the changed page, if you would rather understand the model before wiring anything.