Tagout

v3.0.0: Tagout, and two plugins from one tree

Released 2026-09-15. One major, three slices: the name, the split, and a redesigned site.

What we were trying to fix

The kit was called ai-migration-kit, after the half most consumers never install. The issue to pull request lifecycle runs on any repository every day; the seven phase .NET pipeline runs once, on a legacy application. The name told a visitor the opposite, and it was an identifier six times over: the repository and its Pages URL, two marketplace files, six host manifests, the suite: line of twelve skill frontmatters, the state paths two scripts write under, and a hundred tracked files.

The shape was wrong in the same direction. Measured in #607: a lifecycle only team loaded seventeen components, a Read hook and two dnx servers where twelve components and no .NET would do. And a plugin cannot be narrowed from its manifest, so the only way to ship ten skills of twelve is a root whose skills/ holds exactly ten.

What we decided

The kit is Tagout (ADR 0016), and it ships as two disjoint plugins from one tree at one version: tagout is the lifecycle, tagout-migrate the .NET pipeline, installed beside it. Nothing under skills/ moved, so every <kit>/... path and every gate that globs skills/ was left alone. The docs site was redesigned around the lock out tag world the name comes from (#604), and thirty visual defects found by driving it in a real browser were fixed before the release rather than after.

A transition entry stayed in both marketplaces (#618) so installs made under the old name keep loading instead of failing on a name that no longer resolves.

What got cut

Nothing was cut so much as deferred to the next hour: the release pull request was held until all three slices had landed, so 3.0.0 is the rename and the split together rather than two majors a day apart.

What bit us

The plugin directories reached the tree through git symlinks, and the first Windows install after the release loaded no skills at all. Git there has no privilege to write a symlink, so each one arrived as a text file holding its target path, and the loader, which looks for a directory with a SKILL.md, found none. ADR 0016 had predicted exactly that in its own Consequences and filed the remedy under “if a consumer asks”. A consumer asked the same day (#619), and the plugin trees now ship as generated copies (ADR 0017).

The lesson is not about symlinks. A consequence a decision record names and then leaves optional is a decision to ship the failure and wait for a report, and the report always comes from whoever had the worst day.