Skip to content
gwmgwmgwmv1.10.0

v1.0.0

gwm reaches 1.0.0. The surface is feature-complete and, crucially, the machine-readable contracts are now frozen under Semantic Versioning: the CLI subcommands / flags / exit codes, the --format=json schemas, the daemon JSON-RPC protocol, and the .gwm.toml section set will not break without a major bump. This stable promotes the entire 0.10.0 train (rc.1 → rc.4), consolidated below, and adds the post-rc.4 delta that closes the 1.0 sprint (#320).

The 0.10.0 cycle was the broadest in the project’s history. rc.1 made the Settings panel fully editable and enriched the TUI (Issue/PR pastilles, Working-Tree change counts, a Status diff line, cached GitHub state). rc.2 landed four new surfaces at once - a machine-readable JSON API + gwm daemon (#38), config presets for gwm init (#37), a multi-repo workspace mode (#36), and an embedded PTY overlay for lazygit and a native terminal (#35) - plus a keymap overhaul (redesigned list-view keymap with user macros, fully rebindable modal keys, a Settings Keys tab). rc.3 closed the GitHub loop with gwm review <PR#> and shipped the first daemon consumer, gwm statusline. rc.4 added the gwm exec / gwm clean fleet chores and brought the EN + docs/fr/ documentation in line with the surface.

The post-rc.4 stable delta completes the 1.0 commitment itself: the frozen, versioned machine contracts pinned by tests/contract_tests.rs (#317), the published Stability & compatibility policy (#318), the frozen exec / clean surface decision (#319), and the additive features that decision anticipated - named [exec] / [clean] config profiles, bounded --jobs parallelism, and --workspace fan-out for both fleet chores (#324, #326) - plus TUI exec / clean overlays (#325).

Install from crates.io (cargo install gwm-cli or cargo binstall gwm-cli), the Homebrew tap (brew tap kbrdn1/tap && brew install gwm), the prebuilt release archives (Linux / macOS / Windows, attached to this release), or the Nix flake (nix profile install github:kbrdn1/gwm-cli). The crate is published as gwm-cli - the bare gwm name on crates.io belongs to an unrelated project - but the installed command is still gwm. MSRV is 1.86 (raised from 0.9.0’s 1.82 by the tui-term 0.3 PTY-overlay dependency; the bump rides this minor as documented in the stability policy).

No .gwm.toml migration is required. Every config addition in the 0.10.0 train is additive and opt-in: [exec] / [clean] (incl. [exec.profiles.*] / [clean.profiles.*]), [tui].auto_refresh_secs, [tui.macro1] / [tui.macro2], and the nested [tui.keys.modal.<context>] sub-tables. An existing config - and an omitted [theme] / [tui.keys] - sees no change in behaviour. Pre-#290 [tui.keys] action slugs still load through backward-compat aliases.

What 1.0 freezes. Per the new Stability policy, the covered surfaces are the CLI subcommands / flags / exit codes, the --format=json output schemas (list / doctor / path / status --json, baseline SCHEMA_VERSION = 1), the daemon JSON-RPC protocol, and the .gwm.toml section set. Free to change in a minor / patch: the TUI layout & colours, human-readable strings, and the internal Rust API.

The post-rc.4 work that lands directly in 1.0.0 - the heart of the SemVer commitment plus the additive fleet-chore configuration it unblocks.

  • Frozen, versioned machine contracts for 1.0 (#317). The machine-readable surfaces - the --format=json outputs (list / doctor / path), gwm status --json, the daemon JSON-RPC protocol, and the .gwm.toml section set - are now pinned by contract tests (tests/contract_tests.rs) so a rename, removal, or type change of a stable field fails CI rather than slipping out as an accidental break. The guards are layered: DTO-vs-schema parity, plus DTO-side and schema-side field/type baselines that also catch a coordinated rename or a re-tightened additionalProperties. A new gwm::contract module is the single source of truth for SCHEMA_VERSION (the 1.0 baseline, 1), the frozen daemon method / notification names, and the config section set. The daemon’s worktrees.changed notification now carries params.schema_version so a long-lived subscribe client can detect a contract drift; the field is additive and ignorable. The output schemas use additionalProperties: true so an additive field validates under the same version (consumers ignore unknowns), while .gwm.toml keeps deny_unknown_fields (input rejects typos). Each docs/schema/*.json declares its version, and a new docs/schema/README.md documents the versioning policy and the stable-vs-experimental tier of every field. No behaviour change to any existing output.
  • Named [exec] / [clean] config profiles (#324). .gwm.toml gains two opt-in sections so common fan-out invocations can be saved per repo instead of retyped. [exec.profiles.<name>] carries a command argv array run via gwm exec --profile <name>; [clean.profiles.<name>] carries a dirs set reclaimed via gwm clean --profile <name>. Both are now part of the frozen 1.0 contract (contract::CONFIG_SECTIONS gains exec / clean). Frozen rules: an exec profile’s command is an argv array run with no shell (a deliberate divergence from the string-shell command of [git_tui] / [review]); a clean profile’s dirs is a complete set that replaces - never adds to - the built-in target / node_modules / dist / build; gwm clean without --profile uses [clean.profiles.default] when present, else the built-ins; for exec, --profile and an inline -- <cmd> are mutually exclusive (exit 1) and an unknown profile name exits 1. The safety gate (git-ignored + no tracked files + skip symlinks) still applies to every directory a clean profile lists.
  • Bounded --jobs parallelism for gwm exec (#324). gwm exec gains a --jobs <n> flag and an [exec] jobs config default (with a per-profile [exec.profiles.<name>].jobs override). Precedence: --jobs > profile.jobs > [exec] jobs > 1. 1 (or absent) keeps the unchanged sequential behaviour with live, inherited output; > 1 runs up to N worktrees at once, capturing each one’s stdout+stderr and printing it as a per-worktree block in worktree order once the fan-out completes (so concurrent runs don’t interleave). The aggregate exit code is unchanged (non-zero if any worktree failed). The runner uses a bounded std::thread pool - no new dependency. jobs is a sub-field of the already-frozen [exec] section, so the 1.0 section set is unchanged.
  • --workspace fan-out for gwm exec / gwm clean (#326). Both commands now accept the global --workspace <root> flag and fan out across the workspace’s child repos, reversing the #319 deferral (the refusal is gone). Each repo’s command / dir-set is resolved UPFRONT - a missing --profile, a malformed [exec] / [clean], or an unopenable child repo errors before anything runs (or, for clean --yes, before any remove_dir_all). Repos then run sequentially (parallelism stays bounded within a repo, so output never interleaves across repos) under a ══ <repo> header, with a <repo>/<worktree>-tagged rollup / report and an aggregated exit code (non-zero if any worktree in any repo failed; for clean, a delete failure in one worktree is reported but doesn’t abort the rest). --profile resolves per child repo against that repo’s .gwm.toml. This is an additive transition (a former refusal turning into a success is not breaking). The --workspace refusal remains for commands that still don’t implement it.
  • TUI exec / clean overlays (#325). The ratatui interface gains two overlays over the worktree list: x opens an exec picker that lists the [exec.profiles.*] names and, on Enter, runs the highlighted profile’s command array - with no shell - in the embedded PTY overlay rooted at the selected worktree; X opens a clean overlay that previews the reclaimable build artifacts (gated by the exact git-ignored + no-tracked-files safety check gwm clean --yes uses) and deletes them behind the same safety countdown as the delete confirm. Both overlays’ keys are rebindable under [tui.keys.modal.exec] / [tui.keys.modal.clean], and :exec / :clean reach them from the command palette. The exec overlay runs on the single selected worktree (one PTY cannot fan out, unlike the CLI --workspace); the clean safety gate (dir_is_safe_to_clean / scan_worktree_safe) is now shared between the CLI and the overlay so both honour the identical contract. This is a TUI-only surface - the frozen 1.0 machine contract is unchanged.
  • Frozen 1.0 surface decision for exec / clean (#319). The deliberate MVP cuts in gwm exec / gwm clean (#313) were confirmed as deferred, additive features for the 1.0 pledge - exec sequential by default (bounded --jobs now opt-in, above), clean keeping its built-in artifact set (the [clean] / [exec] profile config now additive under #324), and the cross-repo --workspace fan-out (now additive under #326). The transition is additive: a previous refusal becoming a success is not a breaking change.
  • Help overlay + exec/clean overlay polish (#334). The #325 exec (x) and clean (X) overlays were reachable by key and palette but missing from the hand-curated ? help overlay - now documented there (and hidden in the gwm switch picker mode where they no-op), guarded so a newly bound action can’t silently disappear from ? again. The overlays themselves gain a full-width, scrollable picker (selection bar, ↑ / ↓ N more markers), a magnitude heatmap on reclaimable sizes, and an ecosystem-matched nerd-font icon per reclaimable directory.
  • ⬆️ ratatui 0.30.1 → 0.30.2 (#336).
  • ⬆️ which 8.0.3 → 8.0.4 (#337).
  • Stability & compatibility policy for 1.0 (#318). A new Stability page (EN + docs/fr/) is the explicit, published SemVer contract behind the 1.0 line: which surfaces are covered (CLI subcommands / flags, exit codes, the --format=json schemas, the daemon JSON-RPC protocol, the .gwm.toml section set), which are free to change in a minor / patch (TUI layout & colours, human-readable strings, the internal Rust API), the MSRV policy (currently 1.86, bumps ride a minor), and the deprecation process. It distinguishes surfaces frozen by tests/contract_tests.rs from those covered by the written promise, and defers the per-field stable / experimental tiers to docs/schema/README.md. Linked from the README and CONTRIBUTING.md.

Historical delta: [0.10.0-rc.1] - 2026-06-10

Section titled “Historical delta: [0.10.0-rc.1] - 2026-06-10”

Delta against v0.9.0. Merged PRs: #273, #274, #276, #277, #280, #282, #284, #286, #288.

The Settings-editability + TUI enrichment release. The Settings panel (4) goes fully editable - category tabs (Theme / Worktree / TUI / All), a per-project ↔ global layer selector, real toggles / choices / numeric inputs / free-text fields, live persistence into TOML and on-the-fly apply. On top of that: the Working Tree pane gains colour-coded nerdfont changed-file counts (created / modified / deleted) that also recolour the file rows, the Status pane gains a Diff +ins -del line vs the base branch, and the Issue/PR table and pane are enriched with ●/● pastilles, nerdfont state-chip badges, cached GitHub state that survives restarts, and a periodic [tui].auto_refresh_secs auto-refresh. The async-task spine gains two new consumers: create-worktree and quit-wait, so neither blocks the render loop. No CLI or config-schema change apart from the new [tui].auto_refresh_secs key.

  • ✨ Settings panel (4, renamed from Configuration) is now editable: category tabs (Theme / Worktree / TUI / All) with the edit layer shown as a subtitle, a per-project ↔ global edit-layer selector (L), real toggles / choices (theme preset, sidebar position, open mode), numeric input (confirm countdown), and text inputs (worktree base + patterns, open shell / editor commands). Edits persist into the chosen layer’s TOML and apply live; a global edit shadowed by a .gwm.toml override is surfaced rather than silently dropped. The read-only resolved config lives under the All tab (#279).
  • ✨ Scrollable modal bodies (Keybindings, Settings) now render a herdr-style scrollbar (#279).
  • ✨ Reusable dedicated-area LoaderWidget; the delete-worktree modal is the first real consumer, showing both in-flight and failed delete states (#257).
  • ✨ Sidebar Working Tree pane bottom-right footer breaks the changed-file tally into colour-coded nerdfont counts - created (green), modified (yellow), deleted (red) - derived from git status --short, each segment shown only when non-zero (clean tree shows nothing). Every file row is recoloured by the same change category; the previous staged-vs-worktree cyan column split is retired (#287).
  • ✨ Sidebar [2] Status pane now shows a Diff +<ins> -<del> line (insertions green, deletions red) for the branch versus its base trunk, using three-dot git diff --shortstat <base>...HEAD semantics. Hidden when no base resolves, when HEAD is the trunk itself, or when the branch has no committed diff yet (#287).
  • ✨ Worktree table renders Issue/PR as two slots ●/●, ●/-, -/●, or -/- (left = Issue, right = PR; - means no link; the main worktree keeps its ★). The Issue/PR pane leads each line with a nerdfont dev glyph and badges the link source (auto / detected) and GitHub state (open / closed / draft / merged) as version-style reverse-video chips (#283).
  • ✨ [tui].auto_refresh_secs controls periodic TUI worktree refreshes. Default is 60 s; 0 disables. Exposed in the Settings panel under the TUI tab (#285).
  • ✨ Project tooling ships a Flippad-style coloured Makefile plus Zed tasks for the local Rust workflow (build, test, clippy, doctor, audit, worktree bootstrap, and related shortcuts).
  • 💄 Statusbar and modal which-key hints drop the reverse-video badge for a flat “accent bind
    • muted action“ treatment; action buttons keep their chip style. Keybindings and Command Logs overlays scroll their body only, keeping title and footer hints pinned, with a herdr-style scrollbar. Command Logs separates entries with a full-width dashed rule and copies the whole transcript to the clipboard with y (#279).
  • 💄 Auto-detected PR (gh pr list --head <branch>) is now persisted to a dedicated branch.<name>.gwm-pr-detected git-config key on F refresh. Issue/PR titles and states (gwm-issue-title, gwm-issue-state, gwm-pr-title, gwm-pr-state, gwm-pr-detected-title, gwm-pr-detected-state) are persisted after successful status fetches, so the pane shows cached titles, state chips, and state-coloured icons on startup before or during a new fetch. An explicit gwm link --pr still wins; a vanished detection clears the stored key / title / state (#285).
  • 💄 Worktree table’s first Created column and sidebar’s Created row now use the local branch-creation timestamp recorded by gwm create (branch.<name>.gwm-created-at) when available, with trunk-divergence age as a fallback for existing branches (#285).
  • 💄 Issue/PR pane icons keep two spaces after the glyph with no leading icon padding, and use the loaded GitHub state colour (open / closed / draft / merged) instead of always rendering muted (#285).
  • 🐛 Worktrees pane Issue/PR pastilles now switch to loaded GitHub state colours across all linked rows after a worktree refresh, so closed issues/PRs no longer fall back to the linked-only colours after relist (#285).
  • 🐛 TUI now kicks off an initial Issue/PR status refresh for all linked worktrees at startup when a GitHub remote is available, and worktree refreshes persist refreshed Issue/PR state per branch so markers survive closing and reopening the app (#285).
  • 🐛 Settings free-text fields (worktree base / patterns, open shell / editor commands) persist as TOML strings, so a value like 123 or true is no longer coerced to a number / bool. Config writes validate before touching disk (a rejected edit can never overwrite a good config file) while an edit to an already-invalid file is still written so gwm config set can recover a broken config (#281).
  • 🐛 Scrollable modal bodies (Keybindings, Command Logs, Settings) compute the horizontal-pan bound after reserving the scrollbar column, so the final cell of a long line stays reachable (#279).
  • 🐛 Delete-worktree confirmation no longer blocks the TUI render loop while the removal runs; the async spine drives the deletion and quit waits for it like other mutating tasks (#257).
  • 🐛 Create-worktree submission no longer blocks the TUI render loop while worktree::add and bootstrap run; the Create modal shows a dedicated loader / failure row and the global statusline spinner stays active until completion (#276).
  • 🐛 TUI quit now waits for in-flight mutating spine tasks (sync / bootstrap / delete-worktree) to finish instead of abandoning them mid-operation (#267).
  • TDD throughout; the full suite is green locally (env-minimal PATH) and on the ubuntu-latest / macos-latest / windows-latest matrix. The Settings editability, LoaderWidget, Issue/PR pastilles and cached-state logic, Working Tree colored counts, Status diff line, and the async create / quit changes are all pinned by state-machine and helper tests (tests/tui_app_tests.rs, tests/tui_ui_helpers_tests.rs, tests/tui_footer_tests.rs, tests/tui_theme_audit_tests.rs) - no ratatui backend needed.

Historical delta: [0.10.0-rc.2] - 2026-06-16

Section titled “Historical delta: [0.10.0-rc.2] - 2026-06-16”

Delta against v0.10.0-rc.1. Merged PRs: #289, #292, #293, #297, #301, #302, #303, #305, #306.

The second 0.10.0 train. This candidate is dominated by four new surfaces - a machine-readable JSON API + gwm daemon for editor / statusbar tooling (issue #38), config presets for gwm init (issue #37), a multi-repo workspace mode (issue #36), and an embedded PTY overlay for lazygit and a native terminal (issue #35) - plus a keymap overhaul: a redesigned list-view keymap with user macros (#290), fully rebindable modal keys with contextual actions (#219), and a Settings Keys tab that captures and persists bindings live (#294). The Status pane gains a current-PR CI status indicator (#299) and the Working Tree pane becomes a nerd-font file-explorer tree (#300). No breaking changes; the default text output of every command is unchanged.

  • JSON API + daemon mode (issue #38): a structured, machine-readable surface for editor / statusbar / tooling integration, so consumers no longer shell out to gwm and parse human output.
    • --format=json on gwm list, gwm doctor, and gwm path (gwm path / gwm doctor also accept --format=text, the default). Each emits a stable, documented schema decoupled from gwm’s internal types - JSON Schema files live under docs/schema/ (worktree-list, doctor, path). gwm list --format=json includes the main worktree (unlike names); gwm doctor --format=json keeps the conventional 0/1/2 process exit code and also carries it as a field. Additive - the default output stays human-readable text.
    • gwm daemon: a long-running JSON-RPC 2.0 server over a unix domain socket ($XDG_RUNTIME_DIR/gwm.sock, falling back to $TMPDIR then /tmp; override with --socket). Exposes list / doctor / path request/response methods plus subscribe, which streams worktrees.changed notifications (initial snapshot then one per change). Newline-delimited JSON. Change detection is interval polling (--poll-ms, default 1000) rather than a filesystem watch - a deliberate MVP choice (no extra dependency, deterministic, MSRV-safe; latency bounded by the interval). Unix-only, behind the default-on daemon Cargo feature; on other platforms / --no-default-features builds the subcommand exits with an explanatory error (it stays listed so --help is identical everywhere). No new runtime dependencies - the socket uses std::os::unix::net.
  • Config presets for gwm init (issue #37): gwm init --preset <name> seeds an opinionated .gwm.toml for a known stack instead of the generic template. Built-ins: laravel (env copies + AWS-RDS guard + vendor/ no-symlink + composer install), node / nuxt (node_modules/ no-symlink + bun-or-npm install), rust (target/ no-symlink + cargo fetch), go (bin/ no-symlink + go mod download), python-uv (.venv/ no-symlink + uv sync), and generic (the documented default). gwm init --list-presets enumerates them with one-line descriptions, and gwm init --preset <name> --show prints the resolved TOML to stdout without writing (handy for diffing against an existing config). Preset bodies are embedded in the binary and kept in sync with examples/presets/<name>.toml. gwm init with no flag stays byte-for-byte the generic template.
  • Multi-repo workspace mode (issue #36): operate across every git repo one level below a root directory instead of a single repo. Two entry points:
    • gwm --workspace ~/Projects opens the TUI over every direct-child repo, and gwm list --workspace ~/Projects prints the merged worktree table. Both accept the flag before or after the subcommand (global = true).
    • Bare gwm in a directory that is not itself a git repo but holds child repos prompts No git repo here. Open <dir> as a workspace? [Y/n] (declined silently when stdin is not a terminal, so pipes / CI keep the old single-repo behaviour).
    • The CLI table and the TUI list gain a leading REPO column naming each row’s repo. In the TUI the active repo follows the selection, so every selection-driven action (lazygit, terminal, sync, delete, link, open, …) operates on the highlighted worktree’s own repo.
    • gwm create in workspace mode requires --repo <name> to disambiguate which child repo gets the new worktree; an absent or unknown name lists the candidates.
    • .gwm.toml stays per-repo - each row inherits its own repo’s config. There is no workspace-level config in this version; the keymap and theme resolve once from the first repo, matching the single-repo “resolved once, relaunch to change” contract.
  • PTY overlay for lazygit and native terminal (issue #35): press l to open lazygit inside a ~90 % fullscreen embedded PTY overlay; press L to open it fullscreen; o / O do the same for a native $SHELL session. Both overlays stay inside the TUI - no alternate screen swap. Esc closes the overlay; q inside lazygit quits lazygit and auto-closes. The keybindings (lazygit_pty, lazygit_fullscreen, terminal_pty, terminal_fullscreen) are fully rebindable in [tui.keys]. Powered by portable-pty 0.9 + tui-term 0.3 (tui_term::vt100 - bundled vt100 0.16).
  • Current-PR CI status indicator in the Status pane (issue #299): the Issue / PR section (2) now renders an overall CI state for the linked PR instead of a bare · checks N/M. A coloured nerd-font indicator ( CI passing 9/9 green, CI failing 7/9 red, CI running 8/9 yellow) is derived from the statusCheckRollup already fetched - no extra GitHub request. The state follows failing > running > passing so a red check is never hidden behind an in-flight one; a PR with no checks renders nothing.
  • Edit every keymap from the Settings panel (issue #294): the Settings panel (4) gains a Keys tab that lists every rebindable binding - the global list-view actions ([global]) and every modal verb grouped by context ([modal.<context>]) - each with its current key(s) and a default/user/repo source badge. Select a binding, press the activate key, and capture a new key live: the key column becomes a [ … ] input that records the actual keystroke(s) pressed. A multi-stroke global chord commits on Enter (Backspace drops the last stroke); a single-stroke modal verb auto-commits on the first key; Esc cancels.
    • The capture writes a TOML array to the layer the panel targets ([tui.keys] for a global action, [tui.keys.modal.<context>] for a modal verb), honouring the project ↔ global layer toggle (L).
    • The write is validated before it touches disk - a conflict / prefix-collision aborts it, leaves the previous binding live, and reports the error on the statusbar - then the keymap reloads so the new key works immediately, no restart.
    • An empty capture unbinds the action (global). Esc, Enter, Backspace and Ctrl+C can’t be assigned via capture by design - hand-edit .gwm.toml for those.
    • New config_cli::set_array_at array write-back backs the persistence.
  • Rebindable modal keys with contextual actions (issue #219): the modal/overlay keys that used to be hard-coded (create form, delete-confirm, link prompt, settings panel, command logs, help, open-menu, command palette, bootstrap report) are now remappable under nested [tui.keys.modal.<context>] sub-tables in .gwm.toml. Each context owns typed verbs, so the same physical key can mean different things in different modals (Enter is submit in the create form but activate in the delete-confirm modal). The dedicated modal namespace keeps a context from colliding with a same-named global action (create/help/command_logs/ link): a global create array and a modal [tui.keys.modal.create] table coexist across config layers.
    • Modal bindings are single keystrokes only (no chord timeout); a multi-stroke chord is rejected at load time.
    • Two-stage surfaces use a dotted path - [tui.keys.modal.link.choose_target], [tui.keys.modal.link.input_number], [tui.keys.modal.config.edit].
    • gwm tui keys lists every context and verb; gwm doctor validates the contextual bindings (re-reading the on-disk config) and reports per-context conflicts.
    • The Keybindings help overlay and the statusbar footer hints now resolve modal keys from the override layer instead of fixed strings.
    • Ctrl+C, the list view’s contextual Esc/Enter, and the PTY overlay’s emergency Esc stay hard-coded by design.
  • TUI keymap redesign (issue #290): unified, consistent key bindings across the worktree list. New actions and default bindings:
    • p → pull - git pull on the selected worktree’s branch (async, progress shown in status bar).
    • P → push - git push on the selected worktree’s branch (async).
    • c → edit_worktree - rename modal mirroring New Worktree (Type / Issue / Desc), pre-filled by parsing the current branch. Submitting renames the local branch (git branch -m), the remote branch when it exists on origin (git push origin :<old> <new>:<new> + upstream re-track), and moves the worktree directory on disk (git worktree move) so the slug stays in sync - all off-thread.
    • e → exit_to_worktree - quit TUI and print the selected path to stdout, enabling cd "$(gwm)" shell patterns.
    • y → yank_branch_name - copy the selected branch name to clipboard.
    • w → yank_worktree_name - copy the selected worktree name to clipboard.
    • t → mux_pane - open the selected worktree in a new tmux/zellij pane.
    • h / H → macro_one / macro_two - run user-configured commands from [tui.macro1] / [tui.macro2] in the project .gwm.toml.
    • s (was S) → sync; D (was p) → toggle_delete_branch; l → lazygit_pty; r → review_pty.
    • Sidebar keys: V → toggle_sidebar (show/hide), S → toggle_sidebar_mode (Commits ↔ Stashes), Space → cycle_sidebar_layout (auto / side-by-side / stacked), v → toggle_sidebar_position (left ↔ right).
    • Action slugs aligned: lazygit_fullscreen, terminal_pty, terminal_fullscreen, review_fullscreen, yank_path.
    • Pre-#290 [tui.keys] slugs (git_tui, review, yank, open, open_menu, …) still load via backward-compat aliases.
  • [tui.macro1] / [tui.macro2] config (issue #290): user-defined commands launched from the TUI. Each entry accepts a command string and an optional open_in field ("pty" - default; "mux_pane" for a new tmux/zellij pane).
  • Working Tree pane as a file-explorer tree (issue #300): the Status pane’s Working Tree section (2) now renders git status as a nested, nerd-font file tree instead of a flat XY PATH list. Directories sort before files (alphabetical within a level) and single-child directory chains collapse (src/tui/ then ui.rs); each file row carries an extension-driven file-type icon plus its M / A / D / ? status badge, all painted in the file’s change-category colour (so a row matches the footer count it belongs to). The counts footer is unchanged. The tree builder (flat status → tree model) is a pure, ratatui-free function with unit tests.
    • Tree connector lines (├─ / └─ / │) draw the hierarchy like tree(1), in the muted role.
    • Directory rows are coloured retroactively by git: a folder takes the aggregate change-category of its subtree - only-modified → yellow, only-new → green, only-deleted → red, mixed → neutral accent.
    • An extra space pads each nerd-font glyph (most render double-width in a single cell) so the following name isn’t clipped.
    • A pathological untracked directory is bounded at two levels: the git status scan is streamed and stopped after 5000 records (git is killed once the cap is hit, so its directory walk can’t run away), and the tree then renders at most 500 file leaves with the remainder shown as a single … N more row (… N+ more when the scan itself was truncated, since the true total is then unknown) - selecting such a worktree can neither stall the scan nor flood the non-scrollable section. The scan runs under --no-optional-locks so killing it at the cap can’t leave a stale .git/index.lock, and stderr is drained off-thread to avoid a pipe deadlock.
    • File and directory names are sanitised before rendering (control characters → ?), so a verbatim -z filename can’t corrupt the sidebar layout or inject terminal escape sequences.
    • git_status_short now reads git status --porcelain -z --untracked-files=all: -uall expands an untracked directory into its individual files (git-ignored paths stay excluded), and --porcelain -z emits paths verbatim and NUL-delimited - so filenames with spaces, arrows, quotes, or non-ASCII bytes (and rename source/destination) parse unambiguously. The footer counts share the same -z parser, so a rename counts once and the total always matches the rows rendered.
  • Worktree table: label the issue/PR badge column (issue #294): the second table column (the ● / ● issue / PR pastilles) now carries an I/P header so the badges read self-explanatory next to the Worktree / Branch columns.
  • Added portable-pty 0.9 (cross-platform PTY pair) and tui-term 0.3 (ratatui widget rendering a vt100 parser buffer).

Historical delta: [0.10.0-rc.3] - 2026-06-17

Section titled “Historical delta: [0.10.0-rc.3] - 2026-06-17”

Delta against v0.10.0-rc.2. Merged PRs: #310, #311, #295.

The third 0.10.0 train closes the GitHub loop. Every worktree⇄GitHub feature so far was outbound-only (create mints a branch, pr opens a PR); this candidate adds the inbound half - gwm review <PR#> materialises an existing PR into an isolated worktree to review / test / fix - and ships the first real consumer of gwm daemon (issue #38): a compact gwm statusline one-liner for shell prompts, driven by the daemon’s subscribe stream. No breaking changes; the default text output of every command is unchanged.

  • gwm review <PR#> - materialise an existing PR into a worktree (issue #308). The inbound counterpart to gwm create: resolves the PR head via gh and fetches origin’s universal refs/pull/<N>/head ref - cross-fork aware, and valid for PRs in any state (open / draft / closed / merged) - into a local review/pr-<N>-<author>-<slug> branch, attaches a worktree, links the PR so the sidebar / CI indicator light up immediately, and points the diff base at the PR’s base ref (origin/<base>). Tear down with `gwm remove --delete-branch` like any worktree. `--name` overrides the branch. **Safe-by-default**: bootstrap and lifecycle hooks are *not* run, because a review worktree holds a contributor's (possibly fork) code and those steps execute commands against it (`npm install`, `composer install`, `direnv allow`, `post_create` hooks …) - i.e. arbitrary code; pass `--bootstrap` to opt in once you trust the PR. This closes the loop the rc.2 CI indicator (#299) opened - a failing PR can now be pulled into a worktree to act on. (The branch-level `gwm checkout ` / `gwm create --from` primitives noted in #308 are deferred to a follow-up.)
  • First daemon consumer - gwm statusline (issue #309): the first real consumer of the gwm daemon JSON-RPC surface (#38). A thin, dependency-free client that connects to the daemon socket and renders a compact one-line worktree summary for tmux / starship / zsh prompts - active branch, worktree count, dirty / ahead / behind, linked issue / PR. --watch rides the subscribe stream and reprints on every worktrees.changed push; without it, a single list round-trip prints once and exits. When no daemon is reachable it prints an empty line and exits 0, so a prompt substitution degrades to nothing instead of erroring - and the --watch stream emits a trailing blank when the daemon stops, so a long-running consumer clears its stale line rather than freezing on it. A detached HEAD falls back to the worktree name; a CI rollup is intentionally omitted (not part of the daemon’s stable schema). New docs/5.integrations/4.daemon-consumers.md (EN + FR) documents the statusline, the raw socat / nc protocol one-liner, and an editor recipe (Zed / VS Code). JsonWorktree / JsonStatus gained Deserialize so a client can decode the lines the server serialises.
  • Bumped regex 1.12.3 → 1.12.4 (#295).

Historical delta: [0.10.0-rc.4] - 2026-06-17

Section titled “Historical delta: [0.10.0-rc.4] - 2026-06-17”

Delta against v0.10.0-rc.3. Merged PRs: #314, #316.

The fourth 0.10.0 train adds the fleet-chore pair - two utility subcommands that act across the whole worktree set instead of one at a time - and brings the in-repo documentation (EN + docs/fr/) fully in line with the v0.10.0 surface. No breaking changes; the default text output of every command is unchanged.

  • gwm exec [<slug>...] -- <cmd> (issue #313) - run a command in each worktree, sequentially. Targets every non-main worktree by default, or the slugs listed before --; everything after -- is forwarded verbatim (flags and all). Prints a per-worktree ✓ / ✗ rollup and exits non-zero if any worktree’s command failed. A program containing a path separator (e.g. ./script) is anchored to each worktree so it runs that worktree’s own copy regardless of platform; bare names stay PATH lookups. No bootstrap trust gate - it’s the user’s own command against their own worktrees, distinct from the untrusted-.gwm.toml threat model (#95).
  • gwm clean [<slug>...] [--yes] (issue #313) - report (and with --yes reclaim) heavy build artifacts (target/, node_modules/, dist/, build/) across worktrees. Report-only by default. The safety gate deletes only directories git treats as ignored and that hold no tracked files, so a tracked or hand-authored dist/ / build/ is reported as skipped rather than destroyed; symlinks (entries and artifact roots) are never followed, so size accounting and deletion stay bounded to the worktree. The dry-run preview is classified through the same gate, so its total and its “re-run with --yes” promise match exactly what a deletion would remove. Deliberately not journaled into gwm history - the artifacts are regenerable.
  • Full documentation sync to the v0.10.0 codebase (issue #315), EN + the docs/fr/ mirror in lock-step: the CLI reference now documents gwm review (#308), gwm exec and gwm clean (#313); the TUI docs cover the Working Tree file-tree sidebar, the PR CI indicator, the v0.10 keymap redesign and the Settings Keys tab; configuration, integrations, getting-started and development pages were verified against src/ + examples/. ROADMAP.md records the rc.3 and post-rc.3 trains in Shipped highlights. The pass was strictly evidence-based - no command, flag, or feature is documented that is not in the codebase - and a completeness/parity critic confirmed every subcommand is covered with EN/FR parity.