Skip to content

Latest commit

 

History

History
359 lines (278 loc) · 77.2 KB

ROADMAP.md

File metadata and controls

359 lines (278 loc) · 77.2 KB

GitWand — Roadmap

Full release details: CHANGELOG.md


What's Next

Ordered by priority, last verified 2026-10-10 (v3.12.1 shipped 2026-10-10 with the seventeen-plus PRs merged since v3.12.0, the v3.12.x merge-back fix included; the 2026-10-08 changelog scan inserted Agent Control, the worktree audit widened it into Agent Workspaces and added a v3.12.x merge-back fix; on 2026-10-10 Agent Workspaces was split in two, part I moved ahead of Stacked Branches as v3.13.0 — it completes the v3.12.x fix and unblocks Dendreo's teardown — and part II became v3.16.0, so Stacked Branches, Combined Diffs and Voice Input each moved one minor later). The thread: the measured-accuracy engine re-founds the trust every later auto-apply feature spends, then make the app reactive and fast (Live Repo), close the resolution loop (preview-to-apply, whose confidence threshold is only meaningful because of the accuracy work), then workflow & comparison primitives, experimental voice input, and the v4.0 code-intelligence headline. Full renumbering history: git log -p -- roadmap.md.

Version Codename Why now
v3.13.0 Agent Workspaces I — Lifecycle & merge-back Worktrees as provisioned environments (repo-defined setup/teardown hooks) and the real merge-back through preview→apply: the interim v3.12.1 fix refuses as soon as main moved, which is the normal case for a long agent task; Dendreo's bin/worktree shows what a real team needs
v3.14.0 Stacked Branches Native stacked PRs, sequenced after v3.11 (leans on preview→apply)
v3.15.0 Combined Diffs Multi-commit, non-contiguous aggregated diff
v3.16.0 Agent Workspaces II — Agents & parallel work Live agent status, in-app permission requests, agent picker, worktrees view, cross-worktree conflict prediction, merged-PR cleanup — GitKraken 12.x, VS Code 1.141 and Conductor shipped parts of it
v3.17.0 Voice Input Experimental — local dictation via embedded Whisper
v4.0.0 (candidate) Blast Radius Code-graph impact before merge — the code-intelligence headline

v3.12.4 (Windows build no longer needs the VC++ runtime), v3.12.3 (reset --keep, opt-in auto fast-forward, tracked-but-ignored warning, diffs that keep --/++ lines, file history compare across renames, PR comment actions, in-house Markdown, GPU rendering on Linux), v3.12.2 (AI context for PRs and release notes, AI branch creation, AI language and model fixes), v3.12.1 (merge-back no longer loses data, security hardening, full-screen Settings, WIP as a Git Tree row, per-project identity), v3.12.0 (built-in terminal renderer, WIP in the Git Tree), v3.11.2 (Finder-like folder navigation), v3.11.1 (History-aware LLM fallback) and v3.11.0 (Merge preview-to-apply) shipped; see Shipped below and the full detail in CHANGELOG.md.


v3.13.0 — Agent Workspaces I: lifecycle & merge-back

From the 2026-10-08 changelog scan and worktree audit. GitKraken 12.1→12.5 shows each agent session's live status, answers Claude Code / Codex / Copilot CLI permission requests from its panel and runs per-repo setup commands before an agent starts; VS Code 1.141 cleans up agent worktrees by disk use and merged PR; Conductor gives each workspace setup/archive scripts and a port range; Strand snapshots a worktree before removing it. Dendreo's own bin/worktree (~1,700 lines) shows the real need: a worktree is a running environment — its own containers, subdomain, tenant, test databases and reserved Vite port — that must be provisioned on create and torn down on delete. GitWand today creates and removes the git worktree only (WorktreeManager.vue, scratch.rs), launches Claude Code only, and then loses sight of the session.

Split on 2026-10-10: this part makes a worktree a provisioned environment and brings agent work back for real; the agent-facing half (status, permissions, parallel-work prediction) is v3.16.0 below.

Lifecycle hooks (the foundation) — a worktree section in .gitwandrc, so the repo, not GitWand, says how to bring an environment up and down:

worktree:
  dir: .claude/worktrees            # default stays configurable; Claude Code / Dendreo convention
  include: [.env, auth.json]        # or a .worktreeinclude file (Claude Code / Conductor / Strand)
  setup: bin/worktree provision {name}
  teardown: bin/worktree teardown {name}
  url: bin/worktree url {name}
  • setup runs after creation, streamed into a terminal tab; teardown runs before any removal (manual, merge-back, cleanup), and a failed teardown blocks the removal instead of orphaning containers, volumes and databases — what happens today when a Dendreo worktree is removed from GitWand
  • name, path, branch and base exported as GITWAND_WORKTREE_* variables; url output shown on the worktree card and openable
  • include copies ignored files only (same semantics as .worktreeinclude); symlink vs copy per entry, for agent config (settings.local.json, mcp.json) and shared dependency folders

Creation

  • Base on the freshly fetched remote default branch by default (Claude Code, Dendreo, Conductor), not the local HEAD as AI tasks do today

Bringing work back

  • Merge-back becomes a real merge or rebase through the v3.11 preview → apply flow (completing the v3.12.1 interim fix; the agent's terminal processes are stopped first — on Windows too, where v3.12.1 only kills the leader, and including a shell's background jobs, setsid processes and a foreground job whose leader already exited, which survive terminal_close today): conflicts previewed, auto-resolved by the engine, agent commits kept, snapshot taken

Removal

  • Snapshot before removal (v3.8 Time Machine), restorable as a new worktree (Strand)
  • Never touch a worktree that is locked, marked .worktree-keep (Dendreo's guard against Claude Desktop's cleaner), or owned by another orchestrator

v3.14.0 — Stacked Branches (native)

A differentiating feature: stacked PRs workflow without an external CLI (Graphite, ghstack…). Sequenced after v3.11.0 on purpose: Restack leans on the conflict preview → apply flow.

The paradigm: short stacked branches (feat/step-1 → feat/step-2 → feat/step-3), each with its own PR targeting the previous one.

Visualization — The DAG automatically identifies stacks; a "Stack" banner in the sidebar; a "Stacks" tab in Today

Creation — "Stack a branch" button in the context menu; ⌘⇧S shortcut from the commit area

Restack — Automatic detection when the base has moved; one-click "Restack" button (cascading git rebase --onto); conflict preview before execution (v3.11.0 preview-to-apply)

PRs — "Submit stack": creates or updates GitHub PRs for each layer; automatic retarget when a layer is merged

Merged-PR detection (from the 2026-10-08 changelog scan, Tower 17 / Windows 14) — "is this layer merged?" cannot rely on git_branch_merged (read.rs, git branch --merged): a squash- or rebase-merged PR leaves no ancestry, so the layer is never seen as merged and the retarget never fires. Ask the forge (merged PR whose head is this branch), fall back to a patch-id comparison against the target (git cherry). The same signal feeds the v2.12 Archived Branches: a "merged" hint with a one-click Archive on branches whose PR is merged

Stale-head guard (from the same scan, Conductor 0.89) — a layer is merged only if the PR's head is still the commit reviewed locally: pass the expected sha to the forge merge endpoint (rest_merge_pr sends only merge_method today; GitHub refuses with 409 on mismatch, GitLab has the same parameter), and say so instead of merging commits nobody looked at. Applies to every in-app PR merge, not only stacks

Implementation — Metadata in .gitwand-workspace.json; no external CLI dependency. Cascading Restack and per-layer Submit-stack progress stream via tauri::ipc::Channel (v3.10.0 pattern) rather than a new global emit() broadcast


v3.15.0 — Combined Diffs (multi-commit, non-contiguous)

Inspired by GitBlade. A comparison primitive we lack: one aggregated diff across several commits, even non-consecutive — review scattered work as a single change.

Today's baseline — getGitFileDiff(from, to) and folderDiff(refA, refB) compare exactly two points; CommitGraph.vue is single-select; file history / split commit / fork point don't cover "these 3 commits together".

  • Multi-select in the Git Tree — ⌘-click / ⇧-click commit selection, selection chip ("3 commits selected → Combined diff")
  • combined_diff Tauri command — Rust-side aggregation of the selected commits' patches into one virtual diff (per-file hunk merge, conflict-free since same-history)
  • Combined viewer — standard DiffViewer rendering + per-hunk commit attribution (gutter badge → jump to commit)
  • Entry points — Git Tree context menu, file history ("combine these versions"), PR review (subset of commits)
  • Optional AI summary — "what these N commits do together" (what/why/affected areas) via useAIProvider, reusing the v3.5.0 PR-summary prompt

v3.16.0 — Agent Workspaces II: agents & parallel work

Second half of Agent Workspaces (split 2026-10-10), on top of the v3.13.0 lifecycle and merge-back. Sequenced after Stacked Branches (v3.14.0), whose merged-PR detection drives the cleanup below.

Creation

  • Start from a branch, a remote branch, a PR (pull/<n>/head) or a Launchpad issue (GitKraken 12.4): branch named after it, issue body as the starting prompt
  • Agent picker (Claude Code, Codex, Gemini, opencode… — the providers GitWand already knows), not Claude Code hard-wired

Visibility

  • A worktrees view, sortable and filterable, replacing the modal: branch, dirty count, ahead/behind, last activity, disk use, PR state, env URL, agent status
  • One WIP row per dirty worktree in the Git Tree (GitKraken 12.3), building on the #224 WIP-as-Git-Tree-entry work
  • Recognise worktrees created by other tools (.claude/worktrees/, Conductor, Superset…) and identify an agent session by its process, not by the presence of a .claude/ folder — detect_agent_tool flags every worktree of a repo that commits .claude/, GitWand's own included

Agent status

  • Live status — per session: running, waiting for input, idle, exited. Baseline with no integration: PTY output activity + process state (works for any CLI); richer states from each CLI's own hook mechanism where it has one, starting with Claude Code hooks. Shown on terminal tabs, in the worktrees view and as an OS notification when a background agent starts waiting
  • Permission requests in-app — when the CLI exposes it (Claude Code hooks first), surface the pending tool call with the exact command, Allow / Deny from the panel. Never auto-allow; an unanswered request stays pending in the terminal exactly as without GitWand

Parallel work — where the engine pays off

  • Cross-worktree conflict prediction — run the Conflict Predictor between parallel tasks and against the target before anything lands: "task A and task B will conflict on useRepo.ts, 3 hunks, 2 auto-resolvable". Strand only warns that two worktrees touch the same files; nobody predicts the actual conflicts. The headline of this release
  • Compare two attempts at the same task side by side, keep one (Strand)

Cleanup

  • git worktree lock while an agent runs (Claude Code does the same), unlock when it exits
  • Clean up once the PR is merged (v3.14 merged-PR detection) or after N days inactive, single or batch (Dendreo's clean --merged), always through teardown

v3.17.0 — Voice Input (experimental)

  • Local dictation: microphone button in the commit panel — transcription via embedded Whisper (whisper-rs Rust) — zero cloud
  • Optional AI enrichment: pass dictated text through useAIProvider for conventional commit formatting
  • Models: tiny or base downloaded on demand, stored locally
  • Multilingual: Whisper auto-detects the language
  • Graceful fallback: clear message if microphone access is denied by macOS TCC

v4.0.0 (candidate) — Blast Radius: code-graph impact before merge

Inspired by Snipara's project-intelligence layer. Before a merge/rebase, answer: "what does this operation risk breaking?" — the natural extension of Conflict Predictor + postMergeRisk (v2.4.1), and a headline differentiator. The same graph also answers the question one step later: "did it actually break something a text merge couldn't see?"

Today's baseline — packages/core already embeds tree-sitter (TS/JS/Python/Go/Rust WASM grammars), an ES/CJS import parser (resolvers/imports.ts) and parse-tree validation (validate-parse-tree.ts), but no dependency graph, caller discovery, or test mapping.

  • Early exit before parsing — git diff --name-status on the two branches first: if every path is either newly added with no import/require line referencing a symbol the other side changed, or matches an asset/doc extension (.css, .png, .md, …), the engine declares no possible semantic collision and returns without loading tree-sitter. Same spirit as .gitwandrc's generatedFiles skip. Cheap, not literally free — an added file's imports still get scanned against the other side's changed-symbol list, since a new file can call into a renamed export it never touched in the diff
  • Import graph — packages/core/src/codeanalysis/: tree-sitter queries build the module adjacency graph (browser-safe, incremental). Cached locally, content-addressed by blob SHA (git's own object model, no external index format): a file's parsed edges are only recomputed when its blob changes, so re-running against an unchanged main costs nothing. Considered and dropped: downloading a prebuilt LSIF/SCIP index from CI — real repos rarely have one, and it would pull in exactly the cloud/infra dependency the local-first positioning avoids elsewhere on this page
  • Reverse dependencies — for each file touched by the operation: who imports it, which exported symbols changed
  • Shallow parsing on dependents — full AST only for the files a branch actually changed; on unmodified files reached through the reverse-dependency edges, tree-sitter queries pull import declarations and call expressions only, function bodies/loops/local variables are never walked unless the file itself was touched. Keeps the cost proportional to the blast radius, not to the repo
  • Silent conflict detection (detect_silent_conflict) — the case git's text merge never flags because the two sides touched different files: branch A renames a symbol or changes its signature, branch B keeps calling the old shape somewhere the line-level diff never intersects. Runs the same import graph against the merge's actual result (local git merge --no-commit --no-ff, zero side effects, same discipline as gitwand_preview_merge) instead of the pre-merge diff. A scored pattern registry (renamed_export_vs_import, signature_change_vs_unchanged_call, deleted_variable_vs_scoped_reference) reports a traced collision — files_involved, confidence, a trace built only from real symbol/line names, never a paraphrase — and never auto-fixes it. Mirrors the text engine's own rule (a complex hunk is never silently applied, v3.9.0) one layer up, at the symbol level instead of the line level
  • Probable-test detection — heuristic mapping (*.test.* / *.spec.* naming + import edges) → "these 12 tests likely cover the changed code"
  • Co-change analysis — "these files historically change together" mined from local git log (zero cloud, cheap); a second impact signal complementing the static import graph, exactly the history hop Greptile does server-side
  • Blast Radius panel — new tab in MergePreviewPanel: impacted files ranked, affected symbols, suggested test scope; feeds a blastRadius dimension alongside postMergeRisk
  • Review ordering — blast radius reused in the PR review (v3.5.0): files ranked by impact, "start with these 2 files"
  • Feedback loop — rejected impact predictions / auto-resolutions lower the pattern's confidence (extends useResolutionMemory), the local analog of Greptile v4's false-positive reduction; the Engine Accuracy release's lot F (derive the repo's conventions by replaying its own history) is the active, measured form of the same idea — the two should share one store
  • Agents too — exposed via @gitwand/mcp (gitwand_blast_radius, detect_silent_conflict) and CLI only, never the /agent WebMCP page, which by design never touches a real repository or its history. Positioning: Greptile sells this as a paid API ("Genius API", $0.45/req) — ours is local, free, open source
  • Package-graph pre-filter (optional) — when the repo already has an Nx, Turborepo or Bazel project graph, use it as a coarse first pass: if main's changed package isn't a dependency of the PR's changed package, declare a pass without loading tree-sitter at all. Falls back to the pnpm-workspace.yaml/package.json workspace graph GitWand already reads when none of the three is present, so this works the same on GitWand's own repo (plain pnpm workspaces, no Nx/Turborepo/Bazel) as anywhere else. Package-level only — two files inside the same package still go through the full reverse-dependency graph, since that's where renamed_export_vs_import actually lives
  • CI/CD gate — detect_silent_conflict doubles as a CLI check (gitwand check-semantic, packages/cli), runnable as a GitHub Actions / GitLab CI job against a PR's would-be merge (fetch base + head, no working-tree side effects). Ships advisory first — inline PR annotations — following the gitwand scan precedent (v3.5.0: non-blocking badge, opt-in pre-commit hook before anything blocked); becomes a hard-blocking gate only once its false-positive rate is measured and cleared, the same discipline that kept --regenerate CLI-only at 38.5% agreement against an 80% bar (Engine Accuracy, v3.9.0). benchmark-gate.yml is the existing precedent for a hard block already living in this repo's own CI
  • Opt-in & lazy — computed post-preview, never blocking the merge flow; enabled in Settings

For reflection — competitive scan (GitUp · Aurees · Snipara · Strand · GitComet · RelaGit)

Competitive scan from 2026-06-24 across 6 clients/tools (Snipara, GitDriv, GitUp, GitX-dev, Aurees, GitBlade), updated 2026-07-20. High-signal leads were promoted into the versioned sections above after a code audit — PR Review 2.0 (inspired by Greptile) → v3.5.0 (shipped), Commit Review (inspired by git-lrc) → v3.7.0 (shipped), global snapshots/undo → v3.8.0, Live Map + libgit2 phase 1 → v3.10.0, editable diff + merge preview-to-apply → v3.11.0, Combined Diffs → v3.15.0, code graph/blast radius → v4.0.0 (candidate). Discarded leads (GitDriv = beginner web drag-and-drop, GitX-dev = near-dead fork, GitBlade = parity only, abandoned since 2019) bring nothing advanced.

2026-07-09 scan — three serious new competitors (all post-dating v2.15.0), now folded into the Competitive landscape table above: Strand (strand/0.5.0, agent workspaces via worktrees), GitComet (gitcomet/0.1.15, pure Rust+GPUI perf), RelaGit (relagit/0.16, design/SolidJS).

Synthesis: none of the three addresses structured conflict-resolution AI (Strand = agent workspaces, GitComet = perf, RelaGit = design) — GitWand's moat (auto-resolve + multi-repo Launchpad + extensible CLI/MCP) stays intact. Worth cultivating: the v3.8–v3.11 pipeline (preview-to-apply) + v4.0 code graph to widen the gap. Worth borrowing from their respective strengths: published a11y/perf baselines (Strand, → v3.10 benchmark pass), SolidJS vs Vue 3 benchmark on heavy diffs (RelaGit, → v3.10 perf pass).

2026-10-08 scan — Multi-Git (AnthonyKopri/multi-git, MIT, Electron/Node): multi-account SSH, safety net, coding-agent launcher, JSON CLI + MCP. No conflict AI (ours/theirs/manual only). Most of its safety layer is already covered: Recovery Points / Recently Discarded ≈ Time Machine (v3.8.0), "behind upstream" fast-forward ≈ v3.6.0, MCP dry_run + structured refusals ≈ design principle 6. Two leads kept, in Later (unscheduled): SSH routing on identity profiles and opt-in auto fast-forward after fetch. Discarded: passphrase vault (the system agent/keychain does the job), parity features (bisect, notes, LFS, patches).

2026-10-08 changelog scan — April→October release notes of GitKraken, GitButler, Tower, Fork, Sublime Merge, GitHub Desktop, Strand, GitComet, RelaGit, GitSquid, plus Zed, VS Code, lazygit, Conductor, Nimbalyst and the jj GUIs. Promoted: Agent Control → Agent Workspaces after the worktree audit (split on 2026-10-10 into v3.13.0 and v3.16.0); merged-PR detection and stale-head merge guard → Stacked Branches (v3.14.0). Gitoryx (gitoryx.com, v1.0.1, 2026-10-06) added after the scan: only gaps worth taking are guided bisect and the tracked-but-ignored warning (both in Later); sprint view, GitFlow and gitmoji discarded, changelog generation ≈ our tag-triggered release notes. Already covered or planned: cherry-pick/revert conflict indicator (Fork 2.66 ≈ Conflict Predictor v2.20), combined diff (Tower 14.1 ≈ v3.15), stacked PRs (GitButler 0.22, VS Code ≈ v3.14), Forgejo, file history, pickaxe search. Moat alert: GitButler 0.21 ships AI-assisted conflict resolution and but resolve (0.22), Gitoryx an auto-resolve "wand" for identical blocks (0.0.31) and AI conflict resolution (0.0.42), IntelliJ 2026.2 a "streamlined conflict resolution flow" — "nobody else does conflict AI" no longer holds for GitButler; the measured-accuracy benchmark (v3.9) is the answer to keep forward.

Still watching:

  • Per-hunk commit attribution for parallel agents (Nimbalyst 0.75) — when several sessions edit the same file, each commits only its own hunks. Interesting once Agent Workspaces (v3.16) knows which session wrote what; speculative before.
  • GitUpKit (gitup.co) — their SDK for building Git clients, worth studying.
  • libgit2 phases 3-4 — migrate git_log/git_show (revwalk, the real win on 40k commits — but the object-fetch loop needs optimizing first) then git_file_log (--follow/rename tracking to reimplement). To schedule once phases 1-2 (v3.10/v3.11) are validated. gix as an alternative to be re-evaluated at that point.
  • libgit2 for list_repo_tree (candidate, 2026-10-01) — the File Explorer panel's one-shot tree is git ls-files --cached --others --exclude-standard, capped at 20,000 entries. It could read the index directly and classify untracked entries with is_path_ignored, the way v3.11.2's list_repo_dir does (66 ms for a 6,000-entry directory against 1.6 s with git check-ignore). Next step: retire list_repo_tree (no frontend caller since v3.11.2, when the panel moved onto useLazyRepoTree) or migrate it to libgit2 if a caller returns. Same rule as every libgit2 migration: measure first, keep the CLI fallback, cover it with parity tests. libgit2 stays off anything that runs filters, hooks or external config (LFS, signing, credentials), off writes, and off algorithms it implements differently (blame, histogram/patience diffs).
  • Verification Plans attached to handoffs (Snipara) — every PR/change carries the checks it must pass; overlaps with the CI annotations (v2.18.0).
  • Greptile (greptile.com) — largely absorbed into the plan (2026-07-02): multi-hop pre-review + confidence scores → v3.5.0 (shipped), hot index → v3.10.0, LLM-fallback historical context → v3.11.0, local code graph + co-change + feedback loop → v4.0.0. Still watching: their public AI-reviewer benchmark (reusable for the v3.5.0 benchmark work) and how the Genius API evolves.
  • git-lrc / LiveReview (HexmosTech) — concept absorbed in v3.7.0 (Commit Review). Still watching: their LiveReview team offering (dashboards, org policies, review analytics) — if the GitWand-Review trailer catches on, a cross-repo rollup in Today/Dashboard would be the local equivalent.
  • FinderGit — UX worth borrowing (file-tree first), macOS-only today; the Finder-like sidebar concept has been promoted to v3.11.0. Cross-platform via Tauri is a structural advantage over FinderGit's solo-dev status.

Later (unscheduled)

  • Follow-ups from the #234–#239 reviews (2026-10-09):

    • explicit force pushes (reset, rebase, undo, the Force Push menu item) still use a bare --force-with-lease, which the 30 s background fetch defeats — pass the expected sha as the #239 auto path does
    • #239 treats a pull later undone by a local reset as a local rewrite (the collaborator's commit was once a local tip), so Force Push is offered and would drop it; and with push.default=upstream + a differently named upstream the auto force push can never succeed — judge against @{push} and lease that ref
    • #234: on Windows, gh/glab receive the PR body on the command line (≈32K limit) — send JSON on stdin (--input -); a background revalidation racing a save can briefly show the old title/body
    • #237: the Rust model-listing commands (codex debug models, copilot help config, agy models, opencode) have no process timeout of their own (the frontend gives up after 30 s, the child lingers)
  • Follow-ups from #244 (security hardening) (2026-10-09, updated after its review rounds on 2026-10-10):

    • Copilot is unverified (not installed when the follow-ups were written): its run directory, stdin support and lockdown; Antigravity (agy 1.0.13) still gets the prompt on argv, and its tools are not restricted
    • the user's own MCP servers still load for Codex and opencode (no confirmed switch: -c 'mcp_servers={}' does not remove them)
    • ai_http_request with auth: "none" (Ollama) still reaches any http(s) URL through the backend — limit it to the configured Ollama URL
    • Windows: a grandchild of the claude --help probe can outlive it once the direct child has exited (needs a Job Object)
    • Claude Code still creates one empty ~/.claude/projects/<run-dir>/ folder per run (no flag avoids it; --no-session-persistence already drops the transcript)
    • the ai-runs sweep (24 h, at base setup) could remove a run directory still in use by a run older than that in another GitWand process
    • flaky tests seen on 2026-10-10: pullAutostash.git.test.ts cleanup (rmSync hits ENOTEMPTY on .git, retry it), merge_back_without_a_recorded_base_still_works under full-suite load
    • an XSS in the webview still drives every IPC command: scope commands per window/capability, and give read_file/write_file a registry of repositories the user opened rather than the .git-ancestor check (a dotfiles repo at $HOME passes it)
    • img-src stays https: http: for self-hosted forge avatars — proxy or allowlist avatar hosts, then tighten it
    • parity-probe dispatch entries for read_commit_template and ai_http_request (none auth against a local fixture server)
    • usePrPanel-cli-missing.test.ts fails on a machine whose locale is not English (asserts the English timeout string) — pin the locale in the test
  • SHA-256 / reftable repositories (2026-10-08 scan: GitButler 0.19.10, Sublime Merge 2130, Zed) — git handles them, but a few GitWand parsers assume 40-hex ids (git/libgit2.rs:754, dev-server.mjs:4165). Audit every such assumption and add a SHA-256 fixture repo to the parity tests.

  • Guided bisect (Gitoryx) — bisect exists only as an in-progress operation GitWand can abort (ops.rs). Add a start flow (pick good/bad from the Git Tree), Good / Bad / Skip on the current commit, remaining-steps counter, culprit commit opened at the end; optional bisect run with a user command.

  • Per-project identity everywhere (from the #246 review) — the project's identity (commitIdentityFor) reaches plain commits and custom automations only; amend, split, --no-ff merge, revert and cherry-pick still use git's config, so the committer (and for merge/revert/cherry-pick the author) can differ inside one project. Route every commit-creating command through it. Also key identityOverrideByRepo on a canonical path (case-folded on case-insensitive filesystems, worktrees resolved to their main repo), so the same project opened through another spelling or a linked worktree keeps its identity

  • SSH routing on identity profiles + wrong-account guard (from the 2026-10-08 Multi-Git scan) — the v2.12 profiles (useIdentity.ts) only inject user.name/user.email at commit time; authentication still goes through the global SSH config. Add an optional SSH key per profile, routed per operation via GIT_SSH_COMMAND (fetch/pull/push/clone), auto-select rules on the origin URL (github.com/acme/ → Pro), and a pre-push check: the account the key actually signs in as (ssh -T, remembered per key) vs. the one the remote expects; on mismatch, block with an explicit override, force-push included. Real pain for anyone juggling work and personal accounts, and author + key always switch together, so a repo can no longer push as one account and commit as another.

  • Follow-ups from #260–#265 (2026-10-14):

    • #262: PR reads (detail, review threads, comments, reviews) and comment/review writes still resolve the PR via get_pr_json, origin first — on a fork with a same-numbered PR they act on the fork's PR. Moving get_pr_json itself to the base repo fixes every caller at once
    • #262: the tokenless merge (gh pr merge, gh_merge_pr_inner) passes no --repo, unlike gh pr ready
    • #265: a bisect in progress is invisible to the status, so the tooltip shows it only after a fast-forward attempt; a stale block reason can linger up to one fetch tick (30 s); a branch literally named HEAD or unknown is treated as detached
    • #264: git_untrack_paths needs git ≥ 2.25 (--pathspec-from-file)
    • #263: the fr/es/pt-BR/zh-CN strings for the Keep mode were not read by a native speaker
  • Follow-ups from #258 (command registry covers the forge wrappers) (2026-10-14):

    • on a fork, dev-server /api/gh-pr-comment (POST, PATCH, DELETE) targets origin via getRepoNwo, while the Rust commands resolve the PR elsewhere; the PATCH and DELETE web branches of ghPrUpdateComment / ghPrDeleteComment do not even send the PR number. dev:web QA of review-comment edits on a fork is not representative
    • 97 forge commands are registered as GAP: (Azure DevOps and Bitbucket PRs, GitLab MRs beyond auto-merge and issues, Gitea beyond the 8 read routes, and some GitHub PR actions, reactions and auth flows) — dev:web cannot exercise them
  • Follow-ups from #269–#270 (file history compare, diff parsers) (2026-10-14):

    • a file history entry outside the loaded history (line-range result, rebased commit) has no known name before a rename; the Compare tab says so instead of guessing — load more history, or have git log -L results carry names
    • CRLF: Rust strips \r from diff line content, the dev-server keeps it (also true of git_diff)
    • file status (added/deleted/renamed) is still derived in several places with different coverage (parse_diff_hunks, parse_multi_file_diff, devParseDiffHunks, the dev-server git-show loop)
    • combined @@@ hunk header numbers differ (Rust old 1,1 / new 0,1; core and the dev-server 0,1,0,1), and isPureMove on a combined hunk
    • strict hunk counts cut a hunk whose header undercounts its body; no forge path in the app sends such diffs today
  • Follow-ups from #257 (GPU-first rendering on Linux) (2026-10-13):

    • the software fallback is untested on the setups it is for: only the #135 (Ubuntu 26.04, native Wayland) and #139 (Mint 22 .deb) reporters can confirm that the second launch recovers. Ask them once it ships
    • the first launch that hits the EGL abort still shows nothing; only the next one switches to software. A launch that hangs without aborting is not detected
    • remove the shim (commands/render_fallback.rs, its two commands and the Settings row) once the EGL abort is no longer reported. It is not tied to a build host: #135 was on 26.04
  • Move the Linux build host to ubuntu-24.04 (around April 2027, when 22.04 leaves standard support) — release and bundle builds run on ubuntu-22.04 so the .deb/AppImage keep working on glibc 2.35 (22.04, Mint 21.x, Debian 12). Moving drops those systems, so announce it one release ahead.

  • Test the log view epoch (follow-up to v3.12.0, #214) — the filter/scope change that drops in-flight log pages and the forced-reload depth (forcedReloadDepth) have no test; a useGitRepo test for "filter change while a page is in flight" would lock them in.

  • Re-list loaded folders without the watcher (follow-up to v3.11.2) — the File Explorer panel re-lists a loaded folder only on a watcher event. With Live Repo off, or with the watcher unhealthy (network mounts, for instance), new and deleted files never appear in a folder already loaded, while the folder badges, fed by status polling, do change, so the tree and its badges disagree. Add a Refresh action, or re-list the loaded folders whenever the repoFiles path set changes and the watcher is not healthy.

  • Snapshot rebase/cherry-pick state — v3.8 restores MERGE_HEAD but not .git/rebase-merge/ or .git/sequencer/, so restoring a snapshot taken mid-rebase or mid-cherry-pick brings the files and index stages back without the in-progress sequence. Restoring those is a directory copy rather than a plumbing call, which is why it was left out of the first pass. Revisit if users report rewinding mid-rebase.

  • Snapshot cost on very large working trees — each snapshot runs git add -A into a scratch index, which is O(worktree) on a cold cache. Fine on normal repos, unmeasured on a 100k-file monorepo. Benchmark alongside the v3.10 FS-watcher work, where the same walk gains a second consumer.

  • Snapshot refs are visible to a bare git log --all — GitWand excludes them from every traversal it runs, but any ref under refs/ is by definition part of --all, so a user typing it in a terminal sees snapshot commits, exactly as they see refs/stash. Nothing to fix short of abandoning refs entirely (which would let gc eat the snapshots); documented here so it is a known property rather than a surprise.

  • libgit2 phase 2: stage/unstage (moved out of v3.11.0, 2026-09-14, measured and declined): the plan was index-level git2 staging behind a CLI fallback, mirroring the v3.10 git_diff migration. Measured before building, and the numbers say not to. Perf: the win is a flat ~15 ms, which is the subprocess spawn and nothing else, because both paths pay the same hashing cost. git add against libgit2, median of 7 runs: 1 file 17.1 vs 1.8 ms, 100 files 79.7 vs 64.1, 1000 files 926.7 vs 874.7, 5000 files 4997 vs 4487. Staging is batched (one call for N paths), so that 15 ms is per user action, and every stageFiles is followed by a refresh() whose git status alone costs 20 ms on a 1000-file repo and 31 ms on 5000. The saving is smaller than the refresh that immediately follows it. Correctness: 8 of 9 scenarios write a byte-identical index (modified, untracked, deleted, CRLF under text=auto + core.autocrlf, exec bit, symlink, conflicted-resolve, and unstage via reset_default). The ninth diverges: libgit2 implements the built-in CRLF filter but executes no external filter.<name>.clean process, which is exactly the Git LFS mechanism. A probe with a filter rewriting SECRET to REDACTED had the CLI store value=REDACTED and libgit2 store value=SECRET; on an LFS repo that is the raw binary in the index instead of the pointer, and git then reports the file as AM rather than A, so it reads as "still modified" rather than as corruption. A guard is possible (repo.get_attr(path, "filter") to detect filtered paths and defer to the CLI), but a fast path plus a detector plus a fallback plus parity coverage, all for 15 ms, does not pay for itself. Revisit only if staging latency becomes a real complaint, in which case the measurement points at the post-action refresh() rather than at git add, and the v3.10 watcher is already the infrastructure for that.

  • libgit2 blame (moved out of v3.11.0, 2026-09-14, because it cannot be completed on demand): git_blame's fast path was written, tested and then left disabled in v3.10.0. blame_attribution_matches_the_cli_on_a_moved_block exposed a git-version-dependent attribution divergence on a moved block between libgit2's bundled Myers xdiff and the CLI's histogram blame: green against git 2.50.1, red against 2.55.0. This is a disagreement between two algorithms, not an unfinished task, so it has no estimate and no owner action short of resolving the divergence upstream or reimplementing the attribution. Blame attribution is user-visible, so the CLI stays authoritative. libgit2_blame and its tests stay in tree as the regression guard; re-enabling it means resolving the divergence first, not deleting the test.

  • Linux inotify validation (moved out of v3.11.0, 2026-09-14, same reason): the v3.10 watcher registers inotify watches across the working tree, and registration cost on a node_modules-sized checkout was never measured on real Linux hardware, the work having been done on macOS where FSEvents has a different cost model. It is a measurement, not a change: the outcome may be "nothing to do" or "the watcher needs rework", which is precisely why it cannot sit on a release's critical path. Needs doing before the watcher is leaned on any harder, and before the v4.0 indexer becomes its second consumer.

  • Rebase preview loses commit provenance (deferred from v3.11.0 lot A1): preview_rebase replays each commit of the stack separately, then deduplicates the results per file keeping the strongest conflict signal (read.rs, the by_file fold). Which replayed commit actually produced a given conflict is discarded in that fold, so the panel cannot say "this conflicts at commit 3 of 5", and a future per-commit "stop here" apply cannot be driven from the payload. Fixing it means a new field on the serialized FileMergePreview, which ripples into the dev-server route and the parity normalization, so it was left out of the release that added the routes. The scratch-file race and the missing -L labels in the same function were fixed; this one is purely an enrichment.

  • Multi-forge PR-freshness signal parity — follow-up to the branch-badge background-prefetch/cache work (PR #125): GitLab/Bitbucket/Azure already get the breadth fix (background drain past the first page), but not the cheap freshness-signal instant-cache-restore fast path — GitHub-only today, since the other three don't yet have an equivalent cheap "most-recently-updated PR" query built. Deferred until there's real non-GitHub usage pressure.

  • Cursor-based PR-list pagination (Rust) — already flagged in-code as Phase 2/v2.9 (gh_list_prs_inner/rest_list_prs comments, predates PR #125): replace the naive offset+limit re-fetch, which re-walks from the start on every page, with a cursor-based gh api graphql query. Removes the quadratic re-fetch cost for repos with very large open-PR counts; most repos stay well under the current 300-PR prefetch ceiling, so this is scalability hardening, not an urgent fix.

  • Commit Review "Fix with agent" in a scratch worktree — follow-up to v3.7.0: the originally-planned "optionally in an AI-task scratch worktree" variant was cut after manual QA against real claude/codex CLIs found a brand-new scratch worktree always hits a first-run "trust this directory?" onboarding screen that misinterprets the piped prompt as menu navigation (drove a real brew upgrade --cask codex in testing). Revisit once there's a real fix — pre-trusting the directory before launching the agent, or detecting the onboarding screen before writing.

  • Decide the fate of the explainOnly option (follow-up to the v3.7.2 predictor fix): it short-circuits resolveHunk() before the format-aware dispatch and the confidence gate, so any caller that reads stats.autoResolved after using it gets a structural 0. That is exactly how gitwand preview and two MCP tools shipped broken. After the fix the option has zero consumers in the monorepo while staying part of the public GitWandOptions contract, so it is now a footgun with no user. Either remove it (breaking change for external consumers, if any) or redefine it as "classify and resolve, but do not assemble merged content", which is what every call site actually wanted.

  • Let an in-flight AI call survive a hunk renumbering (deferred from the issue #196 work): confirming one hunk renumbers every later one, and the queue's answer to that is to keep its settled suggestions (renumbered) and discard whatever is still running, because a run captured its index in its closure when it was dispatched. Keeping those runs alive means giving each one a token the queue resolves to an index at write time, so a renumbering rewrites the mapping rather than invalidating the work. Worth doing only if batches get slow enough that discarding a few in-flight calls is felt.

  • Hard cancel for an in-flight AI call (deferred from the issue #196 work): cancelling a hunk or a batch marks the entries idle and discards late results, but an already-spawned claude -p keeps running to completion. Killing it needs a Rust command holding the process handle plus a way to address it from the frontend, which is its own piece of work.

  • Manual pass over the AI hunk queue in the packaged app (outstanding from the issue #196 work). The UI half is done: a run against the real claude CLI under pnpm dev:web (4 complex hunks, one file) watched the batch stage 4 answers, confirmed one hunk and saw the other 3 survive renumbered onto the right hunks, saw a rerun re-buy nothing, and saw a cancelled call's late answer land nowhere. What is left is the responsiveness half, and it cannot be checked under dev:web: dev-server.mjs spawns the provider with spawnSync, so it blocks its own single thread for the whole call (measured: an unrelated API request waited 10.1s; the 4-hunk batch took 79s as four serialized calls, never 3 concurrent). The dev-server therefore shows the opposite of what the Rust spawn_blocking change fixes. The mechanism itself is now pinned by a Rust regression test (commands::ai::tests): three AI commands are put in flight on a deliberately single-worker runtime and a 50ms timer still fires in 50ms, where the same test measured 3.2s before the spawn_blocking change. What is left is therefore only the human half, in the packaged app: that the window keeps painting and the progress and partial-failure lines read correctly while a real batch runs.

  • Commit Review coverage on a content-only restage — v3.7.0's staged-set watcher fingerprints staged file paths + statuses, not content, so editing an already-staged file's content without changing which files are staged doesn't retrigger a coverage/finding recompute automatically (the pre-commit gate still recomputes coverage honestly right before the trailer is written, so the record itself stays accurate — this is a UI-staleness gap between review passes, not a data-integrity one).

  • Retire the frontend's "default to GitHub" forge fallback (follow-up to the v3.7.3 self-hosted-GitLab fix, #168): useForge.ts's getProviderByUrl/usePrPanel.ts's pre-resolution forge computed still assume githubProvider whenever detection hasn't resolved yet (no remote, dev:web mode, or a genuinely unrecognized forge) — a deliberate, documented backward-compat default, not an oversight. The Rust-side detection is now forge-agnostic end to end (URL match → glab/gh auth status --hostname probe), so the one remaining non-deterministic step is this UI default. Precedent exists for the alternative: Cursor Origin (#165) shows an honest "unsupported forge" state instead of guessing. Doing the same here would need the brief pre-resolution window (before gitRemoteInfo() returns) to render a neutral/loading state instead of an optimistic GitHub guess — deferred until there's a concrete report of it mattering, since today it never surfaces the wrong forge for supported CLIs.

  • Gitea follow-ups (deferred from the v3.11.0 Gitea lot, issue #193): forge-side auto-merge via the merge endpoint's merge_when_checks_succeed, which Gitea does support; submitting and dismissing reviews (reading them is implemented), check annotations, per-file review history, cross-fork PR creation, and Gitea Actions logs; exact PR counts, since gitea_pr_count is bounded at 300 because Gitea's real total lives in the X-Total-Count response header and curl_with_status captures no headers at all, so an exact count needs a shared-transport change that would touch every forge; SettingsAccountsTab.vue has no test file, so the account form's Gitea branch and the two-entry keychain removal are covered only by hand-reading, which is where the frontend-to-Rust join already broke once and would break silently again; and an old Gitea that silently ignores an unrecognised merge field and merges with its own default (HTTP 200) never triggers the legacy-field retry, with nothing in the status code to distinguish that case. Also, from the final review fix wave (2026-09-16): commit links force https and drop the port, because the frontend-only forgeCommitUrl builder cannot see the account's base URL, which lives in the keychain, Rust-side only; App.vue's openOnForge sends a Gitea repo to github.com, a pre-existing gap it now shares with azure and cursor; the account form can carry a stale username when the forge select is switched mid-form without clearing it; and the dev-server's gitea-pr-count route uses the list ceiling where the Rust command uses a dedicated count ceiling, and surfaces an HTTP error where the Rust command degrades to 0.

  • History-aware prompts for the MCP — align buildResolveHunkPrompt / gitwand_resolve_hunk_llm with the v3.11.1 history context (collectHunkHistory is already exported from @gitwand/core).

  • Rename-aware history — blame -M -C / log --follow for the v3.11.1 history context.

  • Dedicated git_conflict_history Rust command — one IPC round-trip and a real process timeout, if the gitExec round-trips of v3.11.1 prove slow.

  • Honor .gitwandrc llmFallback.model / maxTokens on the desktop — ignored today in favour of the app's AI settings.

  • File Explorer follow-ups (out of scope for v3.11.2, spec §10 and its 2026-10-02 addendum). Not done: stage/unstage from the panel, file operations (rename, delete, create), and tree-wide name search beyond type-ahead over the visible rows. Each needs its own design, and search would have to work with a 5,000-per-folder listing cap.

  • Refresh a clean File Explorer tab on an external change. A tab's buffer is read when the tab opens. Since v3.11.2 a clean tab re-reads the disk when it leaves its Diff side, but a tab that stays on File does not see an edit made outside GitWand until it is reopened. The watcher already reports the path, so a clean tab could reload in place, and a dirty one could offer to.

  • Live Repo watcher blind spot on ignored folders. The watcher drops events under node_modules, target, dist, .venv and __pycache__, so an ignored folder expanded with "Show ignored" in the File Explorer does not refresh live. Collapsing and re-expanding it re-lists it.


Vision

GitWand is a native Git client that understands code, resolves trivial conflicts on its own, and makes visible what the terminal hides.

Positioning: neither "yet another Git GUI" nor an IDE. A first-class Git navigation tool — fast, local-first, cross-platform — with a unique algorithmic intelligence for conflict resolution, and a surface for interacting with AI agents (MCP, Agent Sessions, terminal).

Core values: open source (MIT) · native performance (Tauri 2 + Rust) · zero mandatory cloud · every feature optional and explicit.


Competitive landscape

Client Stack Price Strengths Weaknesses
Kaleidoscope macOS native ~€150/yr Image diff, folder diff, visual 3-way merge macOS-only, no Git workflow, no auto-resolve
GitHub Desktop Electron Free Simple, GitHub PR workflow, cherry-pick/rebase GitHub only, basic diff, no AI, no auto-resolve
GitButler Tauri/Rust Free Virtual branches, stacked PRs, Agents Tab (Claude Code); MCP server, Series A Apr 2026 Unfamiliar paradigm, no algorithmic auto-resolve
GitKraken Electron $8/mo Agent Mode v12.0, multi-forge, Launchpad, cloud Workspaces, AI commit/PR/merge Paid, Electron, cloud account required for advanced features
GitSquid Tauri/Rust €49/yr Conflict Predictor, scratch worktree, Monorepo Scope, secrets scanner, multi-forge Paid, no algorithmic auto-resolve
Fork Native $50 Fast, clean UI, large repos No inline PR review, no auto-resolve
Tower Native $69/yr AI commits (Claude Code + Codex, v16 May 2026), multi-forge Paid, no resolve engine
Sublime Merge Native $99 Ultra-fast, configurable diff_algorithm No PR workflow, no AI, no auto-resolve
Strand Tauri 2 + React Free/OSS Agent-native worktree sessions (parallel agent workspaces), full worktree lifecycle (merge+archive+recovery), WCAG 2.1 a11y, published perf baselines No conflict AI, mono-repo only, no Launchpad equivalent
Gitoryx Native (non-Electron) Freemium (private repos capped at 30 commits on Free) Very active (36 releases May→Oct 2026, v1.0 on 2026-10-01): guided bisect, identity profiles per repo, auto-resolve wand for identical conflict blocks + conflict map, AI conflict resolution and commit explanation, changelog generation Proprietary, conflict handling shallow (identical blocks + LLM), no engine accuracy measurement
GitComet Rust + GPUI Free/OSS Zed-level responsiveness, dual GUI+headless (difftool/mergetool), Linux-first, documented perf on Chromium-scale repos No AI, no worktrees, no multi-repo, no conflict resolution (strategy algo only)
RelaGit Electron + SolidJS Free/OSS Fine-grained reactivity (SolidJS), native AI SDK (@ai-sdk/anthropic) for commit suggestions, community theme ecosystem, popout windows Electron (heavy), fragile beta, no worktree/launchpad, no structured conflict AI

Shipped

Full change details per version: CHANGELOG.md

Version Highlights
v3.12.4 Windows app starts without the Visual C++ Redistributable — the C runtime is linked statically (it had been imported since v3.11.2, so winget rejected v3.11.2 to v3.12.3), and the release fails if the exe imports it again · the asset re-upload step looks in the real bundle folder (#273) · SECURITY.md (#272)
v3.12.3 Reset --keep (#263) · opt-in auto fast-forward after fetch (#265) · tracked files matching .gitignore warning + untrack (#264) · PR comment actions on GitHub, in-house Markdown renderer, GPU rendering by default on Linux with an automatic software fallback (#257) · diff parsers bounded by hunk counts keep --/++ lines (#270) · file history compare in the desktop app, across renames (#269) · non_overlapping no duplicate lines under diff3 (#259) · MCP residual-marker check (#260), Bitbucket PR-list pagination (#261), PR write actions on forks (#262), global-shortcut startup (#256) · command registry covers forge wrappers and Rust registration (#268, #269)
v3.12.2 Extra context for AI-written PRs and release notes, create a branch with AI from the branch selector, commit AI language chips translate the current message, one shared frame for AI split buttons (#252) · AI generation follows the chosen language and model again (stale settings write-back), no phantom origin branch and every remote's branches count as remote (#255), identity menu no longer clipped (#252) · modal close buttons aligned, light-theme dividers and minimap visible, larger modal/Help titles (#253, #254) · tests pinned to en-US (#251)
v3.12.1 AI-task merge-back no longer loses data (#233, #247) — squash-merge only when the main checkout's HEAD is in the task's history and the task's starting commit/branch still holds, all or nothing, snapshot first (dry run, so a refusal leaves none); closing a terminal stops the agent's process groups; a cleanup failure closes the task with a warning · Security hardening (#244) — AI CLIs from an allowlisted env, each run in a fresh private directory, Claude with no tools/project settings/MCP, prompts on stdin; AI key in the OS keychain, bound to its endpoint; CSP to fixed hosts; remote images and Gravatar opt-in; telemetry opt-out; file commands confined to git work trees · Full-screen Settings aligned with Help, per-project commit identity with its signing key (#246) · WIP as a Git Tree row (#224) · AI PR-description update and in-place edit (#234), reasoning effort forwarded + provider model lists (#237), unified AI templates with per-repo output language (#238), force push after a local rebase (#239), responsive header (#240), discard keeps staged work (#241), terminal polish (#242), plus graph, stash, rebase and diff fixes (#222–#236, #243, #245) · Dependabot #127/#128 (#249)
v3.12.0 Built-in terminal renderer — xterm.js replaced by GitWand's own VT emulator and DOM renderer (utils/vt) that rebuilds only changed rows, fast even on software GL; bundled Symbols Nerd Font for prompt icons; terminal follows the tab surface and light/dark theme · WIP in the Git Tree — the Changes dock entry becomes a WIP tab glued to the Git Tree, the WIP diff overlays the graph · Cherry-pick as WIP (--no-commit) · reset/checkout refresh the Git Tree immediately (#213) · staged files can be discarded, including staged renames · WIP on the trunk head stays on lane 0 · dependency security pass (rustls 0.23.45, MCP SDK transitive deps, DOMPurify 3.4.16)
v3.11.2 Finder-like folder navigation — the File Explorer panel becomes the file browser (the separate Browse view is gone): lazy per-folder list_repo_dir with in-process libgit2 ignore classification (5 000-entry cap, 66 ms for a 6 000-file folder vs 1.6 s for git check-ignore), live re-listing from the Live Repo watcher, a virtualized keyboard-first role="tree", change badges on every folder above a changed file, per-tab Diff | File with a Working tree | Index switch, context menu (Copy path, Reveal in Finder/Explorer via reveal_in_file_manager, Scope here) · git_diff/write_file go through a filesystem-resolving safe_repo_path · the untracked-file diff gets the 5 MB cap · getGitDiff stops dropping the truncation, untracked-directory and nested-repo fields on Tauri · Linux AppImage launcher shipped 0755 (@tauri-apps/cli 2.12, CI mode check)
v3.11.1 History-aware LLM fallback — llm_proposed and "Resolve with AI" now tell the model why each side changed the conflicting lines: the commits since the merge base, with their messages, plus range diffs within a token budget (1 500 by default, 200–8 000). Computed locally through an injected GitRunner, so @gitwand/core stays browser-safe, and collected only for hunks actually sent to a model · an explicit "History unavailable" line instead of a silent gap · a .gitwandrc opt-out that wins over the app setting · shown in the LLM trace panel · fixes: MergeEditor never received the repo path, which had silently disabled custom automations and resolution-memory apply; saving Settings no longer drops unknown llmFallback keys
v3.11.0 Merge preview-to-apply + editable diff — "Merge and auto-resolve" runs the real operation and re-runs the engine against what git produced, applying what passes the gates and stopping on the residual; a numeric confidence bar (minConfidenceScore) ANDed with the label gate across desktop, .gitwandrc, CLI and MCP; per-hunk opt-out; CodeMirror 6 in the merge editor and an editable inline diff · Gitea and Forgejo support (#193) verified against a live 1.27.3 server · Forge-side auto-merge on GitHub, GitLab and Azure, with Bitbucket refusing honestly rather than pretending · Abort and continue tell the truth (#197, #202): one git_operation_action for merge, cherry-pick, revert and rebase, three outcomes instead of two, confirmation before discarding resolution work, and nothing auto-continues · A declared Tauri-to-dev-server command registry with a guard, plus failure parity for 27 write commands — which found and fixed a submodule update that reported success whatever git did, and two routes that 404'd under dev:web
v3.10.0 Live Repo (#178) — a notify filesystem watcher replaces the 2s status poll, which becomes a 15s fallback; raw OS events are coalesced into typed RepoChangeEvents over a scoped tauri::ipc::Channel (SSE under dev:web), one watcher per repo shared by N subscribers, designed as the hook for the v4.0 incremental indexer. libgit2 phase 1 lands on git_diff only (see Later (unscheduled) for why git_blame did not). clone/fetch progress moves off the global broadcast onto per-invoke channels, packages/core resolution moves into a Comlink Web Worker, and the Today inbox stops being read-only: merge, nudge and a direct jump into the resolver.
v3.9.1 No-fast-forward merge option (#177) — the merge-into-current popover gets an "Always create a merge commit" checkbox, forcing git merge --no-ff even when a fast-forward is possible. Off by default · CLI update notice — gitwand checks npm for a newer version at most once every 24h and prints a one-line notice for a global (non-npx) install
v3.9.0 Engine Accuracy — the engine's claims are now measured against ~1,700 real merges instead of asserted (benchmark/, 8 pinned public repos, byte-for-byte comparison with what teams actually committed) · no complex hunk is ever silently applied (format_semantic reclassification, scored and traced) · a resolution that breaks a format invariant (double Unreleased, duplicate JSON key) is retracted · generated files (lockfiles, bundles) decline by default instead of an auto-merge measured wrong ~100% of the time (resolveGeneratedFiles opt-in) · the engine knows what merge it's in (MergeContext) — version-identity conflicts resolve to the target branch, laravel agreement 24 → 83% · package.json/composer.json fragments merge by key instead of line-by-line · gitwand conventions measures a repo's own merge history to derive its policies, always losing to an explicit .gitwandrc · a sandboxed --regenerate tier runs the ecosystem's own installer in a disposable worktree for declined lockfiles, measured at 38.5% agreement against an 80% bar so it stays CLI-only rather than shipping to desktop · benchmark-gate.yml CI check blocks any future PR that regresses agreement on the pinned corpus
v3.8.0 Time Machine — repo snapshots & global undo. Every destructive operation (discard, reset, checkout, branch switch, bulk resolution apply) first captures a restorable snapshot of the working tree (untracked included), the index and conflict stages 1/2/3, written with git plumbing under refs/gitwand/snapshots/ and restored via read-tree so it never refuses on a dirty tree · undo offered where the action happened — a single-slot toast with an Undo button and a ⌘Z hint, since a discard previously gave no feedback at all · global ⌘Z / ⇧⌘Z now rewind and replay repo operations, reporting through that same toast · the existing rewind popover (⌘⇧U) lists snapshots merged with git's reflog instead of the reflog alone, with a full-history modal behind its footer link; restoring is itself undoable via a pre-restore snapshot · retention settings (age + count caps, pruned on repo open) and opt-in AI snapshot labels · snapshot refs excluded from every --all traversal, and every ref move a restore makes carries an explicit reflog message
v3.7.0 Commit Review — micro AI reviews in the Changes panel (inspiration git-lrc, fully local instead of a cloud+browser detour). "Review staged changes" runs the pre-review engine against the staged diff (inline findings, severity badges, n/p/x navigation) · Fix with agent pipes findings into a terminal AI agent session against the current repo (the scratch-worktree variant was cut after manual QA found it could hit a CLI's first-run "trust this directory?" screen and misfire a real command — tracked as a follow-up) · Iterations & coverage tracking bound to HEAD · Review / Vouch / Skip commit-time decision recorded as a GitWand-Review: trailer · per-repo .gitwandrc opt-in overriding the app Setting in either direction · a composable pre-commit hook merging the shipped v3.5.0 secrets section with a new warn-only review reminder · a real focus trap added to BaseModal, fixing a foundational a11y gap inherited by every modal in the app · fixed a core reactivity bug where routine background polling silently wiped findings, plus a dozen smaller findings from a dedicated product/code review round
v3.6.6 Dev loop & CI build times (pure tooling/perf chore, no product surface) — ci.yml's 3-bundle-per-push desktop job replaced by a fast rust-check (fmt/clippy/check/test, now on PRs too) + a path-filtered bundle-smoke job (~230 billed CI min saved/push); Rust cache across all 3 workflows; [profile.ci]/[profile.dev] cut a post-edit cargo build from ~21s to ~6.5s; measured cargo llvm-lines/--timings to rule out the previously-planned gitwand-git crate split; Vitest defaults to environment: "node" instead of global jsdom (setup time 96s→17s); secrets-scanner ignore-regex precompiled (~24x Rust/~2.5x TS); @gitwand/core's resolution engine lazy-loaded out of the boot chunk (main bundle −185 KB raw); deduped reqwest (dropped native-tls/openssl-sys, removed libssl-dev from CI); anonymous telemetry gated behind an explicit telemetry Cargo feature with a build-time guard against a telemetry-less release
v3.6.0 Post-checkout "Update branch" prompt — one-click fast-forward (with stash/restore) or "Continue on local branch" when checking out a branch that's behind its upstream with no divergent commits, per-branch mute · Non-blocking rebase-conflict handoff (#128) — an interactive rebase conflict now closes the blocking RebaseEditor modal and hands off to the existing rebase banner + inline MergeEditor instead of trapping resolution behind an overlay; also fixes a UI freeze on very long/minified conflicting lines (word-diff now guards against pathological line lengths) · CommitGraph animation polish (#127) — no more layout shifts/flicker during pagination loading
v3.5.0 PR Review 2.0 — GitHub-standard keymap (J/K/⇧J/⇧K/V/⇧V/T/C/N/P/⌘Enter), viewed-file tracking, pending-review persistence, dismiss review/request reviewers, local opt-in AI pre-review pipeline (multi-hop, confidence-scored findings), PR summary block, unified LineAnnotation gutter model, GitLab review completion, lazy per-file diff loading + virtualized rendering (PR detail hot path 6→3 forge calls) · Pre-commit secrets scanner — zero-network local scanner (AWS/GCP/Azure/GitHub/GitLab/Slack/Stripe/OpenAI/Anthropic/RSA/JWT/high-entropy), non-blocking commit-area badge, .gitwandrc extensible patterns, dual Rust+TS implementation, CLI gitwand scan, opt-in pre-commit hook · PR badges: background prefetch & cache (git-log style) past the first page, plus a real open-PR count on the dock badge · Repo-tab reordering via pointer events (mouse/touch/pen) + keyboard a11y · File Explorer Save button moved next to the lock toggle
v3.4.0 Conflict-engine bundle — token_level_merge pattern (line/token decomposition, never auto-applied, user-confirmed via TokenMergePanel) · 2-way base recovery from the git index (unlocks diff3-only patterns on default-conflictstyle repos, guarded against clobbering manual edits) · ResolutionPreviewPanel + per-hunk "Resolve auto" confirmation · recoverable-before-model metric (summarizeTiers, surfaced in CLI/desktop/MCP + local cumulative stats in Settings, backed by a corpus regression guard + golden-funnel CI gate) · value_only_change extended to diff3 with semver/timestamp-max resolution · deterministic recoverers forced before the LLM path · data-loss fixes (imports resolver emptying hunks, insertion_at_boundary dropping duplicate-line insertions, whitespace_only false positive in string literals, rename detection matching inside strings/comments) · git log pagination/caching fixes. Measured: manual residual halved on a 2000-merge production corpus (5.6%→2.7% of hunks)
v3.3.0 Blame gutter in the File Explorer's CodeMirror editor — opt-in author/date gutter, deduped per commit run, hover tooltip · Telemetry moved to Aptabase — Umami Cloud was silently dropping every launch ping (non-browser User-Agent filtering); replaced with App-Key-authenticated Aptabase, including a self-hosted upstream crash fix (tokio::spawn → tauri::async_runtime::spawn) · Azure DevOps PR base-branch picker now lists server-side branches, not just local refs
v3.2.0 Integrated terminal (WebGL rendering, inline search, clickable links, typed tabs with unread dot, real PTY agent launch, "New AI task" scratch-worktree button) · File Explorer / Editor panel (gitignore-aware tree, CodeMirror 6 editor, lock/undo/save toolbar) · Git Tree (filter mode, branch/author quick-toggles, date-bucket separators, branch autocomplete + #PR search) · Per-project worktree submenu + AI-task worktree management · Submodule update checking/applying · Per-author line churn stats · Antigravity CLI provider · Rebase onto any ref + branch reset · Sidebar unified Changes section · Tauri 2.11
v3.1.0 Customizable dock & startup view, PR create unpublished-branch warning, customizable release-note templates, anonymous GDPR-compliant launch ping, website screenshot slideshow & lightbox, pnpm 11.9.0
v3.0.0 Today (triaged action inbox, urgency tiers, state-aware primary actions, Launchpad → Today rename) · VS Code extension on the Marketplace (esbuild bundle, publish-vscode.yml CI, 4 extension bug fixes, CLI validation surfacing) · Dashboard (contributor modal, activity tooltips, fortnight stats, Git-Tree commit navigation) · Branches (top-contributor avatars, pinned section, move uncommitted changes on switch, force-delete prompt) · Fullscreen markdown image viewer · Website hero toggle + clickable platform cards
v2.24.0 Full-screen views & in-app Launchpad — the permanent sidebar/Git-Tree strips give way to a floating bottom-center AppDock; Dashboard, Changes, History, PRs and a first-class full-screen Git Tree each render full-bleed (RepoSidebar gains a pane prop; collapsible, persisted commit composer rail). Launchpad gains in-app issue review (IssueDetailView + useIssuePanel), an action inbox (useLaunchpadInbox / useRepoActionCards), extracted scope (useLaunchpadScope) and internal navigation. The list/tree file-tree toggle extends to the history (commit) sidebar (useFileTree generalised over any { path } entry). Plus a Linux AppImage follow-up: URL openers de-pollute PATH/XDG_* so a spawned xdg-open resolves the system browser instead of silently no-opening (#52), with opener stderr/exit captured. EditCommitOverlay/SplitCommitModal lazy-loaded. Full dev:web parity + 5-locale i18n
v2.23.0 Changes sidebar & rebase polish — list/tree layout toggle for the changes view (collapsible folders, persisted layout + per-section collapse state, auto-expand to the selected file) via a new useFileTree composable; per-file and per-folder stage/unstage/discard fused into an always-visible segmented "action group". Interactive rebase now works in the packaged desktop app (dedicated git_interactive_rebase Tauri command replacing a dev-only HTTP endpoint) and branch pickers list branches by most-recent commit (shared branchSort). Plus a Linux AppImage fix: external links/OAuth buttons route through a robust multi-opener chain. Full dev:web parity + 5-locale i18n
v2.22.0 Advanced conflict resolution — file-level bulk resolution ("Accept all: Current · Incoming · Both" in one click, persistent memorize-rule toast, one-click "Apply rule to N hunks"); tree-conflict resolution for markerless conflicts (modify/delete, both-deleted, add/delete) via get_tree_conflicts/resolve_tree_conflict with a dedicated editor panel + sidebar badge; markerless content-conflict reconstruction (reconstruct_conflict rebuilds the 3-way text from index stages when the working tree lost its <<<<<<< markers). Plus remote-state reliability fixes: false "Publish branch" on already-published branches (remote_branch_exists), false "offline" blocking push/pull (WKWebView spurious events → hysteresis + authoritative confirmOnline probe), and git_remote_info preferring origin (fixes the bogus "unpushed tags" modal). Full dev:web parity + 5-locale i18n
v2.21.0 Monorepo Scope — pick a sub-workspace and scope the commit graph, search & stats to its file tree. Auto-detects 6 workspace formats (pnpm, npm/yarn, Cargo [workspace], nx.json, turbo.json, go.work), parsed natively in Rust with a documented precedence; scope persisted per repo (additive scope field in .gitwand-workspace.json, validated on load); git_log pathspec filtering + a new git_rev_count driving a stable "N commits hidden" badge; sidebar ScopePicker (auto-detected packages + "Custom folder…" ad-hoc), active-scope chip & badge in the graph header. Picker shows only on detected monorepos; full dev:web parity via a mock detect-monorepo route
v2.20.0 Scratch worktree + extended Conflict Predictor — "Resolve in scratch worktree" from the merge preview opens a temporary isolated gitwand-scratch-<timestamp> worktree as a repo tab (resolve away from the active checkout, bring changes back in one click or discard, auto-cleanup, origin-anchored lifecycle); Conflict Predictor extended to rebase (per-commit replay against onto) and cherry-pick — side-effect-free preview_rebase / preview_cherry_pick Tauri commands, MCP gitwand_preview_merge operation param, new gitwand preview CLI command, operation selector + risk badge (low/medium/high) + hunk-by-hunk preview in the panel
v2.19.0 GitHub OAuth & Azure DevOps + cross-fork PRs — "Sign in with GitHub" via OAuth device flow (tokens in the OS keychain, tokenless REST path, no gh CLI required), Azure DevOps as a first-class forge (AzureProvider, Entra ID device flow + auto token refresh, PR list/detail/diff/create/merge/checkout, comments, branch-policy CI checks, reviewer votes), cross-fork pull requests (target-repo selector defaulting to upstream, fork PRs surfaced in the list), and a backend performance pass (async Tauri commands, disk-persisted SWR PR cache, libgit2 git_status fast-path)
v2.18.0 Inline CI Check Annotations — check-run annotations overlaid in the PR diff across the three forges (GitHub check-runs API, GitLab artifacts:reports:codequality, Bitbucket Reports API), gutter icons ❌/⚠/ℹ with hover tooltip, clickable "N annotations" badge in the CI tab, per-file ⚠ count in the diff sidebar, forge-agnostic CIAnnotation type + ForgeProvider.getCheckAnnotations(), lazy one-shot fetch per PR; Copilot CLI as a fourth AI provider (text-only sandbox)
v2.17.0 opencode provider + per-CLI model picker — opencode-cli as a first-class AI provider (opencode run, binary discovery, Settings status), second model select under the provider picker for the three CLI agents (opencode enumerates via opencode models, Claude Code aliases, Codex free-text), aiModelByProvider persisted per provider, --model threaded through all three CLIs
v2.16.0 PR Activity Notifications — background Launchpad poller, zero-network snapshot diff (useLaunchpadNotifications) for CI flips / review requests / new comments / merge-close, native OS notifications via tauri-plugin-notification (background-only), Settings granularity (All · Reviews & comments · CI failures only · None) + "by people" bot filter, enriched workspace_prs_all (CI/review/comment fields)
v2.15.1 Git Tree polish & quick actions — Force push (branch context menu + protected-trunk/diverged-remote guard), Quick Stash ⌘⇧, (instant, AI label) + pending badge in the commit area, Submodules in the Git Tree (branch-picker section, per-commit pointed-SHA badge, click-to-navigate)
v2.15.0 Git Tree multi-branch — Git Tree as primary view, Log panel removed, unified context menus, stash/branch/tag management from the graph, DAG trunk-pinning, WIP node, search bar
v2.14.0 Forge completeness — GitLab updateComment/deleteComment/CI checks, complete Bitbucket stubs, forge-agnostic getConflictPreview/getHotspots, multi-account provider
v2.13.0 AI & Review — custom AI prompt presets, GitHub-native inline code suggestions in PRs
v2.12.0 Branch Management & Identity — Archived Branches, Pinned Branches, Multiple Committer Identities, Commit Templates
v2.11.0 Large-scale performance — backend.ts domain split, Fork Point visualization, transparent command log (⌘⇧L), real-time clone progress, CommitLog pagination
v2.10.0 Forge integrations + MCP catalog — GitLab MRs, Bitbucket PRs, multi-account, in-app MCP catalog (Settings > MCP, one-click install)
v2.9.0 Launchpad — cross-repo PRs/Issues/WIP/Team dashboard, pin/snooze, ⌘L, lazy Team, 95 green tests
v2.8.0 Agent Sessions View + Scheduled AI tasks — Agents panel, active MCP sessions, launch Claude Code from GitWand
v2.8.2 Performance hardening — lazy-load 20 panels, bundle −150 KB, libgit2 fast-path, consolidated polling, lib.rs split into 6 domains
v2.7.0 Multi-repo Workspaces + Hooks manager + Worktree first-class — tab=worktree, quick-create "New task" (⌘⇧N), cross-worktree status
v2.6.0 @gitwand/core Refactoring-aware merge — rename/move detection, opt-in via .gitwandrc
v2.5.0 LLM fallback opt-in — llm_proposed pattern, resolveAsync(), audit trail, desktop+CLI+MCP tie-in
v2.4.1 Semantic post-merge validation — tree-sitter parse-tree validity, opt-in tsc --noEmit, postMergeRisk dimension
v2.3.0 Tree-sitter structural dispatcher — entity-by-entity merge for TS/JS/Python/Go/Rust, +20-30% auto-resolution
v2.2.0 Format profile registry + JSON Patch arrays — /dependencies, /scripts, RFC 6902, +10-15% on JSON/YAML
v2.1.0 Histogram diff & block-move detection — Patience++, Rabin-Karp rolling hash
v2.0.0 Distribution & polish — Clone & Fork from the UI, Codex CLI provider, native macOS menu bar, Contributors Dashboard
v1.9.0 Git 2.54 suite — commit context menu (checkout/reset/revert/branch/tag/cherry-pick), Trailers, Blame diff algorithm, File history line-range + pickaxe, Tags panel, Conventional Commits prefixes
v1.8.0 Design system & modal foundations — AppHeader split, BaseModal, merge editor line numbers + minimap, PR description markdown
v1.7.0 Split commit by hunks — line-by-line selection, integrated into interactive rebase
v1.6.x Folder diff, Image diff, Submodules & Worktrees, @gitwand/core/@gitwand/cli/@gitwand/mcp published on npm + MCP Registry
v1.5.x Hardening, performance & English-first — XSS, LCS O(min), CI Rust↔Node parity, macOS TCC fix
v1.4.0 Pattern registry — reorder_only, insertion_at_boundary, desktop auto-update
v1.3.0 AI Everywhere — branch naming, PR writing, hunk review, conflict explanation, commit search, release notes
v1.2.0 Interactive Rebase, Absorb, AI commits, Undo stack
v1.1.0 MCP server (@gitwand/mcp) — 5 tools, 3 resources, Claude Code slash commands, enriched CLI JSON
v1.0.0 Full Git client + resolution engine — 8 patterns, diff3 LCS, format-aware resolvers, PR workflow + integrated Code Review

Design principles

  1. Intelligence first — Every screen should offer more than the terminal.
  2. Native performance — Tauri 2 + Rust. Sub-1s startup, smooth on 100k+ commits.
  3. Progressive — Works immediately for simple cases. Advanced features are discovered naturally.
  4. Cross-platform — macOS, Linux, Windows. Same quality everywhere.
  5. Free and open source — Core and desktop under MIT.
  6. Refusal is structured, not silent: any tool that declines to decide (a pending hunk, a detected silent conflict) hands back agent_guardrails built only from facts it actually computed (the diff, the signature, the missing argument), never inferred domain judgment like "this is security-critical." Applies everywhere a @gitwand/mcp tool can refuse (gitwand_resolve_conflicts today, detect_silent_conflict in v4.0.0); the /agent WebMCP page has no repository to reason from, so it never carries this.