User guide · The model

How stet works

One model sits behind every command in this guide. This page walks through it once, top to bottom — after that, each chapter is the model in action.

What stet manages
  • Every word your products say — headlines, button labels, email copy, SEO fields — in one registry behind typed keys
  • Anyone on the team edits and publishes in seconds, without a deploy
  • Every change is versioned and can be reverted in one clickComing
What stays in code
  • Layouts, markup and email template design — never open in an editor
  • New pages, new sections, new kinds of email — built by a developer or an agent
  • …and the moment new structure lands, its words join the registry too

Editors only ever touch the words, which is why an edit can't break a page or an email's design. The sections below walk each piece.

01The split, inside a real component

Here is where the line runs. The markup is structure — a developer's, an agent's. The two strings are words, read from stet through typed keys.

An editor can change either string at any time, and nothing they do can reach the markup around it.

// The structure is code — yours.
<section class="hero">
  <h1>{copy('hero_headline')}</h1>      // The words are stet's.
  <a href="/signup">{copy('hero_cta')}</a>
</section>

02Every word has a typed key

Each word lives behind a named key. Keys are typed: your editor autocompletes them, and a misspelled key is a compile error, not a blank space in production.

Two committed files carry the registry. descriptor.json says what exists — each key's shape and the plain-language label an editor reads. defaults.json holds what every key says today, so your repo always carries a complete copy.

// content/descriptor.json — what exists
"hero_headline": {
  "shape": "text",
  "target": "web",
  "label": "Headline",
  "help": "The first line a visitor reads."
}

// content/defaults.json — what it says today
"default": {
  "hero_headline": "Never miss a post again."
}

03Changing a word is a transaction

Edits are drafted, diffed against what's live, and published. A publish goes live in seconds, without a build or a deploy, and lands as a new version — so any change can be walked back. The edit chapter walks the day-to-day rhythm.

On a snapshot-only site, the dashboard is the everyday way in. You pick the text on the page, type, see it in place, and commit. The commit is the publish.

$ npx stet draft promo_banner --value "Spring sale — 20% off"
$ npx stet diff promo_banner
$ npx stet publish promo_banner

04One registry, three surfaces

The same registry serves everything your products say — the mechanism doesn't change with the surface. Email copy lives in named slots inside your templates, and the email chapter proves adoption changes nothing about how they render. SEO fields are keys too, validated offline in the check chapter.

SurfaceWhat stet manages
WebPage copy, button labels, link text
EmailSubjects, body lines, button labels — inside your own templates
SEOTitles, descriptions, structured-data facts

05Packs seed a complete startComing

A pack is a ready-made key set for a kind of business. Instead of inventing every key yourself, the pack seeds them — and a new project starts complete instead of empty.

  • The keys for your kind of site — pages, emails, SEO fields
  • Plain-language labels and help on every field, so editors need no manual
  • Starting words in every field, ready to edit

06Your content is always yours

Everything lives in your repo — defaults.json is a complete, committed copy of every word, and the store is plain Postgres, or no database at all. If you ever leave, eject removes stet and your content stays exactly where it is. The leave chapter shows it.

$ npx stet eject

07Agents work under your rules

An AI agent connects over MCP and discovers stet's actions as typed tools — nothing to teach it.Coming Its writes take the same path as everyone else's.

  • Drafts and publishes through the same validated, versioned path
  • Can be scoped to drafting only, leaving publish to a person
  • init leaves a marked guidance note in AGENTS.md, so coding agents route copy through stet — eject removes it
  • No side door — an agent write can't skip validation, versioning or review