RIGOR.md format specification — v1.0
A RIGOR.md is a file at the root of a repository in which the people behind the code state, in their own name, how carefully it was made, whether they vouch for it, and who did which stage of the work. This document specifies that file: its layout, its stamp fields, the validation rules a conforming tool applies, and the prose a conforming tool generates.
A stamp declares its version with spec: "1.0". That is the only accepted
value. rigor.schema.json, shipped beside this document and identified by
https://rigor.diaconou.com/1.0/rigor.schema.json, is the canonical
structural schema; where prose and schema disagree, the schema wins.
1. File layout
A RIGOR.md is a Markdown document. Two regions are defined:
- The stamp: a fenced YAML block carrying the machine-readable claims.
- The summary block: generated prose between the markers of section 4.1.
All other content is free prose. A tool must not read it. A line under the
heading that names the convention and links to this specification is
recommended, so a reader who finds the file cold knows what it is; init
writes one.
1.1 Locating the stamp
- Find every line matching
^##\s+Stamp\s*$. The last one is the stamp heading. - After that line, the first line matching
^```ya?ml\s*$opens the block. - After the open, the first line matching
^```\s*$closes it. - The lines between the fences are the stamp.
Scanning is line by line, never a regular expression applied across the whole
file. A missing heading, open fence, or close fence is the error No stamp found. Expected a '## Stamp' section with a fenced yaml block.
1.2 Parsing the stamp
The stamp is YAML 1.2 under the core schema. A conforming parser must reject:
| Condition | Error |
|---|---|
| more than 65536 bytes of UTF-8 | Stamp is too large (N bytes; limit is 65536). |
| a YAML syntax error | Stamp is not valid YAML: <detail> |
| a duplicate mapping key | as a YAML syntax error |
| any anchor or alias | Stamp uses YAML anchors/aliases, which are not allowed. |
| a document that is not a mapping | Stamp parsed but is not a mapping of fields. |
The anchor and alias check runs before the tree is materialized, so an expansion attack cannot detonate during validation.
Under the core schema, bare yes and no are already strings, and a bare
date is a string. Three normalizations follow the parse:
rigoris trimmed and downcased. If the result is a known level name, it replaces the original; otherwise the original passes through unchanged, so section 3.1 reports it.trueandfalsebecomeyesandnoinsidechecksand insidevouch(an author may writecomprehended: true). A non-mappingcheckskeeps its real type, so the schema rejects it.spec,assessed, and each name undersignedare re-printed as their literal text, so an unquoted1.0stays the string"1.0".
2. Stamp fields
| Field | Required | Shape |
|---|---|---|
signed |
yes | a name, or a list of names (2.5) |
rigor |
yes | one level name (2.1) |
vouch |
yes | one claim, or a mapping (2.2) |
checks |
no | mapping, any subset of five keys (2.3) |
stages |
no | mapping, any subset of four stages (2.4) |
forked_from |
no | the project this was forked from (2.6) |
notes |
no | string |
spec |
no | "1.0" |
assessed |
no | YYYY-MM or YYYY-MM-DD |
Unknown keys are rejected at every level of the stamp.
2.1 rigor
Five level names, in order: unexamined, skimmed, comprehended,
engineered, owned. The name is the canonical encoding; a tool must emit
the name and must not emit an ordinal. comprehended and above are above the
comprehension line.
2.2 vouch
Either a scalar — yes, neutral, or withheld — or a mapping with the
required key claim holding one of those three, and the optional key why
holding a string.
2.3 checks
Keys: comprehended, quality_reviewed, security_reviewed, tested,
owned. Any subset may appear.
Each value is one of six strings, never a boolean:
| Value | Meaning |
|---|---|
yes |
done, actor unstated |
human |
done by a human |
ai |
done by an AI |
human-with-ai |
done by a human with an AI |
no |
not done |
not-applicable |
does not apply |
The first four are the done states.
A check may instead be a pair, [before LLMs, since LLMs]: who did it before
the advent of AI, and who has done it since. Only human, ai and
human-with-ai may appear in a pair, and a pair has exactly two entries. A
single value is a fact about the code as it stands.
2.4 stages
| Stage | Keys | Values |
|---|---|---|
idea |
by, depth, inspired_by |
by: human, human-with-ai, ai, upstream (2.6), or a pair [before LLMs, since LLMs]; depth: one-shot, considered, deep; inspired_by: free text, what the idea grew from |
plan |
by, depth |
as idea, without inspired_by |
implementation |
by |
human, human-with-ai, ai, upstream (2.6), or a pair [before LLMs, since LLMs] |
maintenance |
by, activity, scope |
by: human, human-with-ai, ai, none; activity: active, dormant; scope: evolving, complete |
2.5 signed
Who makes the statement: a string, or a non-empty list of strings. Every
name must be non-empty. With one name the generated prose speaks as I; with
more than one it speaks as we, and every sentence that carries a pronoun
takes its co-signed form from section 4.2. Names join as a, a and b, or
a, b and c.
2.6 forked_from
The project this one was forked from: a non-empty string, a name with or
without a URL. When present, idea, plan and implementation may name the
actor upstream, meaning that project, alone or in a pair. upstream without
forked_from is an error (3.2). forked_from without any upstream actor is
legal: a fork rewritten entirely. maintenance and the checks never take
upstream; they are the signers' own attestations.
3. Validation
Validation checks form and consistency. It does not check truth. Every value in a stamp is a self-report.
A validator reports errors, which make the stamp invalid, and warnings, which do not. Strict mode promotes one case noted in 3.2.
3.1 Structural
The stamp must satisfy rigor.schema.json: required fields present, no
unknown keys, every value drawn from its vocabulary. Structural errors stop
validation; semantic rules do not run against a malformed stamp.
3.2 Semantic
A headline level implies checks. The level may not exceed the checks that back it.
rigor |
Required check | Acceptable values |
|---|---|---|
unexamined |
— | — |
skimmed |
— | — |
comprehended |
comprehended |
yes, human, human-with-ai |
engineered |
comprehended |
yes, human, human-with-ai |
quality_reviewed |
done states | |
security_reviewed |
done states | |
tested |
done states, not-applicable |
|
owned |
all of engineered |
as above |
owned |
done states |
comprehended excludes ai: an AI that comprehends code does not put a human
above the comprehension line.
Where a check is a pair, the rules below read its since-LLMs actor: the level is a claim about the code as it stands. Three rules apply to each required check:
- Present with an unacceptable value — error:
rigor 'L' requires 'K' to be one of ["a", "b"], but it is 'v'.The value list is bracketed, comma and space separated, each element double quoted. - Absent while
rigorisengineeredorowned— error:rigor 'L' claims 'K' but it is not surfaced — show your working (add 'K:' under checks:).Above the line, a claim must show its working. - Absent otherwise — warning in strict mode, silent by default. At or
below
comprehended, a terse stamp stays legal.
Two further semantic errors: stages.maintenance.by is none while
activity is present — no one responds, so activity does not apply; and a
story stage names upstream while forked_from is absent.
3.3 Warnings
| Condition | Warning |
|---|---|
quality_reviewed or security_reviewed is ai while rigor is engineered or owned |
an AI-only review is a different claim from a human one at this level |
stages.maintenance.by is ai while rigor is engineered or owned |
unattended maintenance rarely sustains this level |
no spec key |
add spec: "1.0" |
The first names every affected check in one warning, not one warning per check, and reads the since-LLMs actor of a pair.
3.4 Drift
The generated prose of section 4 is derived from the stamp, so the two can never be allowed to disagree.
- If the summary markers are present in the RIGOR.md, the enclosed text must equal the composed block. A difference is an error.
- If a README is supplied, and the line markers are present in it, the enclosed text must equal the composed line block. A difference is an error.
- If the markers are absent, no check runs. The guarantee is opt-in.
Comparison collapses runs of whitespace, including line breaks, to one space and trims the ends; it is otherwise exact.
4. Generated prose
The sentences below are fixed. A conforming tool must reproduce them byte for byte, because section 3.4 compares generated text against stored text.
Each table with a pronoun has two columns. Signed by one is the voice of a
stamp with a single name under signed; co-signed is the voice when there
are several. The voice is chosen once and applied to every sentence.
4.1 Summary block
<!-- rigor:summary -->
**<summary>**
<!-- /rigor:summary -->
<summary> is the sentences of 4.2, in this order, joined by one space, and
wrapped by the author tool at 80 columns so the file reads as text. Line
breaks inside the block are not significant: the drift comparison of 3.4
collapses runs of whitespace to one space before comparing. A sentence whose
source field is absent is omitted:
This is a fork of <forked_from>.— only whenforked_fromis present; a fork's history begins before the signers', so it opens the summaryThe idea was <stage phrase>.The plan was <stage phrase>.- the implementation sentence
- the level sentence — always present
- the checks sentence
- the maintenance sentence
- the scope sentence
This assessment is as of <assessed>.- the vouch sentence — always present
Why: <why>— a full stop is appended unless<why>already ends with oneStatement made by: <names>.— always present
When any stage or check is a pair, the summary is told in two eras instead
(4.3): the era-less stage sentences, then Before LLMs, ..., then
Since LLMs, ..., then the maintenance and scope sentences, then the level
sentence, then items 8 to 11. The checks sentence of item 5 is absorbed into
the eras.
4.2 Sentence tables
Level, from rigor:
| Value | Signed by one | Co-signed |
|---|---|---|
unexamined |
I have not examined this code. It ran; that is all I claim. | We have not examined this code. It ran; that is all we claim. |
skimmed |
I have run and skimmed this code, but I have not read it properly. No human has understood it line by line. | We have run and skimmed this code, but we have not read it properly. No human has understood it line by line. |
comprehended |
I have read and understood this code; I can explain every line of it. | We have read and understood this code; we can explain every line of it. |
engineered |
I understand this code; it was deliberately reviewed for quality and for security, issues found were fixed, and it has tests I trust. | We understand this code; it was deliberately reviewed for quality and for security, issues found were fixed, and it has tests we trust. |
owned |
I stand behind this code as soundly engineered and hold architectural responsibility for it. | We stand behind this code as soundly engineered and hold architectural responsibility for it. |
Vouch, from the claim:
| Value | Signed by one | Co-signed |
|---|---|---|
yes |
I recommend this for use; I put my name behind it. | We recommend this for use; we put our names behind it. |
neutral |
I make no recommendation either way about depending on it. | We make no recommendation either way about depending on it. |
withheld |
I am specifically not recommending you depend on this. | We are specifically not recommending you depend on this. |
Stage phrase, for idea and plan. With both keys it is the owner phrase
followed by the depth tail; with by alone it is the owner phrase; with
depth alone it is the depth-alone phrase; with neither the sentence is
omitted. When idea carries inspired_by, , inspired by <text> follows the
owner phrase (or the depth-alone phrase), before any depth tail: The idea was
mine, inspired by the query objects of X, and worked in depth over iterations.
by |
Owner phrase, signed by one | Co-signed |
|---|---|---|
human |
mine | ours |
human-with-ai |
mine, developed with an AI | ours, developed with an AI |
ai |
an AI's | an AI's |
upstream |
the upstream's | the upstream's |
depth |
Tail (after an owner phrase) | Alone |
|---|---|---|
one-shot |
, and taken as it first came |
taken as it first came |
considered |
, and thought through |
thought through |
deep |
, and worked in depth over iterations |
worked in depth over iterations |
Implementation, from stages.implementation.by:
| Value | Signed by one | Co-signed |
|---|---|---|
human |
The implementation was written by me. | The implementation was written by us. |
human-with-ai |
The implementation was written by me with an AI. | The implementation was written by us with an AI. |
ai |
The implementation was generated by an AI. | The implementation was generated by an AI. |
upstream |
The implementation was inherited from the upstream. | The implementation was inherited from the upstream. |
Actor phrases, used by the checks sentence and by the eras of 4.3:
| Actor | Signed by one | Co-signed |
|---|---|---|
human |
by me | by us |
human-with-ai |
by me with an AI | by us with an AI |
ai |
by an AI | by an AI |
upstream |
by the upstream | by the upstream |
Checks. The sentence is It was <groups>., built from the done checks among
quality_reviewed, security_reviewed, and tested; the other checks
contribute nothing, and the sentence is omitted when no check is done.
| Check | Phrase |
|---|---|
quality_reviewed |
reviewed for quality |
security_reviewed |
reviewed for security |
tested |
tested |
A group is the checks that share an actor. Within a group, both reviews
merge to reviewed for quality and for security; that and tested join with
, and , two single phrases with and. The actor phrase from the table
above (by me, by us, by an AI, ...) follows: bare after
one check, , both <phrase> after two, , all <phrase> after three. An
unstated actor (yes) adds nothing. Groups join with ; , the last introduced
by ; and .
| Checks | Reads |
|---|---|
quality human, security human, tested yes |
It was reviewed for quality and for security, both by me; and tested. |
all three ai |
It was reviewed for quality and for security, and tested, all by an AI. |
quality human, tested ai |
It was reviewed for quality by me; and tested by an AI. |
Maintenance. When activity is dormant, the sentence is:
| Signed by one | Co-signed |
|---|---|
| Nothing has needed changing lately; I still use this and would respond if it broke. | Nothing has needed changing lately; we still use this and would respond if it broke. |
Otherwise, when by is present:
by |
Signed by one | Co-signed |
|---|---|---|
human |
I drive changes myself now. | We drive changes ourselves now. |
human-with-ai |
I now make changes with an AI. | We now make changes with an AI. |
ai |
Changes are now made by an AI unattended. | Changes are now made by an AI unattended. |
none |
No one maintains this. | No one maintains this. |
Scope, from stages.maintenance.scope. It is independent of by and of
activity, so its sentence stands alongside whichever sentence the rule above
produced, including the dormant one. It has no pronoun, so one form serves
both voices.
| Value | Sentence |
|---|---|
evolving |
The project is still evolving. |
complete |
The project is complete; it will not gain new features. |
Attribution. The summary always ends with Statement made by: <names>., the
names joined as in section 2.5.
4.3 The two eras
A pair on idea, plan, implementation or a check means the work changed
with the advent of AI, and the summary is then told era by era rather than
field by field, so the reader never travels back in time mid-paragraph.
- Era-less stages first: every stage with a single actor, as its sentence of 4.2. A single-valued stage is a whole-life fact.
Before LLMs, <clauses>.— for each paired stage in order, its 4.2 sentence from the first actor, as a clause (lowercase opening, no full stop); thenit was <groups>from the first actor of every paired check. Clauses join with;.Since LLMs, <clauses>.— the paired stages grouped by their second actor, as<subjects> has been reworked <phrase>(havefor more than one subject; subjectsthe idea,the plan,the implementation, joined asa,a and b,a, b and c), the groups joined with;; thenit has been <groups>from the second actor of every paired check and the value of every single-valued done check — a single-valued check is a present fact. The two parts join with, and.- The maintenance sentence, then the scope sentence. The maintenance sentence is omitted when its actor is the implementation's since-LLMs actor, because the era has already said who makes changes now; the dormant sentence is never omitted.
- The level sentence, then items 8 to 11 of 4.1.
So plan: {by: [human, human-with-ai], depth: deep}, implementation: {by: [human, human-with-ai]}, every check [human, human-with-ai], and
maintenance: {by: human-with-ai, activity: active, scope: complete} read:
The idea was mine. Before LLMs, the plan was mine, and worked in depth over iterations; the implementation was written by me; it was reviewed for quality and for security, and tested, all by me. Since LLMs, the plan and the implementation have been reworked by me with an AI, and it has been reviewed for quality and for security, and tested, all by me with an AI. The project is complete; it will not gain new features. I stand behind this code as soundly engineered and hold architectural responsibility for it. ...
4.4 README line
The README line is the level sentence and the vouch sentence, plus Why: when
the stamp carries one, in the stamp's voice. It is not the full summary. The
signers attribute the quotation from outside it, so the quoted text carries no
name.
<!-- rigor:line -->
> "<level sentence> <vouch sentence>[ Why: <why>.]" — <names>, [RIGOR.md](RIGOR.md)
<!-- /rigor:line -->
5. Conformance
A conforming validator must:
- Locate and parse the stamp by section 1, with every rejection in 1.2.
- Enforce
rigor.schema.json(3.1) and the semantic rules (3.2). - Report the warnings of 3.3 without invalidating the stamp.
- Compose the prose of section 4 byte for byte, and enforce the drift rules of 3.4 wherever the markers are present.
A conforming author tool must additionally regenerate the summary block in place, so a stamp and its prose stay in agreement.
6. Changes from v0.3
Version 1.0 supersedes v0.3 directly. A v0.4 was drafted and served briefly but never released as a tool; its changes are folded in here.
signedis new and required: who makes the statement. The summary endsStatement made by: <names>.and the README line attributes its quotation. A co-signed stamp speaks as we, so every pronoun-bearing sentence has a second form.- The maintenance sentences are first person and present tense, matching the
rest of the vocabulary. The v0.3 text for
human-with-ainamed the AI as the actor, which inverted the claim. byonidea,planandimplementation, and every check, may be a pair[before LLMs, since LLMs]. The summary is then told era by era (4.3), and the level rules read the since-LLMs actor.maintenance.bystays single: it describes now.stages.maintenance.scopeis new:evolvingorcomplete, independent ofactivity, so a finished project that still receives upkeep can say so.- The checks sentence groups checks by actor — reviewed for quality and for security, both by me; and tested — instead of repeating the verb and the actor per check.
- The summary block is wrapped at 80 columns by the author tool, and the drift comparison ignores line breaks.
- A
Why:clause is closed with a full stop when the author left it open. forked_fromand theupstreamactor are new: a fork opens its summary with This is a fork of X, and its story stages can say what was inherited.idea.inspired_byis new: free text naming what the idea grew from, rendered into the idea sentence.initwrites a line under the heading naming the convention and linking to this specification.specaccepts"1.0"only. A v0.3 stamp does not validate; re-stamp it.- v0.3 remains published, document and schema both, at
/0.3/and/0.3/rigor.schema.json.