# relay-baton v0.4.0 Release Notes Date: 2026-05-28 ## Summary v0.4.0 is a "trust the harness" pass. v0.2 added the multi-project layer and v0.3 made it safe. v0.4 makes the *fallback path itself* observable and verifiable. Before v0.4 the critical orchestration code — the modules that run on every Codex → Claude handoff — was untested, there was no CI, and the harness emitted no duration / history signal. If the harness quietly did the wrong thing during a handoff, you couldn't tell. v0.4 closes that gap. Highlights: - **GitHub Actions CI** on every push to `main` and every pull request. - **Test coverage for the whole fallback path** — workflow, handoff generation, both quality gates, and the Claude adapter. - **CLI smoke test** for the project-registry lifecycle. - **Session observability** — `startedAt` / `endedAt` / `durationMs` / `handoffCount` in `session.json`. - **New command** `relay-baton handoff history`. Test totals at release: **21 test files / 99 tests**, all green in CI (core 90, cli 9). ## What shipped ### CI workflow `.github/workflows/ci.yml`: - Triggers: push to `main`, and all pull requests. - `ubuntu-latest`, Node 20, corepack-pinned pnpm (`packageManager` field), `actions/setup-node@v4` with pnpm cache. - Steps: `pnpm install --frozen-lockfile` → `pnpm build` → `pnpm test`. - Concurrency group cancels superseded runs on the same ref. This replaces the manual "Validation" sections that older release notes used to carry by hand. ### Test coverage for the critical path Modules that participate in every fallback launch are now covered: - `BatonWorkflow` — fixture-based end-to-end handoff build against a real temp git repo: artifacts written, budget snapshot consistent, every diet profile stays within `maxHandoffChars`, backup-on-overwrite, large diff kept on disk but not inlined, `ultra` truncation reflected in the snapshot, log fallback phrases surfaced into Known Errors. - `HandoffGenerator` — section presence and order, reference-only output, sentinel text for empty inputs, conditional lines (truncated warning, used chars). - `HandoffQualityGate` — pass plus every failure reason (missing/empty files, each missing required section). - `TokenDietQualityGate` — pass / warn / fail across profiles (budget, missing summary, truncate marker, inline guards, caveman/ultra diff bounds). - `ClaudeCodeAdapter` — default args, prompt/task fallback, config override, ENOENT handling, and the auth-safety contract via `createAgentEnv`. ### CLI smoke test `packages/cli/src/__tests__/project.smoke.test.ts` drives the full `project add / list / switch / current / doctor / remove` lifecycle against two temp git repos, with `RELAY_BATON_PROJECTS_FILE` pointed at a temp registry. It imports the command functions directly and intercepts stdout — no built-binary dependency, so it runs in the same vitest pass. ### Session observability `SessionMeta` gained four optional, backward-compatible fields: ```ts interface SessionMeta { // ...existing fields startedAt?: string; // when run/handoff kicked off endedAt?: string; // when the session reached completed/failed durationMs?: number; // endedAt - startedAt handoffCount?: number; // total handoffs written this session } ``` `run` and `handoff` stamp `startedAt` on entry (clearing any stale end fields), stamp `endedAt` + `durationMs` on every terminal transition, and bump `handoffCount` after each successful handoff write. Mid-flight validation aborts (not a git repo, unknown diet, gate-blocked) intentionally do not stamp end fields — they are pre-execution failures, not completed sessions. ### `relay-baton handoff history` ```bash relay-baton handoff history [--project ] [--path ] ``` Lists the current `.ai-session/handoff.md` plus any timestamped `handoff..md` backups, newest first. Columns: timestamp, size, filename, and the first non-empty content line as a label. The active document is marked with `*`. Metadata only — it never dumps file bodies. ## Compatibility - `SessionMeta` additions are optional fields; existing `.ai-session/session.json` files keep working and are populated on the next `run` / `handoff`. - `handoff history` is a new subcommand; nothing was renamed. `handoff --to claude` behaves exactly as before, except a missing `--to` now exits with code 2 and a clear message (it was previously a `requiredOption`, changed so `handoff history` can exist as a subcommand). - CI does not affect runtime behavior. ## Notable fix found while testing `relay-baton handoff history` originally ignored every real backup file: the backup filename regex used `[\d-]+` but `SessionManager.backupHandoffIfExists` produces names like `handoff.2026-05-27T05-58-13-213Z.md` (a trailing `Z` after `toISOString().replace(/[:.]/g, "-")`). Fixed to `[\dZ-]+`. Caught by the new history tests. ## Recommended next work (v0.5) See [v0.5.0.md](./v0.5.0.md). Two headline features are planned: - **Plan-execute mode** — explicit planner → executor sequencing (Claude plans, Codex executes from `plan.md`). - **Context compression mode** — proactive mid-session compression of running state / log so an agent runs longer before fallback. Plus carry-overs: OpenCode / Gemini / Aider adapter scaffolds, macOS / Windows CI matrix, project-level fallback pattern overrides.