0.46.0
Cut on 2026-10-18. Status: beta. A hardening release from moving the maintainers' own machines under the coxswain
home. cox setup migrate --finish can now finish: a lane host that reports a folder inside a moved checkout counts as
migrated, and a second --apply after the move keeps the migration marker and plans no drop-in rewrite. The
migration also rewrites the profile's repo_map entries for the moved checkouts. The chair's status line counts lanes
across every host, an empty queue with idle lanes pushes one notice, and the loop pulls issues at most every ten
minutes, where it had exhausted the GitHub GraphQL limit. Only coxswain-tools changes.
cox setup migrate --finish finishes. A lane host's beat lists coxswain-cartridges/providers among its
repositories, and the check for a migrated host wanted every path directly under the installs folder, so --finish
answered finish: waiting on host <name> to migrate for every host however long it waited. A path anywhere inside the
installs folder now counts. After the move every profile setting names the installs folder, so a second
cox setup migrate --apply resolved the old root to the installs folder itself: it overwrote migrate.json with the
old root equal to the new one, and it planned the chair unit drop-in rewrite on every run, so the local plan never came
down to the single skip that --finish waits for. The marker is now written only while the old root differs from the
installs folder, and the unit and drop-in steps are planned only when a folder actually moves.
The migration rewrites repo_map. The profile's repo_map, which maps a repository name to its checkout, kept
naming the old checkout folders after a migration and had to be rewritten by hand before --finish removed the
compatibility links. A repo_map value that equals an old checkout path, in its absolute or tilde spelling, is now
rewritten to the checkout under the installs folder in one rewrite_profile_key step, and every other entry is left as
it is. A second run plans nothing for it.
The chair sees the whole fleet. The status line's lanes part reads lanes L/C (here l/c) when there are lane
hosts: L and C add every host's live lanes and capacity to the chair's own, which stay in the parenthesis. It had shown
only the chair's machine, lanes 0/4 while ten lanes were building elsewhere. An empty queue now pushes one notice,
Queue empty, when no initiative has a ready task, no intake is queued, no task is approved, no lane is live on any
host and the tick raised no hold; it pushes once until the queue fills again. And the issue pull, which the chair
planned on every idle tick for every routed repository, now waits ten minutes after the last one.
coxswain-tools
setup migrate: a folder inside a checkout under the installs folder counts as migrated (tools #1801), and a re-run after the move keeps the marker and plans no unit or drop-in rewrite (tools #1802).setup migraterewrites the moved checkouts' entries in the profile'srepo_map(tools #1805).- The status line counts lanes across every host (tools #1803).
- An empty queue with idle lanes pushes one
Queue emptynotice (tools #1806). - The chair plans the issue pull at most every 600 seconds, from a new
pull_age_sfact (tools #1804).
Known gaps
The umbrella's development environment declares the tools checkout as ../coxswain-tools. cox setup migrate moves
the tools checkout under the home and leaves the umbrella where it is, and --finish removes the compatibility link,
so uv run in the umbrella cannot resolve the tools package afterwards. On a maintainer's machine that cuts releases,
keep a coxswain-tools link beside the umbrella until the migration moves the umbrella too. The migration does not
list operator scripts, launchd jobs or systemd units outside the chair unit that still name an old checkout folder;
check them by hand before --finish.
From 0.44.0, still open: the doctor has no lane host paths or migration state row, and profile paths does not
check umbrella_dir; the migration emits no beat when it ends, so --finish waits on each host's next beat. From
0.43.0, still open: the empty-decompose hold always says no refusal line was found in the decompose log, cox runs
triage takes no --profile or --repo, and nothing sets up the timer for cox chair watchdog.
The gate for 0.46.0 was the hosted rehearsal (run 39099135025), whose fresh, upgrade and migrate jobs passed, and a
clean-machine rehearsal in a throwaway Proxmox container, where the fresh install, the upgrade from 0.45.0 and
cox setup migrate passed. Both ran on tools 50d302f, graphs 0c138e2, dash b654297, cartridges 8584e34 and crew
80eb36a.
Migrations: none
Components
coxswain-tools changes and is released at 0.46.0. coxswain-graphs has no commits since v0.43.0 and stays pinned there, coxswain-dash has none since v0.42.0 and stays pinned there, coxswain-cartridges has none since v0.40.0 and stays pinned there, and coxswain-crew is unchanged since v0.38.0 and stays pinned there.
Upgrading from 0.45.0. The store schema is unchanged and nothing migrates on its own. Update cox itself first,
with uv tool upgrade coxswain-tools or brew upgrade cox, then run cox upgrade. If a cox setup migrate --finish
was waiting on hosts, run cox host beat on each host and run it again.