Sandbox Sites

A sandbox site is a complete Leed site that lives only on your machine. It builds and previews like any other site, with no Leed account, no sign-in and no CMS behind it, so you can design and fill a whole site before you sign up. When you are happy with it and have an account, the Leed plugin for Claude moves it into your real Leed site, creating every CMS record it needs along the way.

One command makes it:

leed site init --sandbox my-site
cd my-site
leed site build --serve

The site is now at http://localhost:8080, rebuilding as you edit, exactly as described in Local Development.

What --sandbox writes

leed site init --sandbox [dir] creates the site in dir, or in ./leed-sandbox when you give the flag on its own. The folder must not exist yet, or must be empty: init never writes over your files, and refuses any other target with invalid_arguments.

Into that folder it copies a fixed set of files that ships with the CLI:

  • identity.json holding { "companyId": "non-cms-company", "environment": "dev" }. That company id can never be a real one, and it is how every later command knows it is in a sandbox.
  • The data a build needs, under src/_data/ (page types, menus, labels, users, forms, search indexes, autolinks and calls to action) plus src/src.11tydata.json. In a real site the CMS publishes these files; here they are written once, by hand or by Claude.
  • A starting set of templates and styles: src/index.hbs, src/404.hbs, layouts, partials and tailwind/.
  • src/static/images/tmp/, where images wait until the move uploads them. The sandbox’s .gitignore excludes it.

It then installs Font Awesome Free into the site, the only download a sandbox init makes. Offline, the sandbox is still written and the result carries a warning: run leed site init --font-awesome inside the sandbox later to install the icons.

Nothing else a real leed site init does happens here. There is no sign-in, no clone, no git repository and no git hooks. The sandbox is recorded in the site registry, ~/.config/leed/sites.json, so leed site list shows it with sandbox: true and you can name it later by its folder.

Placeholder ids

Every record in a sandbox is named with a readable placeholder instead of a CMS id: ph-<kind>-<n>, such as ph-pt-2 for a page type or ph-page-10 for a page. Pages, menus and templates refer to each other through those placeholders exactly as a real site uses ids, so a pageid:ph-page-3 link and a menu item pointing at it both resolve in the preview.

KindPlaceholder
Page typeph-pt-<n>
Pageph-page-<n>
Labelph-label-<n>
Authorph-author-<n>
Menu, menu itemph-menu-<n>, ph-menuitem-<n>
Formph-form-<n>
Search indexph-index-<n>

Images are not placeholders: they are files in src/static/images/tmp/, referred to as /static/images/tmp/<file>. The move uploads each one to the asset manager and rewrites every reference.

What works in a sandbox

Everything that works on the folder alone keeps working. Everything that needs the CMS refuses, before it signs in or touches the network.

WorksRefuses
leed site build, including --serveleed site validate, commit and push
leed site eject, leed site vscode, leed site listleed settings …, every subcommand
leed import markdown, html, openapi and clean, which stage content for the previewleed import apply and leed import status
leed auth login, logout and status, and leed setupleed page … and leed asset …
leed mcp add --docs and leed mcp docsleed mcp add --cms
leed schema, leed self-update and shell completionleed deployments …, leed contacts … and leed feedback blocked

A refused command fails with the code sandbox_site and exit status 3, a precondition the move satisfies:

This is a local sandbox site (non-cms-company), and leed site push needs the Leed CMS.
Move the site into Leed first with /leed:site-sandbox-move in Claude.

No login or retry helps; the site has to be moved first. Inside a sandbox the CLI also skips its daily automatic update check, so the CLI never replaces itself while you work in one. The full code table is in CLI Troubleshooting and Exit Codes.

Plan features are all on

A sandbox has no plan, so nothing is gated locally: its template data names the Enterprise plan, which lets the preview render every template and style the CMS offers, paid ones included, so you can see how far your site could go. Your company’s real plan applies from the moment the site is moved. leed site eject --json reports tier: null in a sandbox, so a step that checks the plan, such as /leed:create recommendations or /leed:create cta, which need the Growth plan, stops there with the plan message.

Building a sandbox with Claude

The sandbox is designed for the Leed plugin for Claude, whose skills know how to write the records a sandbox holds. Ask Claude to start a sandbox site, or create one yourself and open Claude Code in it. Then:

  • /leed:create blog and /leed:create documentation have a sandbox path. Instead of calling the CMS they write the page type into src/_data/pageTypeList.json, a documentation set’s left menu and search index beside it, and the starter templates, each record with a fresh placeholder, and finish with a preview rather than a publish.
  • site-design-import turns a Claude Design handoff into the sandbox’s theme, layouts and menus, keeping its images as local files.
  • site-migrate stages a migration from Docusaurus, MkDocs, GitBook, Mintlify, ReadMe, VitePress or Nextra in the sandbox, with pages as Leed Markdown under leed-import/.

None of them publishes: every one ends with leed site build --serve and names the move. What each skill does is in The Leed Plugin for Claude: Skills.

Moving the sandbox into Leed

When you have a Leed account, two things come first: sign in, and set up your real site with /leed:setup, which leaves a raw-content checkout on your machine. See Get Started with the Leed Plugin for Claude. Then run /leed:site-sandbox-move in Claude Code. There is no CLI command for the move: it is a skill, with scripts that inventory, plan, rewrite, check and copy the sandbox, and it drives the ordinary leed settings, leed page and leed asset commands from inside your real checkout.

The move follows the CMS’s own dependency order, so each record exists before anything that refers to it:

flowchart TD
  Plan["Inventory and plan every placeholder"] --> Layouts["Copy and push the layouts<br/>(a page type needs its layout on staging)"]
  Layouts --> Types["Page types, labels, authors"]
  Types --> Pages["A placeholder page for each Markdown page"]
  Pages --> Images["Images to the asset manager"]
  Images --> Menus["Menus and their items, forms,<br/>search indexes, calls to action, autolinks"]
  Menus --> Check{"Any ph- id or staged image left?"}
  Check -->|yes| Rewrite["Map it and rewrite again"]
  Rewrite --> Check
  Check -->|no| Copy["Copy templates, tailwind/ and src/static/<br/>into the real checkout"]
  Copy --> Content["Fill the pages and import leed-import/"]
  Content --> Final["Final check, build, publish the new settings,<br/>validate, commit, push, check staging"]

After each step the move writes the real ids back into the sandbox in place of the placeholders, so the next step already carries them. A few things are worth knowing before you start:

  • Nothing is created twice. Every Leed site already has a root page type, a home page and a Header and Footer menu; the move maps the sandbox’s to those. Creating a documentation page type creates its left menu and search index, so those are mapped, not created.
  • Authors must be real users. The CLI cannot create users, so each sandbox author is matched to a team member by email. When nobody matches, Claude asks whether to invite them in the CMS first or credit someone else.
  • Templates above your plan cannot come across. The move checks your plan before copying, and tells you about any template the sandbox used that your plan does not include.
  • It fails loudly. The copy into your checkout runs only once no placeholder and no staged-image reference is left, and the final check fails if one reaches the real site or a created page was never filled.
  • It resumes. The move keeps its id map and a list of filled pages outside both folders, so a stopped move picks up from the first record it has not made.

The sandbox stays where it was, with real ids now in place of its placeholders, and is no longer needed; deleting it is up to you. The pages it filled are ready for review in the editor, like any page Claude writes.

ESC