refactor(templates): the tenant seeds carry rig's -box family suffix #125
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:cli
scope:drill
scope:host
scope:installer
scope:templates
scope:tiers
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/box#125
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/template-family-suffix"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #123.
rig is growing a second family of roles, and once a
stagingrole can mean either a fleet machine or a box tenant, the bare name stops naming anything. rig's answer is a suffix on the role itself (rig#76) —-serverfor fleet machines,-boxfor box tenants. box's answer is that a template keeps being named for the role it converges, so the tenant seeds move with it:templates/claudetemplates/claude-boxtemplates/codextemplates/codex-boxtemplates/groktemplates/grok-boxtemplates/stagingtemplates/staging-boxEach seed's
BOX_BOOTSTRAP_ROLEmoves with its directory. Renamed withgit mv, so each seed's history follows it.blankkeeps its name. It seeds no tenant role and sets noBOX_BOOTSTRAP_ROLE, so it has nothing to agree with — renaming it would only churn the default template's name for symmetry's sake.⚠️ Merge ordering: this goes in AFTER rig's rename
Labeled
blockedon purpose. Do not merge this before rig#76 lands.The seeds install rig from
RIG_REPO/RIG_REF, which default toheavy-duty/rig@mainand stay unpinned until rig#32's releases. So a box minted from these templates asks whatevermainhappens to be forrig bootstrap claude-box. Against a pre-rename rig that role does not exist,cmd_newrefuses to call the box ready, and the operator gets a failed mint — roughly 15 minutes in, on a cold claude-box mint — for a change neither repo has finished making.Merged in the other order the window closes instead of opening. rig's cut is hard, with no aliases, so the day rig's rename lands, every unmerged box seed naming a bare role is the broken one. There is no ordering where both repos are simultaneously correct; there is only the one where the broken interval is zero-length on box's side.
Two namespaces, and only one of them moved
The template name and the rig role are now
claude-box. The seed user staysclaude— that is the user rig's role converges, and the onebox shelllands in.test/cli.shnow pins the pair per tenant rather than each half alone:A later rename that moves one and forgets the other mints a box whose role dies looking for a user nobody created. Pinning them together is what makes that fail here instead of on a host.
The one deliberate asymmetry — please read this arm
The mint-time hints in
cmd_newmatch both spellings ofuser.box.template:This is not an alias for the role.
rig bootstrap claudeis gone and nothing in this PR softens that. What these arms read isuser.box.template, a stamp left on an instance at its own mint time: every box minted before this change carries the bare name forever, and a clone carries it forward. Refusing the old spelling here would not cut anything over — it would only drop the login hint on boxes that predate the rename, which is the same reasonuser.claudeboxis honored everywhere else, and what the README's "boxes minted by any earlier version keep working under every verb" already promises. Happy to drop the legacy arms if reviewers read that promise more narrowly.Relatedly,
migrate-host.shnow stamps re-homed legacy boxesuser.box.template=claude-box— the name the template has today — so a re-homed box looks like a fresh mint rather than a fossil.What was left alone, on purpose
Grepping the bare names is mostly false positives, so every hit was read in context. Deliberately untouched:
claudethen/login,box exec work -- claude --version,~/.claude/CLAUDE.md/~/.codex/AGENTS.md/~/.grok/AGENTS.md. These name the agent, not the template.claude-dev,claudenet,claude-isolate,user.claudebox. Pre-0.4.0 names, honored forever.drill/RUNS.md— a record of what past runs proved,claudebox-era names included. History does not get retconned.README.md's> **0.5.0**: two new templates (\codex`, `grok`)` — a release note recording what shipped under those names at the time. Flagging it in case reviewers prefer it updated.codex,grok) — announced in the pre-flight banner and deleted by teardown. Only the--templatethey pass moved.test/cli.sh'sEVILROOTfixtures — synthetic templates withBOX_BOOTSTRAP_ROLE="claude". The suite's own comment says fixtures survive a template rename, and their point is the parser, not the name.install.sh:159'sstaging="$DEST.migrating.$$"— a shell variable for a staging directory. The clearest argument against a blind sed.rig bootstrap workload— still spelled bare. #123 lists only the four tenant roles; if rig#76 also suffixesworkload, that is a follow-up here (it appears instaging-box's seed comment,bin/box's operator hint, and the README).Checks
bash test/cli.sh— 475 passed, 0 failedbash test/labels-reconcile.sh— 19 passed, 0 failedbash test/release.sh— 90 passed, 0 failedshellcheck -xover CI's exact globstar file list (bin/* **/*.sh) — clean.github/scripts/changelog-armed.sh— passesNot drilled on real hardware: every mint path in this PR is a name change, and the drill's own mint assertions moved with it, but no cold
claude-boxmint has actually been run against a post-rename rig — that proof is only available once rig#76 is merged.Pushed a follow-up commit closing a gap I left: the machine-role half of rig#76 reaches box in one place.
The tailnet workload join box prints as the next step for a
staging-boxguest wasrig bootstrap workload, and that role is nowworkload-server(heavy-duty/rig#79). box never runs it — it holds a pre-auth key, and that it stays operator-run is the absence keeping box creds-free end to end — but box does print it, in three places that had to move together:cmd_new's hint, thestaging-boxseed's own comment, and the README. A next step an operator copy-pastes is as wrong as a role box executes, and it fails later and further from the cause.test/cli.sh's assertion moved with it, so it still pins what it was written to pin — that the join is printed and neverexec'd.475 passing, shellcheck clean, changelog still armed.
Merge order is unchanged: heavy-duty/rig#79 → heavy-duty/rig#80 → this.
Verdict: Approve — I agree with this as-is.
Why
git mvtotemplates/{claude,codex,grok,staging}-boxwith matchingBOX_BOOTSTRAP_ROLE.blankunchanged.claude/stagingwhere stamped;user.claudeboxmaps toclaude-box. Workload join next-step usesworkload-server.Land with/after rig#80 so mint auto-bootstrap hits a role the installed rig knows.
No blockers.
Verdict: I agree with everything and have no additional feedback.
The template and role renames are consistent, legacy instance stamps remain readable, the workload join hint now names workload-server, and the current checks are green. The blocked merge order remains necessary: land rig#79, then rig#80, before this PR.
Verdict: Approve — the rename is exact on both sides of the rig↔box contract, every in-repo consumer moved, backward compatibility is handled at the right layer, and the one dangerous window (merge ordering) is documented and gated by the
blockedlabel. Verified at head9c78911.The cross-repo contract, checked name by name
I diffed rig#80 (and rig#79 for the machine half) against this branch:
claude-box|codex-box|grok-box|staging-box(both entrypoints, hard cut, old names refused) — box's four seeds ask for exactly those:templates/claude-box/box.env:21,templates/codex-box/box.env:21,templates/grok-box/box.env:21,templates/staging-box/box.env:29.claude-box→claude,codex-box→codex,grok-box→grok,staging-box→ops) matches each seed'sBOX_USER— the "two namespaces, only one moved" asymmetry is the same on both sides, andtest/cli.sh:358-361now pins the pair per tenant, which is the right guard for the failure mode (role converging a user nobody created).workload-serverin the three printed-next-step sites (bin/box:1204,templates/staging-box/box.env:11+user-data.yaml:7,README.md:274) matches rig#79's machine-role dispatch exactly.test/cli.sh:437-439moved with it and still asserts printed-never-exec'd.No spelling drift anywhere. Merge order rig#79 → rig#80 → this is stated in both PR bodies and in this PR's CHANGELOG entry; the
blockedlabel is on. Do not merge until rig#80 is in.Consumers — all accounted for
Template resolution in
bin/boxis dynamic (cmd_templatesglobstemplates/*/atbin/box:1020;cmd_newreads$root/templates/$tatbin/box:938), so nothing hardcodes the list at runtime. Every static spelling moved: help text, README,docs/box-design.md,docs/box-recipe.md,drill/drill.sh(including the codex/grok mint loop, which correctly keeps bare box names while passing--template $t-box), andhost/migrate-host.sh. Remaining bare-name greps are all deliberate and correct in context: historical CHANGELOG entries (CHANGELOG.md:406-408records what 0.2.0 shipped), agent CLI binaries and dotdirs, the legacy host stack,drill/RUNS.md, EVILROOT fixtures, andinstall.sh:159's unrelatedstagingvariable.Backward compatibility — handled at the right layer
cmd_new(bin/box:1199-1202) readuser.box.template, an instance stamp, not a role — I agree this is not an alias and does not soften rig's cut. Dropping the bare arms would only lose the hint on pre-rename boxes, contradicting the README's compatibility promise. Keep them.user.claudeboxlegacy detection now maps toclaude-box(bin/box:1199), andmigrate-host.sh:82stamps re-homed boxes with today's name — consistent with "a re-homed box looks like a fresh mint".box shelllands viauser.box.user, which never changed, so existing boxes are untouched under every verb.install.shputs each tree underversions/<ver>and atomically flipscurrent), so an upgrade cannot leavetemplates/claudeandtemplates/claude-boxcoexisting in one tree. No stale-directory hazard.Label
refactoris fair for the main commit: no runtime logic changes beyond names, and the follow-up is correctly typedfix. The one operator-visible break —box new --template claudenow dies with the genericno such template: claude (see 'box templates')— is inherent to the rename and documented under CHANGELOG Changed.Checks run locally at
9c78911bash test/cli.sh— 475 passed, 0 failedbash test/release.sh— 90 passed, 0 failedshellcheck -x bin/* **/*.sh— cleanNon-blocking suggestions
bin/box:939'sno such templateerror could special-case the four old names with a one-line "renamed to -box (rig#76)" hint — cheap insurance for post-upgrade muscle memory and scripts. Fine as a follow-up or not at all.drill/RUNS.mdreasoning.— automated review by
claude-bot-andresmgsl· heavy-duty-review-botRound passed — three bot approvals, head-current. Handing to @danmt.
Still
blocked, and the label is accurate: this must merge after heavy-duty/rig#79 and heavy-duty/rig#80. rig hard-cuts the old role names with no aliases, so a seed here namingclaude-boxfails its own mint-time bootstrap against a rig that predates the rename — and these seeds install rig fromRIG_REF, unpinned, defaulting tomain. Merge order: rig#79 → rig#80 → this.One change since the bots approved, pushed as a follow-up commit and called out in-thread: the machine-role half of rig#76 reaches box in one place. The tailnet workload join box prints as the next step for a
staging-boxguest wasrig bootstrap workload, nowworkload-server, in three places that had to move together (cmd_new's hint, thestaging-boxseed comment, the README). box never runs it — it holds a pre-auth key, and that it stays operator-run is the absence keeping box creds-free end to end — but a next step an operator copy-pastes is as wrong as a role box executes, and it fails further from the cause.bash test/cli.sh475/0 ·test/release.sh90/0 ·test/labels-reconcile.sh19/0 ·shellcheck -xclean over CI's globstar list · changelog armed.Unblocked — heavy-duty/rig#79 and heavy-duty/rig#80 both merged, so the tenant role names this seed converges (
claude-box,codex-box,grok-box,staging-box) now exist on rigmain. Removed theblockedlabel.Ordering held: rig cut the old names with no aliases, so this had to land second or every mint from these seeds would have died at its own bootstrap. That window is now closed in the right direction — it is the unrebased seeds that are broken, which is what this PR fixes.
Three head-current approvals, CI green, @danmt already requested.
Worth stating plainly for whoever merges: no cold mint has run against a post-rename rig. The suite covers name agreement, the drill assertions moved with the templates, but a real
box new --template claude-boxagainst rigmainhas not happened and could not have before now. That is the first thing to watch after this lands.