# Session Handoff — relay-baton > Compact, deterministic handoff for the next session (possibly a fresh/cold > agent on a different machine). This is the relay-baton concept applied to the > project itself. Read this first, then `git pull`. > > **Keep this file alive:** update it after every meaningful chunk of work (and > before ending a session) — bump `_Last updated:_`, refresh "Where we are" / > "Next up", and record any new machine-specific gotchas. See `CLAUDE.md` → > "세션 핸드오프 규칙". _Last updated: 2026-07-21 (latest) — **RELEASED as v1.6.1: one-click Windows install — VERIFIED on-device.** Release run 29796800853 all-green (the custom NSIS template compiled fine in CI — `desktop windows-x64: success`). On-device: uninstalled the prior NSIS build, double-clicked `relay-baton_1.6.1_x64-setup.exe`, **touched nothing** → the app installed straight to `%LocalAppData%\relay-baton` (no Welcome/Directory pages, no UAC), sidecar + app both report 1.6.1, nothing in Program Files. The one-click flow works. (Couldn't screenshot the Finish page — Windows foreground-lock kept capturing the wallpaper — but it reuses the v1.6.0 brand sidebar already verified.) Rollback path if ever needed stays: drop `bundle.windows.nsis. template` to revert to the default wizard. User feedback after v1.6.0: the branded NSIS wizard "still looks old" — the frame, not the images. Explained the hard limit (NSIS/WiX render classic Win32 chrome; a truly modern full-window frame needs a custom WiX Burn bootstrapper = separate pipeline + worse SmartScreen unsigned). User chose the pragmatic path: **make it one-click** (Discord/VS Code style, frame gets out of the way). Implemented via a custom NSIS template: fetched Tauri's exact v-matched `installer.nsi` (`@tauri-apps/cli-v2.11.2` tag → cli is 2.11.2, and CI uses `npm ci` against the committed lockfile which pins 2.11.2, so template matches), changed the Welcome (line ~163) and Directory (~384) pages' `MUI_PAGE_CUSTOMFUNCTION_PRE` from `SkipIfPassive` to the template's existing `Skip` (always-abort) fn; wired `bundle.windows.nsis.template: installer/installer.nsi`. PageReinstall self-aborts on a fresh install (line ~216) so upgrades still prompt. Net fresh-install flow: double-click → install progress (header brand) → Finish (sidebar brand + run app). Could NOT preview locally (no cargo) — verify by installing the v1.6.1 setup.exe on-device. If the custom template breaks the CI NSIS build, rollback = drop the `template` line from tauri.conf.json (falls back to Tauri's default 4-page wizard from v1.6.0). Notes in all 10 locales; CHANGELOG + index + README badge/Latest/table + 9 i18n lines synced. Prior entry below._ _2026-07-21 (later) — **RELEASED as v1.6.0: brand NSIS Windows installer — VERIFIED on-device.** Release run 29794512856 all-green; asset is `relay-baton_1.6.0_x64-setup.exe` (MSI gone). Uninstalled the old MSI, ran the new setup.exe: welcome page shows the warm-dark brand sidebar (orange diamond + relay-baton wordmark + tagline + accent rule) with standard white text on the right — clean and modern; inner-page header shows the dark brand strip (diamond + wordmark) and reads cohesively; **install path `%LocalAppData%\relay-baton`, no UAC prompt** (per-user confirmed); app launches at 1.6.0, sidecar 1.6.0, nothing left in Program Files. The header-image-on-light-bg concern was unfounded — it looks intentional. (Build still CI-only; no Rust toolchain locally.) Switched the Windows desktop bundle from MSI to a brand-styled NSIS `…-setup.exe`: `bundle.windows.nsis` in tauri.conf.json = `installMode: currentUser` (no UAC), `installerIcon`, `headerImage`/`sidebarImage` (warm-dark BMPs with the orange diamond + relay-baton wordmark, generated into `desktop/src-tauri/installer/`; `targets` stayed "all" — "all" already builds nsis, so only the release workflow's upload glob changed). release.yml windows matrix bundle-glob msi → `bundle/nsis/*-setup.exe` (+ updater-glob + the Azure signing step's files-folder). winget/scoop were NOT touched — they ship the standalone CLI exe, independent of the desktop installer. Docs (README download row, RELEASE.md) updated. Notes in all 10 locales; CHANGELOG + index + README badge/Latest/table + 9 i18n Latest lines synced. Caveat for verification: could not preview the wizard locally (no cargo); the BMPs were eyeballed as 2x PNGs and look on-brand, but the actual NSIS header/welcome layout needs an on-device install of the v1.6.0 setup.exe to confirm (and to check the header-image-on-light-bg cohesion). Prior entry below._ _2026-07-21 — **RELEASED as v1.5.1, VERIFIED on-device.** Release run 29792912305 all-green (9 assets, npm 1.5.1, brew/scoop, winget PR); MSI installed. Failed-ending red chip confirmed on the installed app: a scratch repo configured codex as `node -e "…process.exit(3)"` (spawns fine, exits non-zero), Codex selected in the header → `/run` → 여기서 실행 → streamed output ended `X codex exited with code 9` and the run card chip showed red **`exit 4`** (v1.5.0 would have shown green 완료). CLI sanity first: `relay-baton run … --primary codex` returned exit 4. NOTE for a future ask: the **MSI installer wizard is the stock Tauri/WiX template** — no custom WiX config, banner/dialog images, or license RTF in desktop/src-tauri (checked). Customizable via `bundle.windows.wix` (bannerPath 493×58, dialogImagePath 493×312, license .rtf, custom template.wxs) if the user wants branded installer chrome; not done yet. Two follow-ups to v1.5.0, both from the on-device `/run` verification: (1) `run`/`execute` now set `process.exitCode = 4` when the chain ends on an agent that ran but exited non-zero (was exit 0 → the desktop run card's chip showed green `done` next to `✗ … exited with code N`; exit 4 makes the chip red). Codes: 1 spawn / 2 usage / 3 gate / 4 failed agent; documented in COMMANDS EN+KO. (2) `ClaudeCodeAdapter.parseEvent` now suppresses `rate_limit_event` telemetry (returns `[]` not raw pass-through; raw still reaches the FallbackDetector). Tests: +1 cli (exit-4 via a node-exit-3 fake executor in planExecute.test.ts) +1 core (rate_limit_event suppressed) → 330 core + 94 cli. Notes in all 10 locales; CHANGELOG, index, README badge/Latest/table + 9 i18n Latest lines synced. Prior entry below._ _2026-07-20 — **v1.5.0 GUI agent execution VERIFIED end-to-end with a REAL agent run.** After the user re-authenticated the claude CLI (`/login` — the earlier 401 was a stale credential on this machine, not a v1.5.0 bug), the full loop completed on the installed MSI: `/run` in the Agent Room → confirm modal → 여기서 실행 → sidecar spawn → claude (sonnet-5) streamed `--pretty` output into the live card (`● model … · session …`, `→ Bash: ls README.md`) → **README.md in the scratch repo was actually modified in ~20s** → green `완료` chip + session badges flipped to completed and panels refreshed. Minor polish spotted: claude's `rate_limit_event` JSONL line is unknown to parseEvent and passes through raw into the card (by design, nothing lost) — suppressing it in ClaudeCodeAdapter.parseEvent is a one-line cleanup for the next release. The run-exit-code UX nit from 07-16 still stands. Prior entry below._ _2026-07-16 (later) — **RELEASED as v1.5.0: GUI agent execution — VERIFIED on-device (mechanics).** Release run 29477520649 all-green (9 assets, npm 1.5.0, brew/scoop, winget PR); MSI installed on this machine. Real-device /run verified end-to-end mechanically in a scratch repo: confirm modal with the exact command → 여기서 실행 → real sidecar spawn streamed into the live card (including a parseEvent-rendered `● model claude-sonnet-4-6 · session …` line — the --pretty pipeline works through the GUI), completion chip appeared and the panels auto-refreshed. Two findings: (1) **this machine's `claude -p` subprocess auth is broken** — the agent turn itself failed `API Error: 401 Invalid authentication credentials` (same 401 as a direct terminal test earlier that day; needs `claude` → `/login` re-auth; NOT a v1.5.0 bug — codex is also unusable here, too old for its default model). (2) UX nit: when the chain's last agent fails, `relay-baton run` exits 0, so the GUI chip shows green `완료` while the card text shows `✗ claude exited with code 1` — consider a non-zero exit (or distinct chip) for agent-failure endings in a future release. Pre-release catch worth remembering: capabilities only allowed `shell:allow-execute` — scoped `shell:allow-spawn` + `shell:allow-kill` had to be added or Run-here would have been permission-denied on device. Detail below._ _Same day, earlier — **GUI agent execution implementation.** The desktop Agent Room can now actually launch agents, confirmation-first (fits the standing "read-only or confirmation-first" hard rule; AGENT_ROOM.md always specified preview → confirm → run — the GUI just caught up). New in desktop/ui/index.html: `spawnSidecar()` (Tauri shell `Command.sidecar(...).spawn()` with line streaming; `window.__rbFakeStream` test seam for plain-browser dev), `runAgentStreaming()` (one run at a time, live output card in the timeline with a Cancel/kill button and running→done/exit-N chips, panels refresh on exit, output capped at 400 lines), a **Run here** button on the non-readonly confirm modal (records the command to the conversation log on click), new **`/run `** composer command (`run --primary --pretty`), and /plan /execute /handoff args now build real launching commands with `--pretty` (handoff dropped `--no-run`). Strings updated in all 4 GUI locales (tagline no longer says read-only; guide says confirmation-first). Verified in plain browser via the fake stream: confirm modal (Copy/Run here/Close), mid-run streaming + Cancel, clean exit → green "done" chip, kill → red "exit 137" chip; live card survives timeline re-merges via localEvents. NOT yet verified in a real Tauri build — needs the v1.5.0 MSI (or a local desktop build) to test actual sidecar spawn._ _2026-07-16 — **RELEASED as v1.4.1, VERIFIED end-to-end** (desktop timeline polish: cards survive reloads + role-coded rows). Release run 29474372381 all-green (9 assets, npm 1.4.1, brew/scoop pushed, winget PR submitted). The v1.4.1 MSI was then installed on this machine and both fixes confirmed on-device: the /status card stayed visible after /budget reloaded the timeline, and user (blue border, lighter bg, mono commands) vs relay-baton (amber border) rows read apart. Detail below._ _2026-07-16 — **Agent Room result cards now survive timeline reloads.** Local card events are kept in memory (`localEvents`, cap 50) and `renderTimeline()` merges them with persisted entries by ISO timestamp instead of wiping them on every `loadTimeline()`; cleared on project switch. Shared `eventRow()` builder; `window.__rbCards.renderTimeline` exposed for plain-browser testing (verified via the `desktop-ui` static server). Found by real usage on the installed v1.4.0 MSI (only the last command's card ever stayed visible). **Same batch: role-coded timeline rows** — user feedback "user와 relay-baton 대화 구분이 잘 안 간다": rows get `by-` / `kind-` classes; 3px left border color-codes the speaker (user=--user blue, relay-baton=--amber, claude/codex=their vars), user rows use the lighter --panel background, and command/prompt_preview text renders mono. Verified in both themes via browser screenshots. Desktop-only HTML changes — ship as v1.4.1 when the user asks. Also: v1.4.0 MSI installed and visually verified on this machine (status/budget/review cards OK); installed CLI via `npm i -g @relay-baton/cli` (MSI does not add the sidecar to PATH); NOTE this machine's codex-cli 0.134.0 is too old for its default model ("requires a newer version of Codex") — codex-first runs fail at hop 1 until upgraded._ _2026-07-15 — **RELEASED as v1.4.0, VERIFIED** (friendly agent stream + desktop result cards; release run 29395001589 all-green — 9 assets published, npm shows 1.4.0, brew/scoop pushed, winget PR submitted). `--pretty` extended to `plan`/`execute`/`handoff` via shared `agentStreamIO` helper (cli/src/agentStream.ts); COMMANDS EN+KO document it; real-CLI schema verification done on this machine (codex-cli 0.134.0 `--json` + claude 2.1.152 stream-json captures replayed through parseEvent — 0 raw pass-through; codex nests upstream API errors as a JSON string in `message`, now unwrapped by `unwrapCodexError`). Notes in all 10 locales; CHANGELOG, release-notes index, README badge/Latest/table + 9 i18n Latest lines synced. Detail of what shipped below._ _2026-07-14 — **Desktop timeline result cards.** Agent Room slash-command results (`/status` `/budget` `/git` `/review` `/guard` `/risk` `/checkpoints` `/sessions` `/resume` `/inspect` `/workspace` `/profile` `/inventory` `/bundle`) now render as structured cards — chips, gauge bar, marked row lists, plus a collapsed "raw json" `
` so nothing is lost — instead of `JSON.stringify` dumps. All display-only DOM builders in `desktop/ui/index.html` (`statusCard`/`budgetCard`/`gitCard`/ `reviewCard`/`guardCard`/`riskCard`/`checkpointsCard`/`sessionsCard`/ `resumeCard`/generic `dataCard`); `appendLocalEvent` now accepts a Node. `/review` reloads the timeline BEFORE appending its card (the reload used to wipe it). `window.__rbCards` preview hook lets a plain browser (no Tauri) render sample cards — verified via `.claude/launch.json` `desktop-ui` static server with mock payloads (light/dark both OK; new `--ok` CSS var in both themes). **Also same day: structured agent stream shipped (local).** `AgentEvent` extended (`system`/`assistant_text`/`reasoning`/`tool_use`/ `usage` + `AgentUsage`); `AgentRunInput.structuredStream` opt-in makes `ClaudeCodeAdapter` append `--output-format stream-json --verbose` and `CodexAdapter` append `--json`; both implement `parseEvent(line): AgentEvent[] | null` (null = raw pass-through, `[]` = suppressed dedup/noise — deterministic JSONL parsing only, no summarization). `runAgent` gains `parseEvent`/`onEvent`: parsed stdout lines go to onEvent instead of onStdout; raw log + FallbackDetector unchanged (patterns still match inside JSON text). CLI: new display-only `packages/cli/src/agentStream.ts` `renderAgentEvent` (ui.ts style: dim `· thinking:` first line, `→ tool: detail`, `✓ agent turn done — in/out tok · $ · s`) wired via **`run --pretty`** (both hop loop + --until loop; unsupported adapters warn + stay raw). Tests: `AgentStreamParsing.test.ts` (14) — build green, 327 core + 92 cli pass; visual smoke via scratchpad demo. Next: eyeball desktop cards in a real Tauri build; consider `--pretty` for plan/execute/handoff + docs (COMMANDS.md) before releasing. Prior history below._ _2026-06-23 — **v1.0.0 GA SHIPPED.** Public release done: npm `@relay-baton/cli` + `core`/`shared`/`tui` all live @ 1.0.0 (under the `@relay-baton` npm org; CLI is scoped because unscoped `relay-baton` is taken and `relaybaton` was rejected as too-similar — bin stays `relay-baton`). GitHub Release **v1.0.0** is public with CLI binaries + desktop installers + SBOM + `SHA256SUMS` (release run `27925206710` green). The `v1.0.0` git tag was moved off the old internal "Stable Local Release" milestone onto the GA commit. Fixed a Windows-only CI failure (`GitWorktree.test.ts` 8.3 short-path compare → use `fs.realpathSync.native`; main CI green on `42f7166`). Desktop version strings aligned to 1.0.0 (`desktop/package.json`+lock, `tauri.conf.json`, `Cargo.toml`) so the NEXT release's installers drop the stale `2.6.0` name. **Distribution is fully live:** npm (`@relay-baton/cli` + libs), Homebrew tap, Scoop bucket, and Winget (winget-pkgs#391897 merged) all install v1.0.0; release fan-out is automated (`scripts/bump-version.mjs` + release.yml `publish-npm`/ `update-brew-scoop`/`update-winget` jobs, secrets configured). Remaining post-GA: code signing (paid, user decision — Phase 1은 진행 안 하기로 함), demo GIF, announce. **2026-07-09 — v2.8 (Smarter relay) FEATURE-COMPLETE locally (not released).** Both boxes `[x]`. Item 1: `HandoffTriggerPolicy` (core/plan) — opt-in `handoffTriggers` config (`budgetRatio`/`changedFiles`/`usageTokensProxy`), no-op when absent; `run --handoff-now` manual trigger (explicit consent); threshold hits prompt y/N (or `--yes`) before relaying on a clean exit (`relayReason` threading in `run.ts`). ConfigSchema validates the block. Item 2: `AgentRegistry` entries gain `strengths` tags; `suggestChain` (core, `RoutingHints.ts`) reorders the resolved chain by deterministic keyword match; `run` prints an advisory hint only (suppressed by `--chain`/`--primary`). Tests: `SmarterRelay.test.ts` (9). Build green, 313 core + 89 cli pass. Prior history below._ _Earlier: 2026-06-16 — **v2.3 (Multi-agent breadth) FEATURE-COMPLETE locally (not yet released).** Both boxes `[x]`. Item 1: central **agent registry** (`packages/core/src/agents/AgentRegistry.ts`) — tier (first-class codex/claude vs supported), install URL, login spec, default args, per-agent fallback patterns; OpenCode/Gemini/Aider promoted scaffold→supported; **Cursor CLI** (`cursor-agent`) added (`AgentId` gains `cursor`); registry-driven `login`; `doctor` shows all 6 agents + tier; `ConfigSchema`/`diagnostics` derive lists from the registry. Item 2: **N-way & reverse relay** — `run` is now a generalized relay loop over an ordered chain (`resolveChain`: `--chain` > `--primary`/`--fallback` > project > config); supports reverse (claude→codex) + longer chains; `PromptBuilder. continuation()` is agent-agnostic. New tests `AgentRegistry.test.ts` + `relayChain.test.ts`. SHIPPED & VERIFIED on `v2.3.0-alpha.0` (run `27602507471`). **v2.4 (Smarter handoff) FEATURE-COMPLETE locally (not yet released).** Both boxes `[x]`. Item 1 — deterministic compaction v2: `SymbolOutline` (TS/JS/PY/C#/ Go/Rust/Java + Markdown headings) feeds a "## Symbols" section in the repo map; `DiffCompactor.compactRanked` ranks diff chunks by task/path proximity (used by `buildHandoff`). Item 2 — local usage insight: `UsageLedger` append-only `.ai-session/usage.jsonl` token proxy (`ceil(chars/4)`), recorded by `run`/`handoff`; new `relay-baton usage [--json]` (totals, per-type/agent, budget ratio). Local only, never transmitted. New `CompactionV2.test.ts` + `UsageLedger.test.ts`. SHIPPED & VERIFIED on `v2.4.0-alpha.0` (run `27657546301`). **v2.5 (Guarded automation & extensibility) FEATURE-COMPLETE locally (not yet released).** Both boxes `[x]`. Item 1 — bounded auto-orchestration: `BoundedOrchestrator` (core) = `LoopController` + `GuardrailPolicy`; `run --until ` runs ≤N extra continue-steps on the completing agent, confirmation-first (prompts unless `--yes`), checkpoint+usage per step. Strictly bounded, no daemon (respects CLAUDE.md "no autopilot" — chosen "strict bounded" approach). Item 2 — project recipes/hooks: optional `hooks.preHandoff`/`hooks.postExecute` config arrays run by `HookRunner` (core), local-only, env-sanitized, no network, no-op when absent, stop-on-first-failure; wired into `run`+`handoff`. New `BoundedOrchestrator.test.ts` + `HookRunner.test.ts`. Build green, 296 core + 88 cli tests pass. SHIPPED on `v2.5.0-alpha.0`. **v2.6 (Multi-session workspace) FEATURE-COMPLETE locally (not released).** All three boxes `[x]`. Item 1 named sessions: `WorkspaceManager` owns `.ai-session/workspace.json` (active + list); named items under `.ai-session/sessions//`, legacy flat `.ai-session` = `default` (zero migration); `SessionFiles` resolves the active item so all commands follow it; `session new|switch|use|items|assign|remove`. Item 2 per-agent assignment: work items carry `assignedAgent`; `run` uses it as default primary (beats project/config, loses to `--primary`/`--chain`). Item 3 git-worktree isolation: `GitService.addWorktree/listWorktrees/removeWorktree`; `session worktree add|remove`; `run` executes in the work item's worktree when set (own tree + own `.ai-session`) for safe parallelism; registry stays in main repo. New `WorkspaceManager.test.ts` + `GitWorktree.test.ts` + relayChain assignment test. Build green, 304 core + 89 cli tests pass. **SHIPPED & VERIFIED on `v2.6.0-alpha.0`** — release run `27669752717` green (first release with the macOS DMG-retry fix; no flake), provenance verifies (SLSA v1), `sbom-diff.md` published (no dep changes vs v2.5.0-alpha.0), 9 assets. Next: **v2.7 — GA** (first public release as v1.0.0: LICENSE, npm publish, GA versioning, code signing, package managers). Post-GA proposed line **v2.8 — Smarter relay** added to ROADMAP: deterministic ideas borrowed narrowly from Hermes/OpenCode (broadened fallback triggers + advisory routing hints) — explicitly NOT their resident orchestrator-AI architecture (decision: relay-baton stays a baton-touch harness, not a judge-AI control loop). **v2.7 GA — Phase 0 IN PROGRESS (local, not released).** Decisions: **MIT** license + GA cut as **1.0.0** (off the alpha line). Done: top-level `LICENSE` (MIT, © 2026 DongGeon Lee) + per-package copies + `license` fields; all four packages versioned 1.0.0 (+ CLI `--version`); all four publish under the **`@relay-baton` scope** (npm org `relay-baton`, free): **`@relay-baton/cli`** + core/shared/tui. (Naming history: unscoped `relay-baton` is taken on npm @ v4.0.5, and `relaybaton` was rejected by npm as "too similar" — so the CLI lives in the scope; bin stays `relay-baton`.) `publishConfig.access:public`/`files`/ `engines`/`repository` on all four; `CHANGELOG.md` + `CONTRIBUTING.md` + issue templates added; README npm quickstart (`npm i -g @relay-baton/cli`) + badge. **PUBLISHED to npm @ 1.0.0:** `@relay-baton/shared`, `@relay-baton/core`, `@relay-baton/tui` are live; `@relay-baton/cli` pending re-run after the rename (2FA needs an automation token; `git push` + `v1.0.0` tag still pending). **Remaining in Phase 0:** publish `@relay-baton/cli`, demo GIF (deferred). Then Phase 1 (signing, package managers) + Phase 2 (announce). No commit/push yet (awaiting user request). **2026-07-10 — released as v1.3.0** (tag pushed; first release where the npm publish job runs with the NODE_AUTH_TOKEN fix — verify all four channels). Multilingual notes (EN+ko+8 locales) + CHANGELOG + README/i18n Latest lines all updated to v1.3.0. Detail of what shipped: (1) v2.8 features now documented in `docs/COMMANDS.md` + `COMMANDS.ko.md` + GUIDE EN/KO + README config section (`--handoff-now`, `handoffTriggers` block, routing hints). (2) Friendly `ui.ts` output extended beyond `run` to `doctor`/`init`/`status`/`login`/ `handoff` (doctor/login now respect NO_COLOR/non-TTY). (3) New read-only **`relay-baton route "" [--json]`** command exposing `suggestChain` (+`route.test.ts`, 3 tests → 92 cli). (4) `doctor` surfaces whether `handoffTriggers` is configured. (5) Record-ready demo: `scripts/demo/demo.sh` + `fake-agent.mjs` (deterministic fallback→handoff→resume, no quota; verified end-to-end on this machine — needs `cygpath -m` on Git Bash, already handled). Ship these as v1.2.1 or fold into the next minor. **Decisions (this session):** - Multi-session/multi-task is now its own **v2.6** line (pulled in before GA): unifies per-agent session assignment + multi-tasking as named "work items"; parallel execution only via per-item git worktrees (no daemon, deterministic). - GA will be cut as **v1.0.0 at v2.7** (after Phase-0 blockers: LICENSE, npm publish, GA versioning). v2.x stays alpha until then._ Prior: **v2.2 SHIPPED & VERIFIED on `v2.2.0-alpha.0`** (run `27597659547` green; provenance attestation verifies, `sbom-diff.md` published). Roadmap milestone **v2.6 — Public release & distribution (GA)** captures launch blockers (LICENSE, npm publish, code signing, package managers, announce)._ **v2.2 detail (all local):** - **(1) Path-traversal safety** — `inspect` on handoff bundles & session archives refuses untrusted manifest `target`s via shared `resolveWithin` (rejects absolute / `..` / symlink) + 8 MiB cap; results gain `unsafe[]` + top-level `safe` (CLI prints `trust: safe|UNSAFE`). Bundler/archiver now write bundle-relative POSIX targets. New `packages/shared/src/safe-path.ts`, `pathTraversalSafety.test.ts`. 262 core + 83 cli tests pass. - **(2) Provenance by default** — `release.yml` `release-finalize` attests the 3 CLI binaries + `SHA256SUMS` with `actions/attest-build-provenance` (default token, no secrets). Added `attestations: write`. Verify: `gh attestation verify --repo dgl1231/relay-baton`. - **(3) Supply-chain hardening** — all Actions pinned by SHA (`ci.yml` + `release.yml`); `.github/dependabot.yml` (npm root+desktop, cargo, actions, grouped weekly); `.github/scripts/sbom-diff.mjs` diffs SBOM vs previous release → `sbom-diff.md`. CI/workflow YAML validated. ## Where we are - **v1.9 alpha is SHIPPED** on tag **`v1.9.0-alpha.0`** — team handoff package (`handoff bundle`/`inspect`, redaction pass, `report`, desktop export). - **v1.8 alpha is SHIPPED** on tags **`v1.8.0-alpha.0`** / **`v1.8.0-alpha.1`** — project intelligence (`workspace`, `profile`, `inventory`, desktop inspector). - **v1.7 alpha is SHIPPED** on tag **`v1.7.0-alpha.0`** — guarded execution (`checkpoint`, `guard`, `risk`, desktop guarded-execution view). - **v2.1 is COMPLETE** — "Reliability & secret safety": Windows-safe agent spawn (`alpha.0`), redact-before-handoff Redaction Gate (`alpha.1`), and secret-leak regression scan + `--allow-api-key-env` audit (latest, local). All three v2.1 roadmap boxes are `[x]`. Next line: v2.2 (Trust & supply chain). - **v2.2 is FEATURE-COMPLETE locally** — "Trust & supply chain". All three boxes `[x]`: path-traversal safety, signed releases + provenance by default, and supply-chain hardening (pinned actions + Dependabot + SBOM diff). Not yet released. - **v2.0 is FEATURE-COMPLETE** — alpha.0..alpha.6 shipped (migration checks, schema migrator, desktop contract, hard constraints, installer/docs finalize, git-baseline schema, prune policy + CI race fix). Latest local (not yet released): conversation-event schema versioning + `session export`, closing the last v2.0/v1.6 `[~]` items. Every planned v1.x/v2.0 roadmap box is now `[x]`. Future direction captured in ROADMAP "Beyond v2.0 — proposed" (additions + hardening; nothing committed). Only remaining `[~]`: v1.2 desktop local-build note (environment caveat, not code). - **v1.6 alpha is SHIPPED** on tag **`v1.6.0-alpha.0`** — session archives & recovery (read-only `session archive`/`list`/`inspect`/`resume` + desktop panel). Release run `27330492827` succeeded with all 8 assets published. - **v1.5 alpha is SHIPPED** on tags **`v1.5.0-alpha.0`** and **`v1.5.0-alpha.1`**. `alpha.0` added read-only git tracking, session baselines, desktop Git panel, Agent Room `/git`, and bounded git summaries in status/review/handoff surfaces. `alpha.1` closed the v1.4 deferred desktop updater item with opt-in/manual checks and signed-updater artifact support when secrets exist. - **v1.4 alpha is SHIPPED** on tag **`v1.4.0-alpha.1`**. Its deferred updater item is resolved in `v1.5.0-alpha.1`. - **v1.1 is SHIPPED** on tag **`v1.1.3`**. The GitHub Release carries three working standalone binaries: - `relay-baton-linux-x64` - `relay-baton-macos-arm64` - `relay-baton-windows-x64.exe` - Current release workflow for `v1.5.0-alpha.1` was started after tag push. At the time this handoff was written, CLI binary jobs and macOS desktop had passed; Linux/Windows desktop were still running. Re-check with: `gh run view 27326048647 --repo dgl1231/relay-baton --json status,conclusion,jobs`. README "Download" links point at `releases/latest`. ## What v1.1 delivered - Per-OS single-file executables via **Node SEA** (esbuild bundle → SEA blob → inject into a copied `node` with postject → codesign on macOS). - Automated release pipeline: [`.github/workflows/release.yml`](../.github/workflows/release.yml), triggered by `v*` tags, attaches binaries to the Release. - Tauri desktop **scaffold** in [`desktop/`](../desktop) (sidecar over the CLI, outside the pnpm workspace). NOT a full GUI yet — that's v1.2. - Docs: [`RELEASE.md`](./RELEASE.md) (runbook + gotchas), this file. ## How v1.1 was hard-won (so we don't regress) The first tag failed; it took v1.1.0 → v1.1.3 to get green. Four distinct issues, all in `release.yml` — full detail in [`RELEASE.md`](./RELEASE.md): 1. v1.1.0 — leading `&` in a pwsh `run:` scalar = YAML anchor → invalid workflow, no job ran. 2. v1.1.1 — `npx --yes esbuild/postject` not on PATH → exit 127. 3. v1.1.2 — `postject@^1` doesn't exist (its "latest" is a prerelease) → ETARGET. 4. v1.1.3 — pinned exact `esbuild@0.28.0` + `postject@1.0.0-alpha.6`. ✅ ## Current cleanup: v1.5 closed v1.5 feature work has shipped and all acceptance criteria in [`TASK-v1.5-git-tracking.md`](./TASK-v1.5-git-tracking.md) are checked: - `relay-baton git status` / `relay-baton git status --json` - non-git fallback with `available:false` - `.ai-session/git-baseline.json` on `init` - session baseline comparison in `git status --json` - bounded git summaries in `status --json`, `review --json`, and generated handoffs - desktop Git panel and Agent Room `/git` The v1.4 deferred updater item is being closed with: - Tauri updater/process plugins wired in the desktop shell. - Dashboard update card with opt-in/manual check. - Install still requires explicit confirmation; no silent updates. - CI enables updater artifacts only when Tauri updater signing secrets exist. - `latest.json` is generated only when signed updater artifacts are present. ## v1.6 — SHIPPED on `v1.6.0-alpha.0` Session archives & recovery, all read-only: `session archive` / `session list` / `session inspect` / `session resume`, plus a desktop session-archive panel + Agent Room `/sessions`, `/inspect`, `/resume` (all through the CLI sidecar). Manifest + SHA-256 integrity checks. Every v1.6 acceptance item in [`TASK-v1.6-session-archives.md`](./TASK-v1.6-session-archives.md) is checked. Deferred (later only): prune (dry-run first), zip/export. ## v1.7 — feature-complete (guarded execution workflow) Roadmap: [`ROADMAP.md`](./ROADMAP.md) → "v1.7 — Guarded execution workflow". Implemented locally after `v1.6.0-alpha.0`: - **Execution checkpoints** — `packages/core/src/plan/ExecutionCheckpoints.ts`; append-only JSON in `.ai-session/checkpoints.jsonl` (command, changed files, git summary, budget, result, ts). `list()` tolerant of malformed lines; `summarize()` builds the compact receipt. New `SESSION_FILES.checkpoints`. CLI: `checkpoint add `, `checkpoint list`, `checkpoint summary`. - **Stop-condition policy** — `packages/core/src/plan/GuardrailPolicy.ts` + `relay-baton guard [--json] [--exit-code]`. Caps from optional `guardrails` config (defaults: maxSteps 25, maxChangedFiles 40, maxBudgetRatio 0.9, requireConfirmation). Advisory; `--exit-code` exits 10 when blocked. - **Risk classifier** — `packages/core/src/plan/RiskClassifier.ts` + `relay-baton risk [--json]`. Flags deps/deletions/release/env-config/binary from git status with category + severity. - **Better receipts** — `checkpoint summary` (see above). - **Desktop guarded-execution view** — dashboard "guarded execution" card + Agent Room `/checkpoints`, `/guard`, `/risk` (`desktop/ui/index.html`), all read-only via the CLI sidecar. - tests: core `ExecutionCheckpoints` (7), `GuardrailPolicy` (4), `RiskClassifier` (4); CLI `checkpoint`, `guard`, `risk`. docs EN + KO. Validation already run: ```bash corepack pnpm build # green corepack pnpm test # 207 core + 64 cli pass node packages/cli/dist/index.js checkpoint add 1 --command "pnpm build" --result ok --path . node packages/cli/dist/index.js checkpoint summary --path . node packages/cli/dist/index.js guard --path . node packages/cli/dist/index.js risk --path . ``` Next: cut a `v1.7.0-alpha.0` release per `RELEASE.md` when ready, then start v1.8 (project intelligence & workspace map). Hard rule remains: GUI calls the CLI sidecar only. **No business logic in the webview.** Read-only or confirmation-first. No auto commit/push/PR unless the human explicitly asks for it. ## Environment notes (this dev machine) - `pnpm` is **not** on PATH directly. Use `corepack enable --install-directory /tmp/rbshim pnpm && export PATH=/tmp/rbshim:$PATH`, or just `corepack pnpm`. - `npx esbuild` fails locally too — install globally (`npm i -g esbuild@0.28.0 postject@1.0.0-alpha.6`) and call the bin directly. - `gh` CLI availability is **machine-specific** — re-check on each machine. - On the original Linux dev box it was unusable (config root-owned, 0600), so the human checked Actions/Releases in the browser. - On the Windows dev box it works fine: `gh 2.91.0`, logged in as `dgl1231` (token scopes `repo`, `workflow`, `read:org`, `gist`) — use `gh` directly for Actions/Releases/PRs there. - Repo branch protection prints "Changes must be made through a pull request" on push, but the push still lands on `main` (confirm with `git rev-parse origin/main`). Tags push cleanly. ## How to cut the next release See [`RELEASE.md`](./RELEASE.md) → "TL;DR — cut a release". Short version: bump versions everywhere, add release notes (en+ko) + index, update README badge, commit, push, then `git tag vX.Y.Z && git push origin vX.Y.Z`. ## Verify everything still works ```bash corepack pnpm install --frozen-lockfile corepack pnpm build corepack pnpm test ```