How it works
How Intentset works.
Intentset has two halves. One is a set of conventions for writing down what your product does, as ordinary files in your repository. The other is a toolchain that reads those files and tells you, plainly, whether the code, the tests and the explanations you publish still agree with them.
This page walks through it in the order you would meet it: the files, the model they form, how ownership and evidence attach to it, and what the tools do with the result.
The short version
- Write records. Each behavior, rule, slice and check is a Markdown file with YAML frontmatter, reviewed in pull requests like the code beside it.
- Link them once. A record names what it points at. Intentset works out the reverse, so every behavior knows its rules, its owner, its checks and its explanations.
- Give each behavior one owner. A slice of your code is accountable for it, and an architecture check keeps other code out of that slice's internals.
- Attach evidence. Test runs from CI are tied to a commit, and only a pass on the commit under review counts.
- Review the impact. Before a change merges, see every behavior, owner, check and explanation it could reach.
- Publish safely. Reviewed explanations go out for one audience and one release, and nothing internal leaks through.
Open files. Explicit meaning.
Every artifact in the model is one Markdown file with YAML frontmatter. The frontmatter is the part tools read: a stable ID, a type, a status, an owner, the audiences it is written for, and its links. The body is the part people read, with the sections its type requires. A behavior, for example, has to say who acts, what triggers it, what happens when it succeeds, and what happens when it fails.
---
markset: 0
intentset:
spec: "0.1"
profile: intentset/behavior/0.1
id: BEH-ASMT-SCHEDULE
type: behavior
title: Schedule an assessment
status: draft
owner: team-assessment
visibility: internal
audiences: [engineering, product]
parent: CAP-ASMT-ASSIGN
links:
governedBy: [RULE-ASMT-FUTURE, RULE-ASMT-AUTH]
# availability: the products, releases, roles and editions it applies to
---
# Schedule an assessment
## Behavior
A teacher submits a future release time for a published assessment and a class.
## Preconditions
The teacher may assign to the class, the assessment is published,
and the requested time is in the future.
## Outcomes
Success: the schedule is recorded. Failure: an invalid time, an
unauthorized class or an unpublished assessment is rejected, and
no schedule is created.
Keeping the model in files is a deliberate choice, and it has consequences worth knowing:
- Records are reviewed in the same pull request as the code they describe, by the same people.
- They read on GitHub, in an editor or in a terminal, with nothing installed.
- The repository is the source of truth. The graph, the reports, the Atlas and the published pages are views rebuilt from these files, and no tool ever rewrites them.
- There is no database and no hosted service to run.
A typed model, centered on behavior
There are twelve record types. They fall into five groups, each answering a different kind of question:
| Group | Types | The question it answers |
|---|---|---|
| Why | product, intent, outcome | What are we building, why, and what measurable change would show that it worked? |
| What | capability, behavior, rule, scenario | What can users do, exactly what does the system do, what must stay true, and what is a concrete example? |
| Where | slice, contract, decision | Which part of the code delivers it, what may other parts rely on, and why was it built this way? |
| Proof | verification | How is a claim checked? |
| Words | knowledge | What may we tell a given audience? |
The behavior is the center of the model. It is one recognizable promise, including how it fails: schedule an assessment for a future time, rather than assessments. When parts of a behavior would be released, owned or reviewed separately, they are separate behaviors. A rule can govern many behaviors and is written once, not copied into each. A scenario is a worked example; it shows the promise, and it does not prove every case.
People arrive from different ends and meet at the same records. A product reviewer starts at the top and drills down, from product to intent, outcome, capability and behavior. An engineer starts from the slice they are working in. Both end up reading the same behavior.
Every link is written once
Relationships are frontmatter fields, written on the record that points:
- a behavior is
governedByits rules - a scenario
illustratesa behavior - a slice
implementsbehaviors, andexposesorconsumescontracts - a verification
verifiesbehaviors, rules or scenarios - a knowledge record
explainsbehaviors, rules or capabilities
The reverse is never written down. "Which slice implements this behavior?" and "which checks cover this rule?" are worked out from the forward links, so there is no second copy to drift out of step with the first.
IDs are permanent. Moving a file or rewording a title keeps the ID. Splitting a behavior creates new IDs and retires the old one with a replacedBy link, so history still resolves.
intentset validate checks the model: every reference resolves to a record of the right type, nothing loops, every active rule governs something, and every type has its required sections. Each diagnostic names the file, the field and how to fix it. Validation reads and reports. It never runs your code, calls the network or changes a file.
Each behavior has one owner in the code
This part comes from the Traceable Vertical Slice Architecture specification. It is optional: the model above stands on its own, and you can add ownership later.
A slice is the part of the codebase accountable for a set of behaviors, end to end: interface, logic, backend access, tests and documentation. Every behavior past the draft stage has exactly one. Other slices may collaborate, but through declared contracts rather than by reaching into each other's files.
The slice record says which files it owns, which entrypoints are its public surface, and how its internal layers may depend on one another. intentset architecture check reads your imports and reports what breaks that declaration:
- another slice importing a private file instead of an entrypoint
- a dependency between slices that nobody declared, or a cycle between them
- a layer importing one it is not allowed to
- two slices claiming the same file
- product behavior living in shared or infrastructure code
A real codebase rarely starts clean, so adoption is by scope. Record today's violations as a baseline, block new ones, and retire the baseline over time. The reference profile maps all of this onto TypeScript and AWS Amplify Gen 2.
Verified means passing now
A verification record defines how a claim is checked: an automated test, named by its file and a stable selector, or a manual review procedure. That definition is not evidence. It says how to check, not that anyone did.
Evidence is a separate run record: this check, on this commit, against this version of the graph, in this environment, passed, failed, was skipped or errored. intentset evidence import turns a Vitest or node test report from CI into run records.
Only a pass on the commit under review counts. A pass from an earlier commit is stale, and skipped, errored and missing runs never count as passing. Reports always show two numbers side by side: how many claims have a check linked, and how many have a current pass.
Keep run records in CI or another store you control, never in the commit they assess. A record committed to the repository describes a commit that stops being the latest the moment it lands.
See what a change reaches
intentset impact starts at any record and follows the links outward: the behaviors that depend on it, the slices that own them, the checks that verify them and the knowledge that explains them. Governing rules, contracts and decisions come along as context for the reviewer. Direct effects are kept apart from candidates further away, and every result says which path reached it. Reaching something is a reason to look at it, not proof that it changed.
intentset review --base main gathers the same picture for a branch: the checks, the coverage, and the impact of everything that changed.
Context for agents, with limits
An agent about to change code should know what that code promises. intentset context and the read-only MCP server hand it the owning slice and its behaviors, rules, scenarios, contracts and decisions, with the snapshot and source paths they came from, and nothing outside that boundary.
The agent is expected to update the records and checks its change affects, in the same review. Validation passing does not let it approve its own release or publication.
Rich documents, with Markset.
Knowledge records are explanations written for an audience, such as teachers. Each carries a visibility (public, customer, internal or restricted) and the products, releases, roles, editions and feature flags it applies to.
intentset publish builds what one audience may see for one release. It denies by default, intersects every availability dimension, leaves out drafts and retired records, and never reveals the title or path of anything it excluded. The output is a set of Markset documents that carry their provenance: the source IDs and revisions, the snapshot and the reviewer. When a source changes, the explanations that depend on it are marked for review before they can be published again. Customer-facing tools read only this publication, never the engineering graph.
Markset provides the document format, and Intentset adds metadata and meaning to it without adding any syntax. See how Markset fits.
The Atlas: the model, for review
intentset serve builds the Product Atlas, local pages for reviewing the model: capabilities and behaviors, owners, verification status and publication readiness. Every count says what it counts (linked checks or current passes), over which scope and which snapshot. Missing or stale evidence is shown as missing or stale, never folded into a green status.
Adopt in levels
Conformance comes in five levels, each including the ones before it. Start at the first and stop wherever the value runs out.
| Level | What it adds | What you can then claim |
|---|---|---|
| L1 Product model | Records parse, link and read correctly | The model is well formed |
| L2 Traceable implementation | Ownership and architecture checks | Each behavior has one owner, and the code respects it |
| L3 Verified product | Current passing evidence | Each claim passed on this commit |
| L4 Published knowledge | Reviewed audience projections | What you publish is authorized and traceable |
| L5 Continuous product truth | CI checks, impact reports and release automation | All of the above, kept true on every change |
intentset validate --level L3 runs every check up to that level. A claim always names its scope and snapshot: one capability passing at L3 is not a repository at L3.
What it does not do
- It does not prove the product correct. A linked, passing test can still assert the wrong thing, and people judge whether a check is adequate.
- It does not need a database, a hosted service, a particular test framework or a cloud.
- It does not replace your issue tracker. Tickets describe changes; records describe the behavior that persists after them.
- It does not run your code, call the network or edit your files when it validates, builds the graph, checks architecture or reports impact.
Try it on one behavior
npm install --save-dev @intentset/cli
npx intentset init --example
npx intentset validate
npx intentset impact BEH-ASMT-SCHEDULE