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).
Upgrade notes
Section titled “Upgrade notes”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.
Stable-only delta after rc.4
Section titled “Stable-only delta after rc.4”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=jsonoutputs (list/doctor/path),gwm status --json, the daemon JSON-RPC protocol, and the.gwm.tomlsection 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-tightenedadditionalProperties. A newgwm::contractmodule is the single source of truth forSCHEMA_VERSION(the 1.0 baseline,1), the frozen daemon method / notification names, and the config section set. The daemon’sworktrees.changednotification now carriesparams.schema_versionso a long-livedsubscribeclient can detect a contract drift; the field is additive and ignorable. The output schemas useadditionalProperties: trueso an additive field validates under the same version (consumers ignore unknowns), while.gwm.tomlkeepsdeny_unknown_fields(input rejects typos). Eachdocs/schema/*.jsondeclares itsversion, and a newdocs/schema/README.mddocuments 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.tomlgains two opt-in sections so common fan-out invocations can be saved per repo instead of retyped.[exec.profiles.<name>]carries acommandargv array run viagwm exec --profile <name>;[clean.profiles.<name>]carries adirsset reclaimed viagwm clean --profile <name>. Both are now part of the frozen 1.0 contract (contract::CONFIG_SECTIONSgainsexec/clean). Frozen rules: an exec profile’scommandis an argv array run with no shell (a deliberate divergence from the string-shellcommandof[git_tui]/[review]); a clean profile’sdirsis a complete set that replaces - never adds to - the built-intarget/node_modules/dist/build;gwm cleanwithout--profileuses[clean.profiles.default]when present, else the built-ins; forexec,--profileand 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
--jobsparallelism forgwm exec(#324).gwm execgains a--jobs <n>flag and an[exec] jobsconfig default (with a per-profile[exec.profiles.<name>].jobsoverride). Precedence:--jobs>profile.jobs>[exec] jobs>1.1(or absent) keeps the unchanged sequential behaviour with live, inherited output;> 1runs 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 boundedstd::threadpool - no new dependency.jobsis a sub-field of the already-frozen[exec]section, so the 1.0 section set is unchanged. --workspacefan-out forgwm 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, forclean --yes, before anyremove_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).--profileresolves 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--workspacerefusal remains for commands that still don’t implement it.- TUI exec / clean overlays
(#325). The ratatui interface
gains two overlays over the worktree list:
xopens an exec picker that lists the[exec.profiles.*]names and, onEnter, runs the highlighted profile’scommandarray - with no shell - in the embedded PTY overlay rooted at the selected worktree;Xopens a clean overlay that previews the reclaimable build artifacts (gated by the exact git-ignored + no-tracked-files safety checkgwm clean --yesuses) 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/:cleanreach 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 ingwm exec/gwm clean(#313) were confirmed as deferred, additive features for the 1.0 pledge -execsequential by default (bounded--jobsnow opt-in, above),cleankeeping its built-in artifact set (the[clean]/[exec]profile config now additive under #324), and the cross-repo--workspacefan-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 thegwm switchpicker 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 moremarkers), a magnitude heatmap on reclaimable sizes, and an ecosystem-matched nerd-font icon per reclaimable directory.
Dependencies
Section titled “Dependencies”- Stability & compatibility policy for 1.0
(#318). A new
Stability
page (EN +
docs/fr/) is the explicit, published SemVer contract behind the1.0line: which surfaces are covered (CLI subcommands / flags, exit codes, the--format=jsonschemas, the daemon JSON-RPC protocol, the.gwm.tomlsection 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 bytests/contract_tests.rsfrom those covered by the written promise, and defers the per-field stable / experimental tiers todocs/schema/README.md. Linked from the README andCONTRIBUTING.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.tomloverride is surfaced rather than silently dropped. The read-only resolved config lives under theAlltab (#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 Treepane bottom-right footer breaks the changed-file tally into colour-coded nerdfont counts - created (green), modified (yellow), deleted (red) - derived fromgit 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] Statuspane now shows aDiff +<ins> -<del>line (insertions green, deletions red) for the branch versus its base trunk, using three-dotgit diff --shortstat <base>...HEADsemantics. 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_secscontrols periodic TUI worktree refreshes. Default is60s;0disables. Exposed in the Settings panel under the TUI tab (#285). - ✨ Project tooling ships a Flippad-style coloured
Makefileplus Zed tasks for the local Rust workflow (build,test,clippy,doctor,audit, worktree bootstrap, and related shortcuts).
Changed
Section titled “Changed”- 💄 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).
- 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
- 💄 Auto-detected PR (
gh pr list --head <branch>) is now persisted to a dedicatedbranch.<name>.gwm-pr-detectedgit-config key onFrefresh. 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 explicitgwm link --prstill wins; a vanished detection clears the stored key / title / state (#285). - 💄 Worktree table’s first
Createdcolumn and sidebar’sCreatedrow now use the local branch-creation timestamp recorded bygwm 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
123ortrueis 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 sogwm config setcan 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::addand 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 theubuntu-latest/macos-latest/windows-latestmatrix. 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
gwmand parse human output.--format=jsonongwm list,gwm doctor, andgwm path(gwm path/gwm doctoralso accept--format=text, the default). Each emits a stable, documented schema decoupled from gwm’s internal types - JSON Schema files live underdocs/schema/(worktree-list,doctor,path).gwm list --format=jsonincludes the main worktree (unlikenames);gwm doctor --format=jsonkeeps the conventional0/1/2process 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$TMPDIRthen/tmp; override with--socket). Exposeslist/doctor/pathrequest/response methods plussubscribe, which streamsworktrees.changednotifications (initial snapshot then one per change). Newline-delimited JSON. Change detection is interval polling (--poll-ms, default1000) 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-ondaemonCargo feature; on other platforms /--no-default-featuresbuilds the subcommand exits with an explanatory error (it stays listed so--helpis identical everywhere). No new runtime dependencies - the socket usesstd::os::unix::net.
- Config presets for
gwm init(issue #37):gwm init --preset <name>seeds an opinionated.gwm.tomlfor 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), andgeneric(the documented default).gwm init --list-presetsenumerates them with one-line descriptions, andgwm init --preset <name> --showprints 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 withexamples/presets/<name>.toml.gwm initwith 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 ~/Projectsopens the TUI over every direct-child repo, andgwm list --workspace ~/Projectsprints the merged worktree table. Both accept the flag before or after the subcommand (global = true).- Bare
gwmin a directory that is not itself a git repo but holds child repos promptsNo 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 createin workspace mode requires--repo <name>to disambiguate which child repo gets the new worktree; an absent or unknown name lists the candidates..gwm.tomlstays 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
lto open lazygit inside a ~90 % fullscreen embedded PTY overlay; pressLto open it fullscreen;o/Odo the same for a native$SHELLsession. Both overlays stay inside the TUI - no alternate screen swap.Esccloses the overlay;qinside lazygit quits lazygit and auto-closes. The keybindings (lazygit_pty,lazygit_fullscreen,terminal_pty,terminal_fullscreen) are fully rebindable in[tui.keys]. Powered byportable-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/9green,CI failing 7/9red,CI running 8/9yellow) is derived from thestatusCheckRollupalready 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 adefault/user/reposource 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 onEnter(Backspacedrops the last stroke); a single-stroke modal verb auto-commits on the first key;Esccancels.- 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,BackspaceandCtrl+Ccan’t be assigned via capture by design - hand-edit.gwm.tomlfor those. - New
config_cli::set_array_atarray write-back backs the persistence.
- The capture writes a TOML array to the layer the panel targets
(
- 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 (Enterissubmitin the create form butactivatein the delete-confirm modal). The dedicatedmodalnamespace keeps a context from colliding with a same-named global action (create/help/command_logs/link): a globalcreatearray 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 keyslists every context and verb;gwm doctorvalidates 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 contextualEsc/Enter, and the PTY overlay’s emergencyEscstay 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, enablingcd "$(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(wasS) →sync;D(wasp) →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 acommandstring and an optionalopen_infield ("pty"- default;"mux_pane"for a new tmux/zellij pane).
Changed
Section titled “Changed”- Working Tree pane as a file-explorer tree (issue #300): the Status
pane’s Working Tree section (
2) now rendersgit statusas a nested, nerd-font file tree instead of a flatXY PATHlist. Directories sort before files (alphabetical within a level) and single-child directory chains collapse (src/tui/thenui.rs); each file row carries an extension-driven file-type icon plus itsM/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 liketree(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 statusscan 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 morerow (… N+ morewhen 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-locksso 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-zfilename can’t corrupt the sidebar layout or inject terminal escape sequences. git_status_shortnow readsgit status --porcelain -z --untracked-files=all:-uallexpands an untracked directory into its individual files (git-ignored paths stay excluded), and--porcelain -zemits 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-zparser, so a rename counts once and the total always matches the rows rendered.
- Tree connector lines (
- Worktree table: label the issue/PR badge column (issue #294): the second
table column (the
●/●issue / PR pastilles) now carries anI/Pheader so the badges read self-explanatory next to theWorktree/Branchcolumns.
Dependencies
Section titled “Dependencies”- Added
portable-pty 0.9(cross-platform PTY pair) andtui-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 togwm create: resolves the PR head viaghand fetches origin’s universalrefs/pull/<N>/headref - cross-fork aware, and valid for PRs in any state (open / draft / closed / merged) - into a localreview/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 thegwm daemonJSON-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.--watchrides thesubscribestream and reprints on everyworktrees.changedpush; without it, a singlelistround-trip prints once and exits. When no daemon is reachable it prints an empty line and exits0, so a prompt substitution degrades to nothing instead of erroring - and the--watchstream 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). Newdocs/5.integrations/4.daemon-consumers.md(EN + FR) documents the statusline, the rawsocat/ncprotocol one-liner, and an editor recipe (Zed / VS Code).JsonWorktree/JsonStatusgainedDeserializeso a client can decode the lines the server serialises.
Dependencies
Section titled “Dependencies”- Bumped
regex1.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 stayPATHlookups. No bootstrap trust gate - it’s the user’s own command against their own worktrees, distinct from the untrusted-.gwm.tomlthreat model (#95).gwm clean [<slug>...] [--yes](issue #313) - report (and with--yesreclaim) 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-authoreddist//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 intogwm 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 documentsgwm review(#308),gwm execandgwm 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 againstsrc/+examples/.ROADMAP.mdrecords 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.