setup guide

Your first project, step by step.

About ten minutes. Haven't installed yet? Start with the installation guide.

01

Open your project's top folder, on a branch

Run Stet in the folder that contains .git, not inside src. A branch makes it easy to try and undo.

terminal
cd ~/code/your-project
git rev-parse --show-toplevel # prints the folder to use
git checkout -b try-stet
02

Set up Stet

terminal
stet init --mcp

Stet detects your stack and test command, then creates:

files
.stet/charter.md # what this is + always / never rules ← edit this
.stet/config.json # protected paths, ignore list
.stet/locks.json # locked behaviours
.stet/decisions.md # decision log
AGENTS.md # the rulebook every AI agent reads (kept in sync)
CLAUDE.md # points Claude Code at AGENTS.md
.mcp.json # connects Claude Code to Stet's tools
03

Write the charter

Open .stet/charter.md. Write one honest paragraph on what the product is, then edit the Always and Never lists. Add the things your AI keeps getting wrong. Then run stet sync.

04

Protect what must never change casually

In .stet/config.json:

.stet/config.json
"protect": ["migrations/**", "infra/**", ".github/**"]
05

Lock 2–3 things that already work

A lock is a feature plus a command that proves it. Use commands your project really has; run npm run to see them.

terminal
stet lock add "Site builds" --cmd "npm run build"
stet lock add "Login works" --cmd "npm test -- auth" --protect "src/auth/**"
stet check

No tests yet? Ask your AI: “Write one test that proves X works today. Don't change any app code.” Then lock that test. It's the most valuable ten minutes of the setup.

snapshot locks · v0.5

Lock behaviour without writing a test.

Many regressions are behaviour changes nobody wrote a test for: an export's column order, a renamed route, a mapping that shifted. Write a tiny script that prints the behaviour, and lock its output.

terminal
stet lock add "Export format is stable" --snapshot "node scripts/export-sample.js" --protect "src/exports/**"
stet lock add "API routes unchanged" --snapshot "node scripts/print-routes.js"
stet lock add "Report totals" --snapshot "python scripts/report.py" --mask "\d{4}-\d\d-\d\dT[\d:.]+Z"

Stet saves the output in .stet/snapshots/ as the approved version (commit it). If it changes, stet check fails and shows the difference:

stet check
✗ L3 Export format is stable (0.2s, snapshot)
│ output differs from the approved snapshot (- approved, + now):
│ @@ line 1 @@
│ - id,net,vat
│ + id,vat,net
│ intended? approve it: stet lock approve L3 --why "<reason>"
  • Intended change? stet lock approve L3 --why "PRO-91: VAT before net" saves the new output and logs it as a decision, which then shows in stet pr.
  • Timestamps or generated IDs? Add --mask "<regex>"; matches become <masked>.
  • Can the AI cheat? stet guard flags any snapshot edited by hand, and AGENTS.md tells agents never to approve snapshots.
  • Keep scripts deterministic: fixed sample data, sorted output, no network calls.
06

Block out-of-scope commits and commit the setup

terminal
stet hook install
git add .stet AGENTS.md CLAUDE.md .mcp.json
git commit -m "Adopt Stet"

every ai task

The loop: scope, work, check.

terminal
# 1. before: agree the task (with its ticket ID) and the files it may touch
stet scope set "LIN-142 Add CSV export" --allow "src/export/**,test/export*"
# 2. context: Claude Code and Cursor read it automatically. For any chat:
stet context --files "src/export/**" # copied to clipboard, paste into the chat
# 3. let the AI work, then:
stet guard && stet check
# 4. record real decisions
stet decide "Postgres is the only datastore" --why "audit trail"
# 5. ship it
stet pr # PR description, copied to clipboard
git commit -F .stet/.cache/commit.txt # "LIN-142: Add CSV export" + file list
  • Guard shows ✗: the AI touched files outside the task. Undo with git restore <file>.
  • Check shows ✗: something broke. Tell your AI: “stet check failed: [paste]. Fix your change, not the test.”

Working from Linear tickets? See the ticket workflow: Stet can pull the ticket for you.

07

Connect your AI tools

  • Claude Code: stet init --mcp already did it. Restart Claude Code once.
  • Cursor: add this to .cursor/mcp.json:
.cursor/mcp.json
{ "mcpServers": { "stet": { "command": "npx", "args": ["-y", "stet-cli", "mcp"] } } }
  • Codex, Copilot, Windsurf, Gemini CLI: they read AGENTS.md automatically.
  • ChatGPT, Claude.ai, Gemini chat: paste the output of stet context.
08

Handing over to a developer or CTO

terminal
stet handoff # writes HANDOFF.md: how to run it, architecture, what must not break, decisions

Command reference

In your terminal, stet help shows the same list.

stet init [--mcp]Create .stet/, AGENTS.md and CLAUDE.md. --mcp also writes .mcp.json.
stet scope set "<task>" --allow "<globs>"Agree the task and the files it may touch. Start the task with a ticket ID (LIN-142) to track it.
stet ticket [LIN-142]Fetch a Linear ticket (needs LINEAR_API_KEY). It goes into stet context and stet pr.
stet context [--files "<globs>"]Copy the live repo state to your clipboard for any AI chat.
stet guardFlag changes outside scope or in protected paths.
stet checkRun every locked behaviour. Fails if one broke.
stet lock add "<name>" --cmd "<cmd>"Lock something that works, with a command that proves it.
stet lock add "<name>" --snapshot "<cmd>" [--mask "<regex>"]Lock a command's output as an approved snapshot; any change fails stet check.
stet lock approve L3 --why "<reason>"Accept an intended snapshot change; logged as a decision.
stet decide "<decision>" --why "<reason>"Add to the decision log.
stet pr [--check] [--base main]Write the commit message and PR description from the diff, scope, checks and decisions.
stet handoffWrite HANDOFF.md, an onboarding pack built from the repo.
stet hook installBlock out-of-scope commits and add the ticket ID to commit messages.
stet statusOne-screen summary.

Troubleshooting

“proof command can't run (missing script)”: the lock uses a command your project doesn't have. Remove it with stet lock rm L1 and add one from npm run.

“No .stet/ folder found”: you're not in the project's top folder, or haven't run stet init there yet.

“stet: command not found”: use npx stet-cli … or install globally (see installation).

Still stuck? Open a GitHub issue with the command and its output.