why
rigger why <PROJECT> <VERSION> [--json]rigger why [PROJECT] --principle <NAME> [--json]rigger why --principles [--json]Shows the work that went into one release: what was decided, what was learnt, what was tripped over, and what changed - everything recorded between the release before it and itself.
$ rigger why sample v0.3.0v0.3.0 — shipped 2026-09-04the work after v0.2.0 (2026-09-04)
2026-09-04 decision The budget is a gate, not a suggestion.2026-09-04 pitfall A wide window hides what the budget dropped.2026-09-04 change feat: rank what a person wrote above a commitNo event carries a version of its own, and none needs to: a release is bounded by the release before it, so the record can answer this for versions that shipped long before the question was asked.
How the window is drawn
Section titled “How the window is drawn”From the previous release to this one, by the moment each was tagged rather than the day. A day would not be enough - this line ships several versions in an afternoon, and a day-wide window would hand every one of them the whole day’s work.
The lower bound is exclusive and the upper inclusive. That asymmetry is the point: a tag points at a commit, so a release and its last commit share a moment. Inclusive at the top keeps that commit in the release it shipped; exclusive at the bottom keeps it out of the next one.
Two releases tagged in the same second have nothing between them, and why says so rather than showing an empty answer that looks like a missing record.
A version imported from a hub carries only the day it shipped, which still bounds the window - less precisely, but better than not at all. Run rigger sync and the tag supplies the moment.
A version still being built
Section titled “A version still being built”The current stage has no upper bound, so its window runs to now:
$ rigger why sample v0.4.0v0.4.0 · Search — being builtthe work after v0.3.0 (2026-09-04)
2026-09-04 decision A bare word is searched as a prefix.That is the work in progress, which is exactly what a session picking up the stage wants to see.
Spelling the version
Section titled “Spelling the version”The number is matched by value, not by text, so v1.9, 1.9 and v1.9.0 all find the stage recorded as v1.9.0 - hubs spell a version several ways and nobody remembers which.
A version the record does not have is refused, with a pointer to what it does have.
Under --json a version prints its window: the project, the version, the version before it, then the events between them.
| Field | Type | Meaning |
|---|---|---|
project |
string | The project’s name. |
version |
object | The version asked about. |
version.name |
string | The version, as the record spells it. |
version.title |
string | The stage’s title. |
version.status |
string | The version’s state, such as planned or shipped. |
version.shipped_at |
string | The day it shipped, YYYY-MM-DD. |
version.shipped_ts |
string | The moment it was tagged, RFC 3339 UTC. |
after |
object | The release before it, which bounds the window. |
after.name |
string | That version. |
after.title |
string | Its title. |
after.status |
string | Its state. |
after.shipped_at |
string | The day it shipped, YYYY-MM-DD. |
after.shipped_ts |
string | The moment it was tagged, RFC 3339 UTC. |
events |
array | The events recorded in the window. |
events[] |
object | One event. |
events[].project |
string | The project it belongs to. |
events[].kind |
string | decision, finding, pitfall, change, question or wish. |
events[].date |
string | The day it was recorded, YYYY-MM-DD. |
events[].body |
string | The event’s text. |
events[].from_git |
boolean | Whether it was read from a commit message. |
events[].commit_hash |
string or null | The commit it came from; null for what a person wrote. |
With --principle it prints an array of the decisions standing on that principle, oldest first. With --principles it prints an array of pairs, each a principle’s name and the number of decisions on it.
| Field | Type | Meaning |
|---|---|---|
[] |
object | A decision standing on the principle, with --principle; a principle, with --principles. |
[].principle |
string | With --principles: the principle’s name, as decisions spell it. |
[].decisions |
integer | With --principles: how many decisions stand on it. |
[].project |
string | The project the decision belongs to. |
[].kind |
string | The event’s kind; always decision. |
[].at |
string | When it was recorded, RFC 3339 UTC. |
[].body |
string | The decision’s text. |
[].version |
string or null | The version it was recorded against; null when it was against none. |
A principle, across the line
Section titled “A principle, across the line”A version is one window on the record. A principle is another, cut the other way: every decision that stands on one thing this line believes, from every project, oldest first.
$ rigger why --principle "no users, no compatibility"no users, no compatibility6 decisions across 5 projects
2026-08-30 · sample Broke the format outright rather than reading both. ...Read one project at a time, six such decisions look like six opinions. Read as one thread they are something the line learnt, with what it cost each time - which is what makes a principle arguable rather than a slogan.
Naming a project alongside narrows it to that project’s share.
--principles prints the vocabulary: every name used, with how often.
$ rigger why --principlesno users, no compatibility — 6 decisionsmeasure the screen — 3 decisionsA name nothing stands on is far likelier a misspelling than a new principle - these are typed by hand, months apart - so the answer lists the ones the record knows rather than an empty result.
Decisions carry a principle when they are recorded: see note --principle.