Skip to content

v0.6.0

Choose a tag to compare

@noahhyden noahhyden released this 18 Jul 16:51

Runtime isolation for git worktrees — collision-free ports, processes, and databases for every worktree, from one zero-dependency bash file.

This release is the "dogfooding hardening" cut: a batch of correctness fixes found by running ataegina against real repos, a new move command, and a much larger test suite that now starts real processes and real databases.

Added

  • ataegina move N — relocate the current worktree to index N (and its derived port pair), rewriting the per-repo registry. Refuses an index another live worktree holds, rejects index 0 (reserved for the primary), frees the old slot for reuse, and warns if either new port is already in use. Motivated by dogfooding: when an auto-assigned slot's derived port is permanently held by a process ataegina doesn't manage, the only previous fix was to hand-edit the registry.

Fixed

  • down no longer leaks worker/child processes. Teardown now enumerates the full process tree under each launched root from a single portable ps snapshot, SIGTERMs it, then SIGKILLs survivors — independent of any port tool. Previously a dev server's workers (uvicorn --reload, vite/esbuild, webpack/turbopack) were orphaned each up/down cycle, and on hosts without lsof/ss/fuser nothing but the wrapper was killed.
  • Concurrent first-up no longer races two worktrees onto the same index (which meant identical ports and the same per-worktree database). Index assignment is now serialized with an atomic mkdir lock plus a double-checked re-read.
  • A repo path containing a space no longer costs the primary its index 0 (and, with a DB configured, a suffixed DB instead of the shared one).
  • Linked worktrees inherit the primary checkout's config, so a fresh git worktree add tree no longer fails up/db with "no backend/database configured".
  • up exits 0 on a successful start with no frontend (scope backend/none) instead of returning 1 under set -e.
  • up distinguishes a dead server from a slow one, reporting "FAILED to start — see " for a pid that already died instead of "still starting".
  • move/up refuse an index whose derived port exceeds 65535.
  • down won't kill a recycled pid (start-time guard on the recorded pid).
  • move frees the old slot's servers itself instead of orphaning them on the old ports.
  • down now reports <label>: stopped on :<port> when it actually stops something, instead of being silent on success.

Testing

  • The suite grew from 44 to 99 tests, adding the first coverage that starts real processes and runs concurrently: real up/down lifecycle across python, node, Go, and Ruby backends, a full two-worktree end-to-end (distinct ports + own databases, simultaneously), real frontend-scope borrow of the shared backend, real logs, and docker-gated integration against live postgres, mysql, and mariadb engines (per-worktree create/drop/isolation) that skip cleanly where docker is absent.

Full details in the CHANGELOG.


Install / upgrade: brew upgrade ataegina · ataegina update · or curl -fsSL https://raw.githubusercontent.com/noahhyden/ataegina-cli/main/install.sh | sh