semantic-claims
v0.1.0
Published
Validate and explore Semantic Claim documents and their executable proofs.
Readme
Semantic Claims Model
Semantic Claims is a simple way to keep software semantics understandable and testable as code changes.
It's designed to help people, coding agents, and sentient creatures build and maintain software together over time.
Links
- OVERVIEW.md: motivation and rationale
- FAQ.md: common questions about Semantic Claims, TDD, and acceptance criteria
- REFERENCE.md: the detailed rules for claims, proofs, document structure, and the authoring workflow
- EXAMPLES.md: claim-decision examples and borderline cases
- JAVASCRIPT.md: the JavaScript and TypeScript conventions
Introduction
Semantic Claims is very similar to TDD (one could call it STDD, though not my favorite acronym), with the difference being that the tests are driven by, and linked to, semantics.
Semantics are the intended observable behaviors of whatever is being built. These behaviors are organized under named subjects, which represent a coherent and complete set of intended observable behaviors. They then pass through a three-step workflow:
claim -> prove -> implement
└────────────────────┘
Just like TDD 🎉Breaking down the steps:
- claim: state the intended observable behavior in a well-formed Markdown file
- prove: write tests that prove the implementation exhibits the claimed behavior
- implement: write or update the implementation until the proofs pass
This produces three colocated artifacts. For example, in a TS codebase:
src/
├── range.invariants.md <- the subject's semantic claims
├── range.invariants.test.ts <- the subject's semantic proofs
└── range.ts <- the subject itselfIf a proof unexpectedly fails, use its claim to check the intended outcome before changing the proof or implementation.
In practice
Claim documents
Claim documents are well-formed Markdown files that enumerate a subject's intended observable behaviors. In this example, a numeric range includes both endpoints.
The claim document from above (src/range.invariants.md) contains a single claim:
# Range
## §1 Endpoint inclusion
### §1.1 Both endpoints belong to the range
A value equal to either endpoint is included.This is a (non-exhaustive) minimal, well-formed claim document:
Rangeis the subject (semantic scope) of the claimsEndpoint inclusionis a claim set, grouping one or more claims togetherBoth endpoints belong to the rangeis a single claimA value equal to either endpoint is included.is the claim's statement
Implementation changes that preserve the claimed behavior should not require claim edits. If routine implementation changes require new claim wording or a new subject name, check whether you have described a private mechanism or chosen an incomplete scope.
Proofs
Each claim document has one paired proof file containing tests of its claimed behaviors. In this JS/TS example, the paired proof is named src/range.invariants.test.ts, and its tests repeat the section and claim titles exactly:
describe('§1 Endpoint inclusion', () => {
it('§1.1 Both endpoints belong to the range', () => {
const range = createRange(2, 5);
expect(range.includes(2)).toBe(true);
expect(range.includes(5)).toBe(true);
});
});The colocation and matching structure allow tools like the checker provided in this package to verify links between well-structured claims and proofs, as well as catch issues like missing proofs.
Claim kinds and scope
There are two kinds of claims:
- an invariant states semantics that remain true whenever its conditions apply
- a scenario states semantics whose expected result depends on event order
Invariants are direct statements, while scenarios can be structured with Given/When/Then to make the conditions, events, and outcomes easier to follow (it's not a requirement though—you do you).
Cross-cutting claims are a way to scope and specify semantics belonging to an interaction between multiple subjects. For example, a claim about the interaction between a search filter and published results can be placed alongside both subjects:
search/
├── --search-submission.scenarios.md
├── --search-submission.scenarios.test.ts
├── search-filter.ts
├── search-results.scenarios.md
├── search-results.scenarios.test.ts
└── search-results.tsThe cross-cutting claim sits in search/—the closest directory containing files for both subjects. Its -- prefix distinguishes it from claims about either local subject.
Design and planning
Use Semantic Claims within your existing design and planning process:
| Activity | Question | | --- | --- | | Design exploration | What should we build, for whom, and which tradeoffs should we accept? | | Claiming | Which intended observable behaviors warrant claims, and how do we state them precisely? | | Implementation planning | How will we build and verify those behaviors? |
You can draft claims during design, write them after design decisions are settled, or add them to existing software once its intended behavior is established. Claiming requires clear intent for the behavior in scope; a separate design phase is optional.
When working with an agent in planning mode, use the conversation to explore design, draft claim wording, and plan implementation. Claims don't need to exist before planning begins. Revisit proposed claims and design decisions as needed while assessing feasibility. When execution begins, write or update the accepted claim documents before their proofs and implementation.
Keep useful design rationale and implementation steps in your design notes or plan. Maintain the claims alongside the code as the record of intended behavior after the planned work is complete.
Tooling
The repo also includes a JS and TS claim checker and local Semantic Explorer, plus an agent skill that can be used to help integrate the method into development workflows.
Fun fact! Semantic Claims were used to build the validation scripts, if you want to see the model in action.
You can install the checker as a dev dependency:
npm install --save-dev semantic-claimsIt supports Node 22 and newer. I've also used it successfully in a pnpm monorepo, but ymmv.
Add commands for checking claims and opening the explorer:
{
"scripts": {
"check:semantics": "semantic-claims",
"explore:semantics": "semantic-claims explore"
}
}The checker verifies the links between claim documents and proof files, including their identifiers, titles, and test structure:
npm run check:semanticsProofs are just normal tests and should run as part of your test harness.
The JS and TS conventions define the supported filenames and the exact links between claims and proofs.
The commands semantic-claims invariants and semantic-claims scenarios are also available when only one claim kind needs checking.
Explore claims
Start the Semantic Explorer from the project root:
npm run explore:semanticsThe command checks the claim links, starts a read-only local server, and prints the URL. The explorer is a nice little dashboard that groups claims by subject and supports filtering by claim kind, cross-cutting status, and text. Restart it to pick up file changes.

Install the agent skill
The Semantic Claims skill follows the open Agent Skills specification. From a project root, install it with the skills CLI:
npx skills add hejhi/semantic-claimsAppend a release tag, such as hejhi/semantic-claims#v0.1.0, to install the skill matching that checker release. Update or remove it with npx skills update and npx skills remove.
Earlier releases installed four semantic-claims-* skills. Delete those directories after installing this one.
Use the agent skill
Select semantic-claims in your agent's skill picker, or mention Semantic Claims in a request, and describe the work:
| Ask for | Example |
| --- | --- |
| Claims | "Write claims for how Range treats its endpoints." |
| Proofs | "Write proofs for the claims in src/range.invariants.md." |
| Implementation | "Add an overlaps method to Range." |
| A review | "Review this diff against its claims." |
A request for claims or proofs completes only that stage. Feature work and bug fixes include the claim and proof updates they need.
Remove it
Uninstall the checker package and remove its package scripts if present (no claims or proofs will be harmed in the process):
npm uninstall semantic-claims