Skip to main content

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.