calendar
rigger calendar [--weeks <N>] [--from <WEEK>] [--json]rigger calendar [--weeks <N>] [--from <WEEK>] --ics <FILE>The release calendar as a grid: weeks across, projects down. What a version was aimed at comes from version plan; what actually happened comes from the tags sync reads. Nothing here is a status anyone sets - slippage is the difference between the two, and it appears the moment a tag does.
$ rigger calendar --from 2026-W37 --weeks 5 2026-W37 2026-W38 2026-W39 2026-W40 2026-W41sample *v0.1.0 >v0.2.0 ·v0.3.0 Awidget +v0.1.0 ·v0.2.0 B
+ shipped as planned < early > slipped ! overdue * unplanned · planned
sample v0.2.0 — aimed at 2026-W37, 2 weeks lateThe trailing column is the project’s tier, when it has one.
The marks
Section titled “The marks”| Mark | Meaning |
|---|---|
+ |
shipped in the week it was aimed at |
> |
shipped, but not in that week |
! |
the planned week has passed and there is no tag |
* |
shipped without ever being planned |
· |
planned, still to come |
A release that slipped is shown in the week its tag is in, not the week it was aimed at. Showing it in its planned week would leave the grid claiming a release happened in a week that has none; the aim is not lost, it is named underneath with the distance in weeks.
A version that was never aimed at a week still appears once it ships. Hiding it would let the calendar disagree with the tags, which is the failure it exists to prevent.
Busy weeks
Section titled “Busy weeks”Two releases in a week are named; more than two are counted, as a span:
$ rigger calendar --from 2026-W33 --weeks 3 2026-W33 2026-W34 2026-W35sample *v0.1.0..v0.14.0 (14) *v0.15.0 *v0.16.0 >v0.17.0..v0.19.0 (3) BThis is not tidiness. A week of a real record can hold dozens of releases, and naming them all stretches the column past three hundred characters - every row wraps, the heading stops lining up, and the grid cannot be read at all.
The mark on a counted cell is the worst standing inside it, so one release that slipped into a busy week is not hidden by the ones that landed on time beside it. The names are in why either way.
Weeks are ISO-8601: 2026-W37 is the week of Monday 7 September, and it releases on Friday 11 September. ISO is used because it is the same everywhere, needs no locale to read, and starts on the Monday this line already works to.
--weeks is how many to show, starting from this week; --from reads a different span. The current week is marked * in the heading, so a grid read on a Wednesday says where the reader is standing.
A version that is neither aimed at a week nor shipped is in the plan and not on the calendar - digest is the screen for that.
For the phone: --ics
Section titled “For the phone: --ics”The same weeks as a calendar file (iCalendar), for the calendar on the phone - where Friday’s release and Monday’s focus show before anyone opens a terminal.
$ rigger calendar --weeks 6 --ics rigger.icsWrote 3 release Fridays and 2 weeks of focus, 2026-W39 to 2026-W44, to rigger.icsImport it into the phone's calendar; importing again updates the events rather than doubling them.- A release Friday is a whole-day event on the Friday of the week a version is aimed at:
sample v0.3.0 · Third. - A week’s focus is one event from Monday to Friday naming what is aimed at that week:
Focus: sample v0.3.0, widget v0.2.0.
Only what is still ahead goes in: a version already shipped has no Friday left to be reminded of. Every event is transparent - a release day is a marker, not a meeting, and does not show anyone as busy.
Each event’s UID is made of what it is about - release-sample-v0.3.0@rigger, focus-2026-W40@rigger - so importing a newer file updates the events it already made instead of adding copies. - prints the file instead of writing it. There is no server and no network: the file goes where it is told, and getting it to the phone - a synced folder, a mail to oneself - is left to the owner.
With --json, the grid as data.
| Field | Type | Meaning |
|---|---|---|
from |
string | The first week of the span, as 2026-W37. |
to |
string | The last week of the span, as 2026-W41. |
now |
string | The current week, as 2026-W41. |
weeks |
array | Every week of the span. |
weeks[] |
string | One week, as 2026-W37. |
projects |
array | One row per project. |
projects[] |
object | One project’s row. |
projects[].project |
string | The project. |
projects[].tier |
string or null | Its tier: A, B, C or out; null when it has none. |
projects[].rhythm_weeks |
integer or null | How many weeks between releases its tier asks for, or null. |
projects[].cells |
array | The versions that fall in the span. |
projects[].cells[] |
object | One version in one week. |
projects[].cells[].week |
string | The week it is shown in: the week of its tag once shipped, else the week it is aimed at. |
projects[].cells[].version |
string | The version’s number. |
projects[].cells[].standing |
string | How it reads: planned, shipped, early (shipped before the week aimed at), slipped (after it), overdue or unplanned. |
With --ics and --json, what was written.
| Field | Type | Meaning |
|---|---|---|
from |
string | The first week written, as 2026-W37. |
to |
string | The last week written, as 2026-W42. |
releases |
integer | How many release Fridays the file holds. |
focus_weeks |
integer | How many weeks of focus the file holds. |
written |
string or null | The file written; null when the file went to standard output. |
ics |
string or null | The file’s text when the target was -; otherwise null. |
Related
Section titled “Related”version plan- aim a version at a week.next- one week of this, in full.project tier- the tier and rhythm shown here.sync- what reads the tags this compares against.