v1.13.0: the kit takes over its own repository configuration
Released 2026-08-20. Two commits, one new skill: setup-repo, which writes the labels, issue forms and repository settings that profile-repo had only ever been able to read.
What we were trying to fix
The lifecycle skills assume a repository is configured a particular way. create-issue files against a label taxonomy on four axes. implement-issue reads the issue forms’ Area dropdown. merge-pr assumes squash-only merges and delete-branch-on-merge. auto-dev sorts a backlog by an effort label that has to exist.
All of that was read by get-repo-profile (as profile-repo was then called) and written by a human clicking through the GitHub web interface. Which meant two things. Porting the kit to a second repository was an afternoon of manual setup nobody wrote down. And once configured, the settings drifted, silently, because the intended state existed only in whoever had clicked it.
What we decided
Split the concern in half and ship the missing half.
setup-repo is deterministic and idempotent: plan prints the drift between a declared manifest and the live repository, apply converges it (#192). At this version it covers the label taxonomy, the issue forms under .github/ISSUE_TEMPLATE/, and the repository settings the merge flow depends on. The manifest is the intended state, checked into the repository, so drift becomes visible rather than merely present. The four surfaces a public repository is judged by, its description, homepage, topics and Pages source, were still unmanaged here and only joined the manifest much later, in v2.1.0 (#400).
Then the kit ran it on itself (#196), adopting its own label taxonomy and issue forms through the tool rather than by hand, which is the only way to find out whether the tool works.
The reader and the writer stayed separate skills on purpose, later recorded as ADR 0013. profile-repo observes and never writes; setup-repo writes and is the only thing that does. A single skill doing both would have made every profile refresh a potential mutation of the repository it was describing.
What got cut
--prune was left out. setup-repo apply converges what the manifest declares and never deletes a label the manifest does not mention, so a repository with its own extra labels keeps them. A tool whose first run can delete labels across an unfamiliar repository is a tool nobody runs twice.
The shipped templates/repo-setup.yml also keeps its area: <your-area> placeholder rather than the kit’s real area names. This was the one amendment the owner made to the plan on the day it was implemented: the kit’s own areas are per-skill names like area: merge-pr, which are meaningless in a consumer’s repository, so they live in a repo-local .github/repo-setup.yml override and the shipped default stays a placeholder. The suite asserts the shipped manifest declares all three axes, and the placeholder satisfies that, so it is deliberately not something to “fix”.
What bit us
Nothing in the release itself, which is what two commits and a new skill usually buys you. The bill arrived in the next one.
setup-repo’s plan passed on placeholder area names instead of failing on them (#198), which is the exact defect the placeholder decision above made reachable and which nobody thought to check for on the day. And a refused label write did not name the status it had observed (#200), so a refusal told you that something had gone wrong without telling you what GitHub had actually answered. Both landed in v1.14.0.
The pattern is the one this whole era keeps re-teaching: a new writer is easy, and making its refusals say what they saw is the part that gets skipped.