Why BoB Holds Rituals
Why BoB Holds Rituals
Section titled “Why BoB Holds Rituals”The work nobody files. A requirement waits in the queue until someone works on it. A retrospective, a dependency audit or a security review does not: it is due on a schedule, and if nobody holds it, nothing reminds you. BoB calls these recurring reviews rituals, and treats each run as ordinary tracked work: an issue, an evidence comment, a session and a close. This page explains why each step is shaped the way it is, following one retrospective on the
hello-linksproduct. The Holding a Ritual tutorial walks the same run, and takes every command below from this page. Every flag, exit code and output contract is in the Rituals reference.
A ritual is scheduled, not queued
Section titled “A ritual is scheduled, not queued”The approved queue answers “what should the loop build next?”. It never answers “when did we last look back?”, because a look back is not a feature and has no acceptance criteria. Left to memory, it slips: a project gets busy, and the review that would have caught a slow build or a stale dependency never happens.
So a ritual has a cadence instead of a priority. P1M means “due one month
after the last run”. before-stable-release means “due before the next stable
release”. BoB grades each ritual against that cadence every time you ask, and the
grade (overdue, due, upcoming) is what surfaces in /status, in
bob ritual due and in the farm’s nightly pass.
Why the schedule lives in the manifest
Section titled “Why the schedule lives in the manifest”A project already has one declaration of what it is: its provision manifest,
provisions/<project>.json in the operator repo. The ritual schedule goes in the
same file, under _meta.rituals, so the project’s whole declared shape is in one
place and every fleet reader already knows where to look.
For hello-links, a monthly retrospective is enough. The product is small and
changes fast, so a quarter is too long to wait:
bob operator show{ "_meta": { "project": "hello-links", "rituals": [ { "name": "retrospective", "cadence": "P1M", "why": "a small product that changes fast: look back every month" } ] }}make -C ~/projects/bigbrain check-ritualsbob operator show names the operator repo, where provisions/hello-links.json
lives. The rituals list goes inside the existing _meta object, next to
project. check-rituals is the gate: it refuses an unknown ritual name, a
cadence it cannot parse, or a kit that is not declared. It runs as part of
make check, so a broken schedule never reaches the fleet.
Declaring a list, even an empty one, replaces the defaults. A project that declares nothing still gets rituals: the active or dormant defaults for its liveness, which BoB reads from the project’s last commit.
Why run history comes from issues
Section titled “Why run history comes from issues”When was the last retrospective? BoB could keep a date in a file. But a file on
one laptop is not visible from the farm, and a file anyone can edit is a date
anyone can forget to update. Instead, every held ritual is a GitHub issue labelled
ritual-run, and the last run is derived from the newest closed one. Holding
the ritual and recording it are the same act.
bob ritual dueRun from inside the checkout, due reads the project’s schedule and its closed
ritual-run issues, and prints one row per ritual. A retrospective that has never
run is DUE. One whose last run plus its cadence has passed is OVERDUE, and the
command then exits 1, so a script can gate on it. When the forge cannot be read,
the row is unknown, never “never run”: an outage must not make the whole fleet
look overdue.
Why a run is an issue before it is a session
Section titled “Why a run is an issue before it is a session”Opening the run issue first gives the session somewhere to write. The issue carries
a marker (bob-ritual-run/1, with the project, ritual and date), the ritual’s
scope, the kit to load, an empty Findings checklist, a Journal section and the
delta against the previous run.
bob ritual open retrospective --dry-runbob ritual open retrospective--dry-run prints the title, labels and body and files nothing. The real call files
ritual: retrospective — hello-links (<today>), labelled ritual-run and
ritual:retrospective. A second open of the same ritual is refused (exit 3)
and names the run that is already open, so two people, or you and the farm, never
hold the same review twice.
Why the evidence is gathered before you sit down
Section titled “Why the evidence is gathered before you sit down”Most of a review’s first hour is counting: what closed, what is stuck, what it
cost, what the memory audit found. That is mechanical, so BoB does it before the
session. prepare runs the ritual’s collectors (for a retrospective: the
status report, cost and churn, aged issues and the memory audit) and posts the
result as one comment on the run issue.
bob ritual prepare 20 --dry-runbob ritual prepare 20prepare only reports. It writes nothing but that one comment, and a rerun
replaces the comment instead of adding another. A collector that cannot run (a tool
that is missing, no checkout on this machine) becomes a named gap in the packet,
never a failure: the rest still runs and the comment is still posted.
The farm does the same thing overnight. Each bob tick runs prepare --due: for
every farm-eligible ritual that is overdue or due in the next two days, it opens
the run if there is none and posts the packet. You can preview that pass for your
project:
bob ritual prepare --due --dry-runThe session itself is never farm work. A retrospective needs someone to judge what the numbers mean.
Why the session loads a kit
Section titled “Why the session loads a kit”A retrospective needs different tools from a feature: the incident and retrospective
commands, a debugger, a lessons extractor, the project historian. Provisioning those
into the project for good would crowd every other session. A kit is a named set
of registry items applied for one session as a provision overlay and restored
afterwards. The retrospective’s kit is incident.
bob ritual run retrospective --dry-runbob ritual run retrospectivebob provision overlay statusclaudebob ritual run does four things in order. It checks the kit against this
machine’s role, and refuses (exit 3) a kit the role forbids. A farm worker, for
example, forbids security and vision-planning. It resumes the open run (issue
#20 here) or opens one. It applies the kit as an overlay stamped with the run.
Last, it prints the evidence summary and the previous run’s findings. Then claude
starts the attended session with the kit loaded.
claude --kit incident applies the same kit without a run. Use it for an ad hoc
session. For a ritual, use bob ritual run, because the overlay is then stamped
with the run, and closing the run restores it.
Why a run closes only with durable outputs
Section titled “Why a run closes only with durable outputs”A review that ends in conversation evaporates. Two weeks later, nobody can say what
was decided or whether it was done. So bob ritual close refuses to close a run
until everything it produced is somewhere durable:
- each finding links its own issue labelled
bug,req,task,securityortodo, or carries ano-actionreason; - each lesson or decision is its own
/journalissue, linked from the run. The run itself is never labelledlessonordecision: it is a record of what was done, not a piece of knowledge.
In the hello-links retrospective, the packet shows that the link-expiry
requirement took three coding cycles, because the seed data had no expired link to
test against. That produces one finding and one lesson. The weekly email is still
waiting on its todo, which needs no new issue:
/requirement Seed data includes an expired link and a link that expires tomorrow. Found in retrospective #20./journal lesson Seed data must cover every lifecycle state a requirement adds, before the requirement is builtbob ritual close 20 --finding 21 --no-action "the weekly email waits on its own todo" --journal 22 --dry-runbob ritual close 20 --finding 21 --no-action "the weekly email waits on its own todo" --journal 22bob provision overlay statusbob ritual due--dry-run runs every check and prints the closed body. On a refusal (exit 3),
it names each problem and leaves the run open. The real close rewrites the Findings,
Journal and Delta sections, closes the issue and restores the kit overlay that
bob ritual run applied. The next bob ritual due shows the retrospective with
this run as its last run, and its next due date a month out.
The Delta section compares this run’s findings with the previous run’s: which were resolved, which recur and which are new. It is what makes a monthly ritual more than twelve separate conversations.
Why the portfolio review decides for every project at once
Section titled “Why the portfolio review decides for every project at once”Every ritual above looks at one project. One question cannot be answered from
inside a project: is this project still worth the attention it gets? The
portfolio review answers it for all of them together, once a quarter. It is
held on bigbrain, never declared by a project, and its run issue has one row per
project. In the session, each row gets a status:
| Status | Means |
|---|---|
invest |
Grow it: new capabilities are expected |
maintain |
Keep it healthy: fixes and upkeep, no new direction |
park |
Stop active work, but keep it safe |
archive |
Retire it |
A status only matters if something reads it, so it goes into the manifest, next to
the ritual schedule it changes. A changed status also needs its reason on record,
as a /journal decision issue linked from the run’s row:
/journal decision hello-links moves from maintain to invest: it is the product we are growing this quarterbob ritual decide hello-links parkbob ritual decide hello-links invest --applyWithout --apply, decide only reports. For park, the report shows what parking
would cost: _meta.rituals is replaced by the dormant schedule (a dependency
audit every six months and a docs review every three), so the monthly
retrospective, and the farm’s evidence for it, stop. A parked project stays safe
but stops asking for your time. archive goes further: it also sets
_meta.active: false, and an archived project has no rituals at all.
invest with --apply writes _meta.portfolio: "invest" into the manifest in the
operator repo and leaves the declared retrospective alone. Commit that change in the
operator repo. The portfolio run’s close checks that each manifest declares the
status its row decided, so a decision that never reached the manifest cannot be
closed as done.
Related
Section titled “Related”- Holding a Ritual: the tutorial that walks this run.
- Hold a Ritual: the same steps as a short task guide.
- Rituals reference: the vocabulary, cadences, collectors, run-issue format and every flag.
- Session Kits: what each kit carries, and which machine roles forbid which kits.