Changing one line of copy through an LLM is slower than typing it yourself — you have to describe the change instead of just making it. So sitekit has a whole layer where words are edited deterministically, with no model in the loop. The brand still holds. Edits land in the canonical content store and are checked by verify like anything else.

The copy layer

Underneath all four surfaces is one idea: every word on the site has an address. A page’s copy is a set of leaf fields — hero.headline, pricing.tiers.0.label, chrome.footer.copyright — and each one is stamped into the rendered HTML as a data-sk-copy="<page>:<field-path>" anchor. That anchor is a durable locator. No selector guessing, no fuzzy text matching. Because the locator is exact, the commit can be exact too. Replacing a plain-text field is an inner-text swap with a field-grained containment proof — if an edit would reach beyond its own field, sitekit refuses it with E_EDIT_OVERREACH rather than writing something it can’t prove is contained.
Plain fields apply with no LLM. Markup fields are deferred to you. A field whose value is plain text is swapped deterministically. A field containing markup can’t be safely swapped by string replacement, so it’s reported as deferred and re-authored by your agent through the voice pack. Every surface below reports the same three outcomes: applied, deferred, failed.
Anchors are stamped by default on fresh emits. For pages built before you turned this on:
sitekit content anchor          # retroactively stamp data-sk-copy (best-effort, fail-closed)
The stamping density is a build-time choice — sitekit run --copy-editing <tier> takes off, essential (Lite), or comprehensive (Full), defaulting to essential.

1. The copy dashboard

The newest surface, and the one to reach for most of the time. A local writing environment over the copy layer:
sitekit dashboard --open
It starts on port 4321, binds 127.0.0.1 only, and gates every request on a loopback host and origin — because unlike the read-only dashboards this pattern came from, this one writes. Navigate to any page, edit its words, then run Import and Verify from the same screen. Deploy deliberately stays in your terminal.
sitekit dashboard                  # default port 4321
sitekit dashboard -p 5000          # bind a different port
sitekit dashboard --no-export      # don't generate copy docs for pages that have none
By default the dashboard generates a copy doc for any page that lacks one, so a site that has never used the copy layer is immediately editable. --no-export opts out.

Embedding it

The same UI ships as a mountable component, so a platform can host it rather than the CLI:
import { CopyDashboard } from '@yevgetman/sitekit/dashboard';
It’s one custom element with an open shadow root and zero runtime dependencies. It never fetches on its own paths — the host injects a CopyDashboardClient adapter and the element renders whatever that adapter can answer. Capabilities are gated by probe (typeof client[m] === 'function', never invoked), so a read-only copy viewer falls out of the contract rather than needing a flag. A prebuilt IIFE build is available for a plain script tag.

2. The front-end editor

Point at the live site, click the words, type the new ones. The browser extension captures the click on any [data-sk-copy] element, live-updates the text on the page, and queues the edit. When you hit Change, it POSTs the queue to a receiver running on your machine:
sitekit edit-bridge              # 127.0.0.1 only, default port 8787
sitekit edit-bridge --once       # exit after the first successful apply (scripted use)
The bridge exposes GET /health, POST /apply, and POST /preview, binds loopback only, and applies edits through exactly the same deterministic core as everything else. “Point, type, approve, done.” The extension itself is a separate connector — deliberately split out so it can later re-point from the localhost bridge to a hosted platform without the CLI changing at all.

3. The Markdown round-trip

The surface for a copywriter who doesn’t want a terminal or a browser extension — just a document.
sitekit content export              # project the store into content/copy/*.md
# → hand content/copy/pricing.md to whoever writes
sitekit content import              # apply the edited Markdown back
sitekit verify
export writes one readable Markdown file per page plus a brand file. Someone edits prose under clear ## field-path headings. import swaps it back — deterministically for plain fields, deferring markup fields to your agent. To see exactly where things stand across all three representations:
sitekit content status              # precise drift report: copy doc ↔ store ↔ HTML

4. Single edits from the command line

When you know the address and the new text:
sitekit content set pricing:hero.headline "Pricing that scales with you"
Or a batch from a JSON file:
sitekit content apply edits.json     # { "edits": [ { "page": ..., "field": ..., "text": ... } ] }
Both are deterministic, no LLM, same containment proof.

Shared chrome — edit once, apply everywhere

Nav and footer copy lives on every page. The reserved brand: address fans one edit out across every carrier page and updates the chrome subtree in content/messaging.yaml once:
sitekit content set brand:chrome.footer.copyright "© 2026 Acme, Inc."
brand is a reserved page slug — a real page can’t be named it (E_RESERVED_SLUG).

Inspecting the store

sitekit content show                  # the full parsed tree as JSON
sitekit content show messaging        # just messaging.yaml
sitekit content show pages.pricing    # one page
sitekit content lint                  # content + playbook checks (a subset of verify)

Which surface should I use?

SituationUse
You’re editing copy yourself, iterativelysitekit dashboard
You want to click the real page and typethe front-end editor + edit-bridge
A copywriter needs to work in a documentcontent exportcontent import
You know the exact field and textcontent set
A script or agent is applying many editscontent apply
The wording change is a brand changenot this layer — see Evolve
The copy layer is for known wording changes. If the business itself changed — a new value proposition, a repositioning, a shipped feature that changes the pitch — that’s the Evolve loop (sitekit brand evolve), which cascades an interpreted delta through the voice pack and re-authors the pages it affects. Using the copy layer for that just edits words while the brand source drifts out from under them.

What’s next

The four loops

Build, maintain, experiment, and evolve.

Voice packs

The rules every edit is still held to.