Skip to main content

Writing rules

Your rules live in stele.md, at the root of your project. A rule can be as simple as one sentence:

Never put credentials in code, config or tests.

That’s a complete rule. It applies to every file the agent writes.

Several rules​

Put a line with only --- between rules:

Never put credentials in code, config or tests.

---

Keep functions under 50 lines.

Apply a rule to some files only​

Add a scope line, then a blank line, then the rule:

scope: migrations/

Never edit a migration that has been merged. Add a new one instead.

Now the agent sees this rule only when it writes under migrations/.

A few examples of scopes:

You writeIt matches
*.goGo files, in any folder
**/*.goGo files, in any folder
/*.goGo files at the root only
migrations/Everything in migrations/
src/**/*.{go,ts}Go and TypeScript files under src/
["internal/**/*.go", "!**/*_test.go"]Go files in internal/, except tests

Scope as much as you can. A rule with no scope is shown for every file, and too many of those is just noise.

Have stele check a rule​

So far, these rules are only guidance. The agent reads them, but nothing checks that it listened.

To check a rule, give stele a pattern that spots a break:

scope: ["**/*.go"]
check: regex
pattern: fmt\.Print(f|ln)?\(
message: log through internal/log, not fmt.Print

Log through the shared logger in internal/log. Never print with fmt.Print,
Printf or Println.

If the agent writes a line that matches, stele sends it back with your message, and CI fails too.

Patterns use Go’s regular expressions. Two things tend to surprise people:

  • The pattern looks at text, so it also matches inside comments and strings.
  • Quotes count. pattern: "net/http" looks for net/http with the quotes around it.

Warn instead of block​

A checked rule blocks by default. To get a warning instead, add this line:

blocking: false

After you change a rule​

Run stele compile, and commit stele.lock and .claude/rules/stele-rules.md along with stele.md.

If you forget to compile, the hook does it for you on the next write, so your edit still takes effect. You just still have those two files to commit.

If something looks wrong​

If a rule can’t be used, stele compile tells you which one and why. The other rules keep working.

stele won’t catch a misspelled key, though. If you write scopes: instead of scope:, the line is ignored and the rule applies to every file.