Skip to content

0.44.0

Cut on 2026-10-17. Status: beta. The dedicated coxswain home is finished. cox install and cox upgrade without --root lay out under the home's installs folder, cox setup doctor shows the home rows, and cox setup migrate --apply moves an existing install with a preflight that refuses while anything holds a checkout. The migration now recreates the virtualenvs and reinstalls the cox and cartridge uv tools from the moved checkouts, re-registers the coxswain-cartridges plugin marketplace, and regenerates the chair systemd unit on Linux. Once every host has moved, cox setup migrate --finish --apply rewrites the shared repository paths and removes the compatibility links. A machine not yet migrated warns on the home rows instead of failing its doctor, and cox setup install keeps the extras of the cox and cartridge uv tools. A land freeze is re-checked before each land of a running tick, an empty-decompose hold waits for the decompose process to exit, land heads resolve for a repository recorded in tilde form, and cox upgrade --to takes a bare version. The 0.42.0 and 0.43.0 known gaps about the home not being wired are closed, except where the known gaps below say otherwise.

A new install lays out under the home. cox install and cox upgrade no longer require --root. Without it the installs folder is <home>/installs, where the home is --home, then COXSWAIN_HOME, then the recorded home, then $XDG_DATA_HOME/coxswain, then ~/.local/share/coxswain. The manifest is read from <home>/installs/coxswain/ manifest.toml, so the umbrella is cloned there first, and a missing manifest is refused with a line that says so. cox install creates the installs folder before it runs its steps, and its setup step runs cox setup install --home <home> in place of --root. With no --workspace, that step makes the default workspace <home>/workspaces/main with its work, runs, intake and cartridges folders, and its last write records the home in ~/.config/agent-tools/home. cox setup install without --root already laid out under the home in the 0.43.0 packages, though the 0.43.0 notes said it required --root; it still refuses a home named by --home or COXSWAIN_HOME that differs from the recorded one and tells you to run cox setup migrate --home. With --root, all three commands behave as in 0.43.0, and cox setup install --root still requires --workspace.

cox setup doctor shows the home rows. After the install rows and before the store rows, the doctor prints home root, marketplace registered and marketplace location, then old layout, home paths, home recorded, cartridge links and install bins. home root fails when the home is missing or not writable. The two marketplace rows warn, without failing, when claude is not on PATH. home paths passes when every skills root, the provider profile and the harness dir sit under the home after tilde expansion, and home recorded passes when the home record names the resolved home. cartridge links accepts a base or local link that points at its folder under coxswain-cartridges/cartridges in the installs folder, written relative or absolute. install bins compares four editable sources with their checkouts under the installs folder: the graphs and tools virtualenvs, read from each package's direct_url.json, and the cox and cartridge uv tools, read from their receipts in uv tool dir; it is left out when uv tool dir cannot be read. On a machine with no home record, old layout, home paths, home recorded and cartridge links warn not migrated: run cox setup migrate, and a failing home root, marketplace registered, marketplace location or install bins row warns not migrated: run cox setup migrate; <detail> instead of failing, so an install made before 0.44.0 keeps a passing doctor until it is moved. Every row compares text and follows no link, and without a profile every home row is skipped.

cox setup migrate --apply refuses while anything holds a checkout. When the plan holds any step beyond a skip or a print, local or, with --hosts, on a lane host, --apply first takes a one-hour repository lease on each old checkout, held as migrate@<host>:<pid>, and only then reads the live lanes, the chair lease and this host's row in the store's hosts table. It refuses, prints one line per holder and exits 1 when a lease is held by someone else, a live lane runs on this machine, the chair holds a live lease here, or this host's row is active, with cox host drain <host> named as the remedy for the last. It does not wait and stops no run. A preflight that passes writes migrate.json in the coxswain state folder with the old and new checkout roots, and the leases are released when the command ends, whether it moved anything or not. The refusals were written in 0.43.0 and are now called (tools #1766).

The migration recreates the virtualenvs and reinstalls the uv tools. When any of the four editable sources the install bins row checks is not its checkout under the installs folder, the plan gains eight steps after the worktree repair. For coxswain-tools, coxswain-graphs and coxswain-cartridges in that order, it runs uv venv --clear -q and uv pip install -q -e .[dev] in the moved checkout, the graphs install also taking the cartridges checkout editable. It then runs uv tool install --force -q -e on the tools checkout and on the cartridges checkout, each with the extras its uv tool receipt names, so a cox installed with an extra keeps it. When uv tool dir cannot be read the plan has no reinstall steps. Because the reinstall replaces the environment cox runs from, --apply imports every module it may need before the first step runs. The 0.42.0 printed note that left the editable installs to you is gone.

The migration re-registers the plugin marketplace. When claude is on PATH and claude plugin marketplace list shows coxswain-cartridges anywhere but the cartridges checkout under the installs folder, the plan runs claude plugin marketplace remove coxswain-cartridges when an entry exists, then claude plugin marketplace add with the moved checkout. It then runs claude plugin install again for each plugin id ending @coxswain-cartridges that claude plugin list --json lists, or for local-skills@coxswain-cartridges when none is listed. When claude is not on PATH the plan prints that the marketplace was not checked. This replaces the 0.42.0 printed note that left the marketplace to you.

The migration regenerates the chair systemd unit on Linux. On Linux the plan reads coxswain-chair.service from ~/.config/systemd/user, and when its Environment=PATH= line still names a coxswain- checkout under the old root, the plan ends with a chair_unit step; a machine with nothing else left to move gets that step alone. The step reads --label, --interval and --profile back out of the unit's chair run line and the file its EnvironmentFile= names, and rebuilds the unit the way cox chair service --install does, with the cox now on PATH. It writes the unit, runs systemctl --user daemon-reload, and restarts the service only when it was active. A unit with no chair run line, no usable label or interval, or values that the install would refuse is left as it is with a line saying why. A failed systemctl call fails the step.

cox setup migrate --finish closes the move once every host has moved. cox setup migrate --finish [--old-root PATH] [--apply] [--dry-run] is its own mode: it plans by default and changes things only with --apply, and --dry-run keeps it a plan even beside --apply. The old checkout root is --old-root, else the old_root that migrate.json recorded; with neither it prints finish: no old root known; pass --old-root and exits 2. It refuses --hosts, and --old-root without --finish, with exit 2. It first checks its gates and prints one finish: waiting on ... line per gate that fails, exiting 1: this machine's plain migrate plan must be a single skip, every home row of the doctor must pass, and every lane host must have a beat row whose checkouts all sit under an installs folder. With --apply it also refuses, exit 1, while a live lane runs on this machine, the chair holds a live lease here, or this host's row is active, as the plain --apply preflight does. Then, for each of the three checkouts, it rewrites the tilde prefix under the old root to the tilde prefix under the installs folder: in the store's queue rows in store mode, else in the work files, the same rewrite as cox route paths --move. It reads the rows again afterwards and exits 1 with finish: N value(s) still under <old root> when any remain, removing nothing. Only then does it remove each link on this machine at <old root>/<checkout> whose target is exactly that checkout under the installs folder, keeps anything else there with a finish: kept <path>: <reason> line, and deletes the marker. Each change is printed as finish: rewrite, finish: remove or finish: delete the marker, as finish: would ... without --apply, and a machine with nothing left prints finish: nothing to do. A store it cannot read, or a profile that does not say where the queue lives, exits 2 with nothing removed. The plain migrate plan now prints run cox setup migrate --finish once every host has migrated. in place of the note that left the repository paths to you.

The rest of the move shipped in 0.43.0. A launch on a lane host maps the harness to the host's recorded checkout of the same name (tools #1746), so hosts on the old and the new layout run side by side while the fleet moves, and cox route paths --move OLD NEW swaps a moved prefix by hand (tools #1743).

Smaller fixes. A land freeze set while a tick runs now stops the lands that tick had already planned: each land re-reads the freeze at the tick's clock as it starts, and a live freeze skips it with the lands frozen until HH:MM (reason) text and no escalation, for a later tick to plan again. A land already running is not stopped. An empty decompose is no longer reported while the decompose process still runs: the runs row can end before the process has written every item, so an initiative whose newest decompose run has a live process, by its pid file in the runs folder or by the tick's pid probe, is left out. The chair's land facts expand a tilde repository path before reading the tip of a refused phase's branch, which had not resolved for such a path, so a phase recorded with a tilde path kept the full land back-off window after its branch moved. cox upgrade --to 0.44.0 reads the bare version as the tag v0.44.0, where it had looked for a tag named 0.44.0. cox setup install, and so the setup step of cox install and cox upgrade, reads the extras of the installed cox and cartridge tools from their uv receipts (under UV_TOOL_DIR, else $XDG_DATA_HOME/uv/tools, else ~/.local/share/uv/tools) and puts them on its uv tool install -e targets, so a tool installed with an extra keeps it.

coxswain-tools

  • cox install and cox upgrade take --home, and without --root they install under <home>/installs and pass --home to the setup step (tools #1772, tools #1777).
  • cox setup install creates the default workspace folders under the home, where a run into the home had stopped at its first step with no message, and a stopped run now names the step that stopped it (tools #1787).
  • cox setup install reinstalls the cox and cartridge tools from the checkouts under the home with --force, so a cox first installed from PyPI is replaced and its uv receipt names the checkout (tools #1789).
  • cox setup doctor shows the coxswain home rows: home paths, home recorded and install bins are new, the marketplace rows warn when claude is absent, and an unmigrated machine warns on four rows (tools #1767, tools #1770). The doctor command gathers them (tools #1775). On an unmigrated machine a failing home root, marketplace or install bins row warns instead of failing (tools #1784). On any machine, a coxswain-cartridges marketplace that is not registered at all warns on marketplace registered and marketplace location and names cox setup install --plugins, since the plugins step is optional; one registered at the wrong path still fails (tools #1788).
  • cox setup migrate --apply takes a lease on each old checkout and refuses while a lease, a live lane, the chair's lease or this host's active row holds it, then writes the migration marker (tools #1766).
  • The migration recreates the three virtualenvs and reinstalls the cox and cartridge uv tools with their extras when an editable source is not under the installs folder: the venv steps are shared with cox setup install (tools #1767), the plan builds the eight steps (tools #1769) and --apply observes the sources and runs them (tools #1779).
  • The migration re-registers the coxswain-cartridges marketplace and reinstalls its plugins: the install's marketplace steps are public (tools #1774), the plan adds them (tools #1776) and --apply observes the registry and runs them (tools #1782).
  • The migration regenerates the chair systemd unit on Linux when its PATH names the old root: the plan step and a reader of the unit's arguments (tools #1765), then the step itself, which shares the unit builder with cox chair service --install (tools #1771).
  • cox setup migrate --finish [--old-root PATH] checks that this machine and every lane host have moved, rewrites the repository paths under the old root, then removes the compatibility links and the marker: the lane-host check is public (tools #1780), the pure finishing step (tools #1785) and the command (tools #1786).
  • A land freeze is re-checked before each land of a running tick, and a land it skips is not escalated (tools #1768).
  • An empty-decompose hold leaves out an initiative whose newest decompose process is still alive (tools #1773).
  • Land heads resolve for a repository path written with a tilde (tools #1778).
  • cox upgrade --to accepts a bare version such as 0.44.0, and the setup install plan carries the coxswain-tools extras on its uv tool install target (tools #1781). cox setup install reads the cox and cartridge extras from the uv receipts and passes both (tools #1783).
  • With the new features' tests, the suite goes from 7,018 test functions at v0.43.0 to 7,157.

coxswain

  • The release rehearsal's fresh scenario installs the candidate tools first, clones the umbrella into the default home's installs folder and runs cox install with no --root or --workspace, and its upgrade scenario runs cox setup migrate --apply after the pin and before the lint. This re-applies coxswain #317, which 0.43.0 reverted (coxswain #322). Its fresh scenario builds the workspace at the home's default workspaces/main, the one the profile names (coxswain #325), and its pin step reinstalls cox editable from the tools checkout at the candidate SHA, the install cox setup install leaves behind (coxswain #326).
  • The install page installs into the home: the umbrella is cloned to <home>/installs/coxswain and cox install runs with no --root, the page says how the home resolves and that --root and --workspace go together, and a new section, Moving an install under the home, gives cox setup migrate, --apply, --apply --hosts and --finish (coxswain #323, coxswain #324).

Known gaps

Some of what docs/design/coxswain-home.md promises is not built. The doctor has no lane host paths or migration state row, and profile paths does not check umbrella_dir. The migration marker records only the old and new roots, not the last finished step. The migration does not list operator scripts or launchd jobs that still name an old bin folder, and emits no beat when it ends, so a lane host's row shows the new paths only on its next beat and --finish waits on that beat. The repository paths are rewritten only by --finish, after every host has moved, so until then the queue keeps the old paths and reaches the checkouts through the compatibility links.

From 0.43.0, still open: the empty-decompose hold always says no refusal line was found in the decompose log, and nothing records that it was reported. cox runs triage takes no --profile or --repo, nothing sets up the timer for cox chair watchdog, and closing an initiative on its last task works in store mode only.

The gate for 0.44.0 was the hosted rehearsal (run 39079091745), 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.43.0 and cox setup migrate passed. Both ran on tools 84647e0, graphs 0c138e2, dash b654297, cartridges 8584e34 and crew 80eb36a. The fresh scenario now installs into the home with no --root. Its earlier runs on this candidate found the three install fixes listed above (tools #1787, tools #1788, tools #1789) and two faults in the rehearsal itself (coxswain #325, coxswain #326).

Migrations: none

Components

coxswain-tools changes and is released at 0.44.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. The umbrella changes its release rehearsal (coxswain #322, coxswain #325, coxswain #326) and its install page (coxswain #323, coxswain #324).

Upgrading from 0.43.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, with --root if your install is not yet under the home. To move an existing install, run cox setup migrate on each machine to see the plan, then cox setup migrate --apply with the loop stopped and the host drained, since the preflight refuses otherwise. Move the lane hosts with cox setup migrate --apply --hosts from the chair's machine, or run cox setup migrate --apply on each host in turn, and check each with cox setup doctor. Once every host has moved and beaten, run cox setup migrate --finish to see what it would rewrite and remove, then cox setup migrate --finish --apply with that machine's lanes and loop stopped. The first machine to finish rewrites the shared repository paths; each machine removes only its own links and marker, so run it on every machine, and pass --old-root on one whose marker is gone.