POST /publish endpoint dispatches to whichever target wins selection.
The three built-in targets
| Target | Name | When it’s used |
|---|---|---|
| Site contract | site-contract | The default. Posts the draft pages to your Next.js site’s /api/publish route. Your site’s adapter then persists to your CMS. |
| Git | git | Writes a JSON snapshot to disk and (optionally) commits + pushes it. Good for “git as your CMS” setups or local dev. |
| Deploy hook | deploy-hook | Calls a Vercel/Netlify deploy hook URL. Use when content is committed externally and you just need to trigger a redeploy. |
Selection order
Every publish call runs through the registry in this order:- If
PUBLISH_TARGET=<name>env var is set and that target is registered → use it verbatim. - Otherwise iterate registered targets in registration order; pick the first whose
canHandle(ctx)returnstrue. - Fall back to the legacy
PUBLISH_MODEenv:git(default) ordeploy_hook→deploy-hook.
site-contract target claims any request that came from a registered site with a valid origin; the git target claims local-only deployments.
Site contract (the default)
Most production deployments use this. Avocado posts the draft to your site’s/api/publish route, your site validates the bearer token, and your adapter writes to the CMS.
Your site’s /api/publish handler is wired by the Site SDK. It validates the shared secret, then calls your CMS adapter’s write path. The orchestrator never talks to your CMS directly — your site is always in the middle, which means your existing CMS auth, hooks, and validation all still run.
Env vars:
Git target
Writes the draft pages as a JSON snapshot under your site’s content directory. Optionallygit commit && git push the change so Vercel / Netlify pick it up.
Good for:
- Local development without a CMS
- “Git as your CMS” setups where content is checked into the repo
- Static sites where publishing means triggering a rebuild
PUBLISH_GIT_AUTO_COMMIT=1 is set) commits with a generated message and pushes to origin. If the push fails (auth, conflicts, etc.) the publish call returns 502 and the tracker records the error.
Deploy hook target
Calls a Vercel or Netlify deploy hook URL. Useful when content is already in place — committed to the repo, or written to a CMS by some other process — and “publish” just means “redeploy.” Env vars:/publish/status to surface “building / ready / failed” in real time.
Building a custom target
PublishTarget is a two-method interface:
PublishContext (session, scoped session, draft pages, slugs, site config, image dir, logger), calls target.publish(ctx), saves the returned tracker, and replies with outcome.response at outcome.httpStatus. Your target controls every byte of the wire response.
Publish status
GET /publish/status?session=<id>&siteId=<slug> returns the latest tracker:
status: "ready" immediately.
Snapshots and rollback
Every publish writes a snapshot to the version log. From the MCP server (or the editor’s history panel) you can:avocado-list-snapshots— list published snapshots with commit shas + timestampsavocado-restore-snapshot— rewind the draft to a specific snapshot (doesn’t trigger a republish; you publish again to push the rolled-back version live)avocado-compute-publish-diff— diff the current draft against the last published snapshot before publishing
VERSION_LOG_CAP (default 100). Older snapshots are evicted FIFO.
See also
- CMS adapters — the site-side hooks the site-contract target calls into
- Architecture — where publishing fits in the orchestrator pipeline
- MCP server — Publishing tools — drive publishes from Claude Desktop