Skip to content

0.18.0

Cut on 2026-09-26. coxswain-cartridges, coxswain-graphs and coxswain-tools are tagged v0.18.0. coxswain-crew is unchanged and stays pinned at v0.12.0. coxswain-tools is published to PyPI from its tag. Status: beta. This release carries three headlines.

Lanes on several machines. The chair is the machine that runs cox. It keeps the workspace and does all landing, and other machines run lanes against a shared Postgres store. cox setup doctor --host <name> checks a lane machine over ssh. cox route launch epic --on <name> allocates the run on the chair, copies the initiative over and starts the lane there. The docket, cox route status and cox runs top show the lane with its host and heartbeat, and the store's lease refuses a second run of the same epic on any machine. When the lane ends, cox runs fetch brings its task records, log and branches home, and cox runs land lands them as usual. Verified end to end with a Docker container as the lane machine. The docs page Several machines covers the setup (coxswain #120, #133).

A data platform. Every run's traces are written as one Parquet file per run, zstd inside, and the old traces are converted: in the reference workspace, 1.12 GB of JSONL became 269 MB across 712 runs. cox lake sync appends each ended run's records to an Iceberg lake, cox lake query runs DuckDB over it, and a land syncs the lake when a catalog exists. The Superset dashboard reads the SQLite store or a shared Postgres store. In Postgres mode each DuckDB connection attaches the store from COXSWAIN_STORE_URL in the container, so no URL or password is saved in Superset (coxswain #114, #116, #118, #131, #136). deploy/superset/check.py plans both modes offline and confirms every chart returns rows (coxswain #108, #134).

A harness that learns from its own records. A quarantined attempt records its cause: the ticket, the code, the review or the harness. A rule decides first, then a cheap model. cox stats causes, cox stats gates, cox stats tiers and cox stats efficiency report where attempts fail, what each review step costs and changes, the cheapest model per role that keeps its landed rate, and the cost per landed task. The dashboard gains an Efficiency section, a quarantines-by-cause chart and review verdict charts (coxswain #110, #122, #126), and a Lake and Efficiency docs page (coxswain #124). On the reference workspace, builds land 98% of the time on Sonnet at $1.23 per landed task, against 92% on Opus at $2.14. On 2026-09-25, 199 tasks landed at $3.71 each, 63% on the first build.

The umbrella's release-check exempts every line of a deprecation sentence and keeps a wrapped citation on its bullet (coxswain #112, #129), and the releases page lists the newest release first (coxswain #127).

Upgrading from 0.17.0. The store migrates itself to schema version 6 on the next run: task_records (0004), attempts.cause and cause_why (0005) and work_items (0006). The record files stay authoritative this release. A team cartridge may set apply_arm: workstore on state_move, item_create and item_update, so the harness makes those ticket writes in code instead of with a model call. CI's required test job runs Python 3.14, and a py312 job keeps the floor. To use Postgres, install coxswain-tools[postgres] and set storage_url in the provider profile on every machine.

coxswain-cartridges

  • workstore is a valid apply_arm without being a role, beside shell and pr (cartridges #165).
  • CI runs the suite on Python 3.14 (cartridges #163), and the required test job now runs it, with a py312 floor job (cartridges #167).

coxswain-graphs

  • The CLI stamps the run's host at run start, and the store copy carries it (graphs #425, #427, #433).
  • Trace compaction writes one Parquet file per run under the profile's traces_url. It deletes the loose files only when the new rows are all there, and leaves them in place on any failure (graphs #429, #461). python -m harness.store_backfill_traces repacks historic traces into Parquet and archives the sources (graphs #431, #434).
  • python -m harness.store_traces dump <root> <run_id> prints a run's Parquet rows as JSON lines, for readers without pyarrow (graphs #436).
  • Calls recorded before calls had ids carry one id everywhere. The store names them legacy:<run>:<seq>, and python -m harness.store_backfill_traces relink rewrites the Parquet traces to match (graphs #445).
  • Every per-ticket node call records its task id, so review steps join to their tasks (graphs #443).
  • Task records are mirrored into the store: migration 0004, the upsert, read, write, copy, the driver's mirror and a backfill (graphs #439, #441, #447, #449, #451, #465, #467).
  • A quarantined attempt records its cause: migration 0005, a deterministic rule, then a cheap classifier, written to the store and backfilled (graphs #453, #455, #469, #473, #476, #478). A budget, turn or limit stop is harness (graphs #479), and so is the older plural check-failure message's code (graphs #493). python -m harness.store_classify gives historic unknowns the classifier's cause, bounded and recorded as a run (graphs #495).
  • A good build whose answer mentions the usage limit is no longer read as the account's limit banner. A quarantine reason is capped at its first line (graphs #485).
  • python -m harness.store_cli is the one writer other tools use: mark-landed, set-state and the chair's lease. It requires --store-url or --runs-dir, so it never creates a stray store (graphs #457, #459, #471, #475, #499).
  • Work items in the store: migration 0006, the mirror rule, store read and write, the driver's mirror and a backfill (graphs #481, #482, #489, #491, #501).
  • The workstore arm carries out a state_move, item_create or item_update proposal in code, and falls back to the model arm when the proposal lacks its fields (graphs #484, #487).
  • A relaunch recreates a phase branch whose tasks are already done, instead of refusing (graphs #463).
  • Reviewers are told which commands the builder's session could run, and never ask for evidence from any other (graphs #505).
  • The required test job runs Python 3.14 and CI runs the suite on it, with a py312 floor job (graphs #437, #497).

coxswain-tools

  • cox lake sync, cox lake query and cox lake doctor. The doctor creates nothing: a missing SQLite catalog reads as "no catalog yet". A land syncs the lake when a catalog exists (tools #652, #654, #658, #704).
  • cox route status and the docket list lanes that other machines hold in the shared store, with their host (tools #656).
  • A cox without pyarrow, such as the Homebrew install, reads Parquet traces through the harness's own Python (tools #666).
  • Lanes on another machine: lane_hosts in the routing profile, the ssh, rsync and git argv builders, the remote-lane record, and cox setup doctor --host (tools #660, #662, #664, #670).
  • cox route launch --on and cox runs fetch (and --all) (tools #673, #684, #686, #688, #694, #720). The launch records the repository, so cox runs fetch brings an epic lane's branches home (tools #749). A lane launched on another machine never takes that machine's chair lock (tools #751). cox setup doctor reads a new, empty store as ok, with "no runs yet" (tools #753).
  • cox runs land records no PR for the local forge (tools #755). Its note for a merged item that was still ready names both reasons: quarantined after approval, or run on another machine (tools #757).
  • cox stats gates reads review verdicts from the store, and flags a step only with at least 50 decided tasks (tools #668, #671, #677, #728, #730). cox stats tiers (tools #679, #690). cox stats causes (tools #702). cox stats efficiency and the docket's efficiency line (tools #716, #724, #726).
  • cox runs land reads a task's record from the store first, falling back to the file (tools #692, #696). It regenerates the README's Commands block before it commits (tools #700, #713, #714).
  • Writes to the store go through the harness's store CLI: the land's mark-done and the chair's lease (tools #698, #706, #708, #711, #722).
  • Work state through the store: the set-state wrapper, the work-items reader, the land's and the route's state mirror, and cox route drift (tools #732, #734, #737, #739, #741).
  • cox route sync drives a tracker plugin through sync(workspace, items, *, dry_run) (tools #743).
  • The store's JSON columns read the same from Postgres as from SQLite (tools #747).
  • cox route launch --initiative ~/... expands the home directory (tools #710).
  • Trace reads find calls recorded before call ids, under the store's legacy id or the backfill's synthetic id (tools #675, #682).
  • The help snapshots pass on Python 3.14, and the required test job runs it, with a py312 floor job (tools #681, #745).

Known gaps

The chair holds the workspace, so a lane's task records come home by cox runs fetch, and only the chair lands. Moving task state and records into the store, so any machine could land, is next. Each target repository must sit at the same absolute path on a lane machine. Traces stay on the machine that ran the lane unless traces_url names shared storage. The Efficiency charts' landing history starts when runs/land.jsonl began.

Components

coxswain-graphs carries Parquet traces, the cause of a quarantine, task records and work items in the store, the store CLI and the workstore arm. coxswain-tools carries the lake commands, lanes on another machine, the stats commands, the store-first land and the tracker plugin contract. coxswain-cartridges accepts the workstore arm. The umbrella carries the Superset Postgres mode, the Efficiency charts and the docs. coxswain-crew is unchanged and stays pinned at v0.12.0.