Rituals¶
Twelve rituals, one facade each under cabinet.rituals. Eight work your pull
requests through one graph: heal.mine sweeps every open pull request of
yours, heal.pr takes one by number in a worktree of its own, heal.this
takes your branch's, and merge, ci, answer, review and guide each
run a single task on your branch. One identifies your open issues, and three make
the labels the others read and put on.
vekna cast heal.mine [--plan-only true] [--bound N] [--attended false] [--batch N]
vekna cast heal.pr --number N [--plan-only true] [--bound N] [--attended false] [--batch N]
vekna cast heal.this [--plan-only true] [--bound N] [--attended false] [--batch N]
vekna cast merge [--plan-only true] [--bound N] [--attended false]
vekna cast ci [--plan-only true] [--bound N] [--attended false]
vekna cast answer [--plan-only true] [--bound N] [--batch N]
vekna cast review [--plan-only true] [--attended false]
vekna cast guide [--plan-only true] [--attended false]
vekna cast identify [--batch N]
vekna cast labels
vekna cast labels.heal
vekna cast labels.identify
heal.mine, heal.pr and heal.this¶
Evocation. Each pull request is read once and turned into a todo list, in the order a cast works it:
| fact | label that removes it | todo |
|---|---|---|
| conflicts with its base | none | merge |
a red check whose job is in ci.jobs |
none | ci |
| unresolved review threads, whoever wrote them | none | answer |
| an open pull request | labels.reviewed |
review |
| nothing else to do | labels.qa |
guide |
Facts make todos; labels only remove them. A branch behind its base but without a conflict needs no merge. Where the forge has not worked out whether a branch conflicts, git does, in memory, against the remote's refs.
heal.mine surveys every open pull request of yours not wearing the wait
label, oldest-modified first. heal.pr --number N takes the open pull request
of yours with that number. heal.this takes the pull request for the branch
at the cwd, and reports that there is none when there is none. Each prints one
line per pull request as it reads it:
#7 feature: merge, ci (checks), answer (3 threads), review
#9 docs: guide
A pull request the forge would not answer about gets a line saying why, and
the cast goes on. With --plan-only true that is all: nothing is checked out,
committed or labelled.
heal.mine works no branch itself. For each one with work it queues a
heal.pr on the vekna daemon and goes on to the next, then reports which
cast took which branch:
heal — 2 queued
#7 feature: cast c41
#9 docs: cast c42
The daemon runs each heal.pr in a pooled worktree as slots and trees free
up, so the branches heal side by side and the checkout you cast from never
moves. vekna cast heal.mine follows them and prints each one's rows and
prompts as they come. With no daemon running, heal.mine prints its survey
and fails: start one with vekna. Configuration
sizes the pool. Typed by hand, heal.pr runs where it was typed.
Otherwise each branch with a task the cast works is taken: the worktree must be clean, the remote is fetched, and the branch is checked out and fast-forwarded to it. The base is read as the remote has it and never checked out, because a worktree cannot check out a branch another worktree stands on. The tasks then run in order, and each one hands the branch back for the next:
- merge: the base merged in, conflicts resolved, the gate made green. See merge.
- ci: the red CI jobs rerun, fixed or covered. See ci.
- answer: the review threads triaged with you, fixed, replied to and settled. Attended casts only. See answer.
- review: the quality review posted. See review.
- guide: the smoke test posted, once nothing else is left. See guide.
Whatever the cast committed is pushed before the next task and before the branch is left, so the review's comments anchor to code the forge has. Nothing waits for CI after a push.
A cast takes the next branch only while the worst that branch can spend still
fits its step budget. One that does not fit ends the cast without failing it,
and the report names the branches left for the next cast. The budget fits a
hundred branches at the default --bound.
Every open pull request of yours is listed: GitLab's listing is read to the end, and GitHub's stops at the thousand its search returns. A listing that stops short says so in the report.
merge¶
Transmutation. heal.this with the merge task alone, the way Mending
joins what was split. Only a conflict makes a merge todo:
- Merge the base in. A conflict goes to an agent, which stages what it resolved; the ritual makes the commit.
- Run the gate. Red means a repair attempt: the agent gets the task's output
and edits, the ritual re-runs the task that broke, up to
--boundtimes, and the whole gate once more when it comes back green. - Commit the merge and the repairs, and push.
A branch the gate will not go green on stands down: the worktree is released, the rest of its tasks are worked anyway, and the report calls it blocked.
ci¶
Abjuration. heal.this with the ci task alone, the way Lesser
Restoration ends one condition at a time. A red check on a job listed in
[cabinet.ci.jobs] makes a ci todo, and so does a green covering check
whose summary names a gap. The task works the red checks one at a time:
- Rerun. A job with
rerun = trueruns again if this head has run it only once. If anything was rerun, the task ends there: a fix pushed on top would start a new CI run and waste the rerun. The next cast reads the result. - Fix with a gate. An agent reads the end of the failed job's log and
edits. Then the job's
gateruns and is repaired the way the merge's gate is, withfastre-run between rounds, up to--boundtimes. - Fix without a gate. An agent reads the log and makes one attempt. The ritual commits it; the next CI run checks it.
- Cover. A
coveringjob runs the coverage measurement here, and the agent writes tests for the lines it names, with the fast measurement re-run between rounds.
Each job's fix is a commit of its own, and all of them go up in one push. A job gets one check fixed per cast: when several of a matrix job's entries are red, the first is fixed and the rest are named for the next cast. A job whose gate will not go green stands the branch down, as a merge does, and the task names the checks it did not reach. A fix that changes nothing is no fix: the job stays red, and the report says it passes here while CI is still red.
In heal.pr and heal.this, a branch whose merge was committed leaves ci
for the next cast. The merge's push starts a new CI run, so the red checks the
survey read belong to the old head.
answer¶
Enchantment. heal.this with the answer task alone, the way Command puts
one word to each listener. Every unresolved review thread makes an answer
todo, whoever wrote it. Every item is yours to decide, so only an attended
cast works it. A cast run with vekna cast --unattended, or with
--attended false, leaves the threads alone and ends its report with what
waits for you:
waiting for you, cast without --unattended or --attended false:
#7 feature: 11 threads
Attended, the task goes round in batches of --batch open threads:
- Finish what was left. A thread whose last word is the ritual's own reply is settled. A thread with an issue already filed for it gets the reply naming the issue. Both happen when the forge failed partway through an earlier cast.
- Read. An agent reads the open threads against the code and returns a triage: one item per thread, with a priority (p1 to p4) and what it would do (fix, reject or file).
- Decide. Each item is put to you. Answer in your own words, or press return to take the reading's proposal.
- Answer. Another agent fixes what you said to fix and drafts a reply for every item. The ritual opens the issues you said to file, posts the replies and settles the threads.
Then the next batch is read, up to three rounds a cast; what is still open after that waits for the next one. What the answers changed goes through the gate, repaired as the merge's is, and is committed as one commit and pushed. A gate that will not go green stands the branch down, as a merge does.
A round that finds no thread open puts the answered label on, so the pull request tells you its review is answered. The next answer task takes it off before it starts. The label is only for you to read: open threads decide whether there is answering to do.
review¶
Divination. heal.this with the review task alone. It posts the quality
review as inline comments, one per action item and anchored to the code it is
about, then puts the reviewed label on. A pull request already wearing the
label has had its review: take the label off after changing the branch
meaningfully, and the next cast reviews it again. A branch whose gate stood
down is reviewed all the same, and the agent is told why it is not green.
guide¶
Divination. heal.this with the guide task alone, the way Guidance lends
a hand to whoever checks the branch. A branch gets a guide only when the survey
finds nothing else to do and it is not wearing the qa label:
- An agent follows the skill at
smoke_skilland writes the manual smoke test for the branch: the shortest path that proves the change works where users meet it, and the features nearby it could have broken. It runs nothing. - The ritual posts the test as a plain comment on the pull request, never a
review thread, so
answerdoes not pick it up. - The ritual puts the qa label on.
To ask for a new guide, take the label off. The next cast edits the guide it posted before rather than posting a second, and never touches a comment someone else wrote. Nothing takes the label off for you: merging the base in does not cost a branch its guide.
identify¶
Divination. The backlog, a page at a time, unasked. The candidates are your
open issues, opened by you or assigned to you, that lack a type label or lack
a size label without being an epic. They go in pages of --batch, lowest
number first:
- The page is shown as it is taken up.
- One agent reads the page: it reads the code each issue is about and says
what the issue is — a type (
feature,edit,chore,bug) and a size (S,M,L), orepicin place of a size with the sub-issues it should be split into, plus the open issues already part of it and the ones blocking it. An issue it could not size is left unsized, which the report tells apart from an epic. - The ritual puts that on the forge: the labels, then each sub-issue opened, labelled and attached under its epic, then the links. A write the forge refuses — a label it lacks, say — is named under its issue in the report, and the rest still go on, this issue's and the next ones'. A sub-issue opened but not attached is named there too. A page on which every write was refused stops the cast: that is a forge that is down or will not let you write, not one that disagrees with a write.
- The next page continues the same agent session, so the skill it follows is read once per cast.
The agent follows the skill at identify_skill (see
Configuration): the issues skill from the
plugins. It reaches the forge for nothing and edits no files, as
every other agent here — the writes are the ritual's, one step of their own.
The issue bodies reach it fenced as data, the same as review threads. The
report says what each issue came to, and says so when the forge would not list
your whole backlog: past the listing's cap an issue is never swept, and it
looks from here exactly like one nothing wanted doing to.
labels¶
Conjuration. Makes every label cabinet uses, created where missing and
refreshed where present: what labels.heal and labels.identify each make, in
one cast. Cast it once to set a project up.
labels.heal¶
Conjuration. Makes the four labels heal reads and puts on: the reviewed,
wait, qa and answered labels. The reviewed and qa labels are the ritual's own:
each goes on once its task is done, so the next cast does not repeat it. The
answered label tells you the review threads are settled; see
answer. A fact that goes away once
fixed, such as a conflict or a red check, needs no label. The wait label is
yours: put it on a pull request heal.mine should leave alone, such as a draft
or one waiting on somebody else, and take it off to hand it back. Cast
labels.heal before the first heal when labels was not, and again after
changing [cabinet.labels].
labels.identify¶
Conjuration. Makes the labels identify puts on issues: the types, the
sizes and epic. Cast it before the first identify when labels was
not. The names are fixed, because the issues skill names them too.
Flags¶
| flag | rituals | what it does |
|---|---|---|
--bound N |
heal.*, merge, ci, answer |
how many times one step may be retried on one branch, 1 to 5, default 3 |
--attended false |
heal.*, merge, ci, answer, review, guide |
nobody is at the terminal: leave the review threads, let the budget decide every repair attempt, and run agents in Claude's dontAsk permission mode rather than auto (see Agents). A cast is attended by default; vekna cast --unattended turns it down too, and --attended true cannot turn that back up |
--number N |
heal.pr |
the pull request to heal |
--plan-only true |
heal.*, merge, ci, answer, review, guide |
survey and print each pull request's todos; change nothing |
--batch N |
identify, heal.*, answer |
how many issues go on one page, or open threads in one round of answers, default 7 |
A flag a repository always wants goes in .vekna.toml as one of vekna's
component defaults, keyed by the ritual's full name. A flag on the command
line still wins:
[defaults."cabinet:heal.mine"]
attended = false
bound = 2
Using only some of them¶
Each ritual has a facade of its own, so a project names the ones it wants. A
repository that only wants reviews casts review and never sees the rest:
[rituals]
modules = ["cabinet.rituals.review"]
modules = ["cabinet.rituals"] loads every ritual. cabinet.rituals.heal_mine
also loads heal.pr, the ritual it queues.