setup guide
Your first project, step by step.
About ten minutes. Haven't installed yet? Start with the installation guide.
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.
cd ~/code/your-projectgit rev-parse --show-toplevel # prints the folder to usegit checkout -b try-stet
Set up Stet
stet init --mcp
Stet detects your stack and test command, then creates:
.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 logAGENTS.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
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.
Protect what must never change casually
In .stet/config.json:
"protect": ["migrations/**", "infra/**", ".github/**"]
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.
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.
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:
✗ 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 instet pr. - Timestamps or generated IDs? Add
--mask "<regex>"; matches become<masked>. - Can the AI cheat?
stet guardflags 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.
Block out-of-scope commits and commit the setup
stet hook installgit add .stet AGENTS.md CLAUDE.md .mcp.jsongit commit -m "Adopt Stet"
every ai task
The loop: scope, work, check.
# 1. before: agree the task (with its ticket ID) and the files it may touchstet 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 decisionsstet decide "Postgres is the only datastore" --why "audit trail"# 5. ship itstet pr # PR description, copied to clipboardgit 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.
Connect your AI tools
- Claude Code:
stet init --mcpalready did it. Restart Claude Code once. - Cursor: add this to
.cursor/mcp.json:
{ "mcpServers": { "stet": { "command": "npx", "args": ["-y", "stet-cli", "mcp"] } } }
- Codex, Copilot, Windsurf, Gemini CLI: they read
AGENTS.mdautomatically. - ChatGPT, Claude.ai, Gemini chat: paste the output of
stet context.
Handing over to a developer or CTO
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 study "<topic>"Map a flow: routes, Mermaid diagram, key and supporting files, tests, protection gaps → docs/flows/<topic>.md.stet studyList studied flows and which are out of date.stet context --flow <topic>Context pack with the flow doc and all its files.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.