Stele: what you decided stays decided

The problem: a project’s requirements are written months apart. Each one is reviewed against whatever the reviewer remembers, and nothing rereads last spring’s rule when this autumn’s lands. A coding agent then builds whichever one it reads. The contradiction shows up in production, as a feature that cannot be used or a job that stops early.

What Stele does: it turns each requirement into a rule it can check, finds the requirements that cannot all hold, and asks you which should. What you approve lives in the repository. From then on, the agent gets the approved requirements each request touches, and a request that cannot keep one makes it stop and ask you before it edits anything.

A Claude Code session with Stele: the owner states a rule and approves it in a permission prompt; a later request that breaks the rule makes the agent stop and ask

A real Claude Code session on a small example project, with the waiting cut.

Preview. Stele is open source and works with Claude Code. The commands work end to end on real repositories. Measured accuracy is uneven, and stated below.

Two commands

latest →
cd your-repo
stele init

stele init finds your spec format and writes Stele’s short instructions and hooks for Claude Code into the repository. Commit what it writes, and every teammate’s agent runs the same loop. Stele is one file with nothing else to install: the Z3 solver is built into it.

After that you do not run Stele. The agent does.

What you see

The approval prompt holds back an agent that would approve for you by mistake. It is not a security boundary.

The specs you already have

Your project writes Stele reads
Spec Kit specs/
OpenSpec openspec/changes/ and the merged specs
Kiro .kiro/specs/
Plain Markdown specs/, docs/specs/ or docs/, or the folder you name: every statement with a MUST, MUST NOT, SHOULD or MAY
Nothing yet stele init sets up requirements/, and the agent keeps it: one line for each requirement, with an ID

Specs kept somewhere else in the repository are one setting away. Name the folder in stele.yaml, and Stele reads every Markdown file under it:

specs:
  root: design/rules
  format: markdown
  snapshot: .stele/accepted-statements.yaml

A project has one spec folder, and it is inside the repository. Stele does not read specs spread over several folders with no common parent, or kept in a wiki or a shared document.

On a project with specs already, the first commit that touches them says how to adopt: Stele reads every requirement once and asks you about the contradictions a reader of your specs would also find. Clashes only its own rules show, it settles itself and lists in the report.

How it works

  1. Read. Each requirement becomes a rule over one vocabulary shared by the whole project, so one fact has one name. A requirement Stele cannot express is reported, not dropped.
  2. Check the reading. Stele asks whether each rule covers every clause of its requirement and no more, reads a misread requirement once more, and names what it could not cover.
  3. Find contradictions. A model proposes them. The Z3 solver confirms the ones it can express, each with a situation in which the rules cannot all hold.
  4. Ask the owner. Each contradiction is settled against the code first, then put to you as a question. Your answers are saved as decisions and lessons, committed with the specs.
  5. Guard. Every later change is checked against every approved requirement, reading only what the change adds or edits. The hooks that inform the agent call no model.

What stays on your machine

The approved requirements, your approvals and the lessons live in the registry, committed with your specs. While a change is open, Stele keeps its readings and your answers in .stele/change/, which is never committed and is removed when you approve. It keeps no copy of its prompts or of the model’s replies, except the calls of a reading that failed, until that change is approved. What it reads from your project reaches the model marked as material, never as instructions. --max-cost limits what a whole check may spend.

With Shale and Prism

Stele stands alone. It is also one of three Provasign tools, each answering a question the diff cannot.

What to expect

Measured on case studies and held-out sets. These are single runs on small labelled sets, and a rerun can read a requirement differently.

A conflict reported as proved holds for the rules as approved. “No conflict” is a statement about those rules, within stated bounds, not about the prose. Stele does not prove that the code implements the spec. What a verdict means states the semantics.

How it compares

Checked against each tool’s public documentation on 2026-11-09. Where a column says no, that is what the documentation showed, not a proof of absence.

Tool Finds contradicting requirements Across how much Checked by Remembers what was decided
Kiro Requirements Analysis Yes, as two-option questions One spec’s requirements file A model and a solver The answer rewrites that file
Spec Kit analyze and clarify As one item of a consistency pass One feature and the constitution A model In that feature’s spec
OpenSpec validate No Structure of one change Rules of form No
Stele Yes, as questions with an example and what the code does Every approved requirement in the repository, whenever it was written A model proposes, a solver confirms A registry of approved readings, decisions and lessons, in git

Kiro does the closest thing, inside its own IDE and for one spec at a time, and it also derives property-based tests, which Stele does not. What Stele adds is the span and the memory.

Not yet

Try it

Try Stele takes about an hour on a project of your own and says what to send back. The source, the docs and the issue tracker are at github.com/provasign/stele.