v2.60.0
Released 2026-09-22. One minor release, two changes, both about what a reader sees of a platform build before and while it runs.
Binaries and the merged-pull-request list are on the GitHub releases page.
hooks.preInstantiate: the shape of the work, before any of it starts
A blueprint's hooks had two homes: a phase's own pre, post and await
slots, and the run-level hooks.postInstantiate list that runs after the last
phase. Nothing ran before the first. So a bootstrap that tracks itself on the
task plane opened its epic in phase one's pre and each milestone and task in
the phase that lands it — and a reader watching the build saw the work appear
one row at a time, as it was reached, with no view of what was still to come.
hooks.preInstantiate is the third home: a run-level list that runs before the
first selected phase places, under no phase ({{ .phase.name }} renders
empty there, as it does in postInstantiate). It is where a bootstrap now
opens the epic and every milestone and task its phases will land under, so the
whole programme is on the plane — in order, with exit criteria and briefs —
while phase one is still on its way. It runs on a resume too: what it does is
idempotent by identity, like everything a bootstrap does, so a resumed build
finds what the first run made rather than making it twice.
hooks:
preInstantiate:
- id: epic
uses: orun.task/ensure@v1
with:
kind: epic
slug: "{{ .inputs.epicSlug }}"
name: "Infra baselining — {{ .inputs.productname }}"
description: "Everything the baseline builds for {{ .inputs.productname }}."
owner: me
- id: m01
uses: orun.task/ensure@v1
with: { kind: milestone, epic: "{{ .inputs.epicSlug }}", name: 01-scaffold, exitCriteria: ["repository pushed, main the default branch"] }
The order of the run is now: preInstantiate, then each phase's pre,
placement, post and await, then postInstantiate. Validation holds the new
list to the same rules as the old one: exactly one of run / uses /
workflow per hook, a known action id, a well-typed with block, all
refused before anything is placed.
orun.task/ensure@v1: an epic is born with what it is for
The epic form of the action took a name and a slug. It now also takes
description — what the epic is for — and owner — me for the caller, or
a subject ref. Both travel on the create only: an epic that already exists
keeps what it has, because a resume is not a reason to rewrite a record a
person may have edited since. Milestones already took exitCriteria, and
tasks a brief; with the epic's two fields, a bootstrap can open its whole
programme with every field the work surface shows.