Skip to content
| Marketplace
Sign in
Visual Studio Code>SCM Providers>BygoneNew to Visual Studio Code? Get it now.
Bygone

Bygone

Preview

David Mashburn

|
32 installs
| (0) | Free
See how change happened. Visual diff and file history for VS Code.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

author: David Mashburn created_at: 2026-06-01T20:35:08Z modified_at: 2026-07-31T20:56:06Z generated_by: Codex generated_for: David Mashburn reviewed_by: approved_by: repo: https://github.com/davidmashburn/bygone branch: main repo_branch_url: https://github.com/davidmashburn/bygone/tree/main repo_head_commit_url: https://github.com/davidmashburn/bygone/commit/183156146f54cc35b9304d6b2131e066b88e97dc

Bygone

Bygone is a VS Code extension and standalone desktop app for visual diff and file history.

Bygone screenshot

Explore the 51-step product tour, including comparison, VS Code editing, dependency graphs, pull-request review, and the reader path for optional proof.

Features

  • Editable two-way side-by-side diff view
  • Dynamic adjacent multi-panel diff view
  • Flowing connectors, block contours, and inline change highlighting
  • Git file history viewer with commit-by-commit navigation
  • Local branch-change exploration using merge-base-to-tip semantics and changed-file progress
  • Binary-aware comparisons with side-by-side image previews and byte-equality reporting

Status

This project is usable as a VS Code extension and standalone desktop app. The two-way diff and git history flows are the most complete. The multi-panel view is diff-focused, not a merge tool.

Change blocks and inline highlighting

Hover a changed block on either side or its gutter connector to show copy arrows. Moving the text cursor into a changed block or jumping to a change also shows them. Each arrow stays beside its source block's first line: the left arrow points right, and the right arrow points left. Clicking copies that block to the opposite panel; arrows targeting a read-only panel are disabled.

A touching run of deletions and insertions forms one blue replacement block, even when the text has no matching words. One-sided changes stay green. Green and blue blocks can still touch; exactly matching lines separate change regions. When an unpaired gap contains exactly one line on each side, those lines are compared for inline highlighting. Larger ambiguous gaps keep conservative line alignment within their blue block. A short statement expanded from one line to several, or collapsed back to one, is compared as a whole for inline highlights when the combined text is similar enough. This preserves the line alignment and the inline highlighting length limit.

Multi-panel comparisons show changes from all adjacent pairs. A shared panel shows the union of changed lines and words, with overlaps painted once. A line that is one-sided in one pair and replaced in another uses replacement blue; connectors in each gutter still describe that pair. Focus selected pair is off by default. Turn it on to show only the selected pair's highlights and connectors, then select another gutter to inspect that comparison with its own block colors. Toggling focus preserves your scroll position. Previous/next change always follows the selected pair. Directory and file views share the Visible panels setting (2, 3, 4, or Fit), so opening a file or returning to its directory keeps the chosen density. New three-way and four-way comparisons start with 3 and 4 panels selected. Those counts stay visible even in tight windows; choose Fit for automatic width-based adjustment. You can still select a smaller count manually.

Bygone matches words first, then uses edge trimming inside each replacement: leave the longest identical beginning and ending unhighlighted, and highlight the remaining middle. The beginning and ending never overlap. If one complete text is a prefix or suffix of the other, keep it unhighlighted: Name → NewName shows Name → [New]Name. If either edge works, or otherwise when matching edges overlap, prefer the beginning. Adjacent removed and inserted tokens form one replacement until an unchanged token separates them.

Brackets below represent the stronger inline highlight:

Change Highlighted result
oldName → newName [old]Name → [new]Name
nameOld → nameNew name[Old] → name[New]
userCount → usersCount userCount → user[s]Count
userStatisticalCount → userMetricsCount user[Statistical]Count → user[Metrics]Count
oldNameOld → newNameNew [oldNameOld] → [newNameNew]

This handles a single contiguous edit anywhere in a replacement. It does not search for unchanged text inside the remaining middle: multiple separated edits within one word highlight everything from the first difference through the last. It also makes no semantic judgment: timeoutMs → timeoutSeconds preserves the shared final s, showing timeout[M]s → timeout[Second]s.

Highlight boundaries preserve whole displayed Unicode characters, including combining accents and emoji. Edge trimming changes inline emphasis, not line pairing or block colors. Existing whitespace-only highlighting and limits on inline highlighting for long lines still apply.

Install For Development

Install dependencies and compile:

npm install
npm run compile

Run the extension in VS Code:

  1. Open this folder in VS Code.
  2. Press F5.
  3. In the Extension Development Host, run one of the Bygone commands from the Command Palette.

Run the standalone desktop app locally:

npm run standalone:start

Run a headless standalone smoke check:

npm run standalone:smoke

For development only, you can install the repo-local launcher globally:

npm install -g .
bygone
bygone path/to/file-or-directory
bygone --diff path/to/left path/to/right
bygone --diff
bygone --diff path/to/file1 path/to/file2 path/to/file3 [...]
bygone --history path/to/path
bygone review
bygone review feature/my-branch --base origin/main
bygone review https://github.com/owner/repo/pull/1753
bygone review 1753
bygone present feature/my-branch --base origin/main
bygone present https://github.com/owner/repo/pull/1753
bygone tour context --pr 1753 --output context.json
bygone completion zsh
bygone --help

For a one-command local sync that builds the repo, installs the global CLI, packages the desktop app, and auto-installs the VSIX and desktop app for your current platform:

npm run dev:sync

A clean checkout installs the committed version. Rebuilding with uncommitted changes automatically increments a local iteration: 0.9.9+dev.1, 0.9.9+dev.2, and so on. The CLI, Desktop About dialog, and artifact names include that label. This is SemVer build metadata, not a new release patch; it does not change version precedence. npm run reinstall reuses the current artifacts without incrementing the iteration.

For a real release, set the intended plain version with npm version 0.9.10 --no-git-tag-version, consolidate the changelog, and commit before npm run dev:sync. Local dev versions must not be published; release:build and release:publish reject them. Keep dev iterations out of committed release history.

CLI defaults:

  • In a Git repo, bygone opens directory history for the current directory.
  • Outside a Git repo, bygone opens a blank editable diff.
  • bygone <file> opens file history.
  • bygone <directory> opens Git directory history for that directory.
  • bygone --history <path> opens file or directory history.
  • bygone review [<head>] [--base <base>] reviews the committed branch tip against its merge base. The base is detected from origin/HEAD, main, or master when omitted.
  • bygone present [<head>] [--base <base>] opens the same committed range as an app-hosted change tour, grouped into a deterministic suggested reading order.
  • bygone <left> <right> auto-selects file diff or directory compare.
  • bygone --diff <file1> <file2> <file3> ... opens multi-panel diff or multi-directory compare.

On macOS, desktop-backed CLI commands and change tours route into the running Bygone app instead of opening another app instance and Dock item. Starting a new comparison brings the central app window forward and replaces its current session after any unsaved-change confirmation. Tours reuse a dedicated window owned by that same app process.

When Bygone is quit or restarted for an upgrade, the desktop app remembers the open Explore session and tour windows. A normal no-argument launch restores them; an explicit file, directory, review, or presentation launch takes precedence. Windows whose source files or Git targets no longer exist are skipped or replaced with a blank Explore window.

Shell completion is generated from the same command specification as bygone --help, including contextual file arguments and local Git refs for branch review. npm run dev:sync, the desktop app's command-line installer, and the Homebrew packages install completions automatically. To install one manually, choose the command for your shell:

mkdir -p ~/.zfunc ~/.local/share/bash-completion/completions ~/.config/fish/completions
bygone completion zsh > ~/.zfunc/_bygone # add ~/.zfunc to fpath before compinit
bygone completion bash > ~/.local/share/bash-completion/completions/bygone
bygone completion fish > ~/.config/fish/completions/bygone.fish

If the native desktop app is installed, the npm/source launcher prefers it and forwards the shell working directory. Set BYGONE_FORCE_BUNDLED=1 to force the npm-bundled Electron runtime instead. The launcher removes ELECTRON_RUN_AS_NODE before starting Electron so editor-integrated terminals cannot accidentally force the app into Node mode.

Review a pull request

Use bygone review <pull-request-url>, bygone present <pull-request-url>, or bygone tour context --pr <pull-request-url>. They also accept owner/repo#1753, host/owner/repo#1753, and a number (1753 or #1753) inside a clone. URL suffixes such as /files and discussion fragments are accepted. A numeric path at the root command, such as bygone 1753, still opens a file or directory.

Pull request inputs require the GitHub CLI, authenticated with gh auth login for the selected host. Bygone discovers gh on PATH and common installation paths; desktop launches can set BYGONE_GH_PATH to its absolute path. gh auth setup-git is not required. A number follows the repository selected by gh, including an upstream repository in a fork clone.

No manual clone is needed. Bygone reuses a matching full clone, or creates an empty cache repository under ~/.cache/bygone/repos (honoring XDG_CACHE_HOME; BYGONE_CACHE_DIR overrides the Bygone cache directory). Fork heads are fetched through the base repository's refs/pull/<number>/head. Host identity and the fetched head commit are checked against GitHub metadata. The destination branch is fetched by name and its observed tip is pinned; GitHub’s historical baseRefOid can lag that branch. If the PR head moves during the fetch, retry the command to refresh it.

Fetched refs use refs/bygone/; the user's branches, checkout, index, and Git configuration are preserved. Bygone-owned caches use partial fetches when supported, with a host-scoped gh credential helper for later blob reads. User-owned partial and shallow clones use the cache instead. Bygone stores the helper command, not credentials. Dirty local changes are excluded from the review.

The desktop Git → Review Pull Request… dialog accepts a link or qualified reference. PR title, description, author, state, and URL are included in context and presentation metadata; the title and URL supply presentation defaults. PR inputs cannot be combined with explicit head/base refs or present --tour, whose authored range is authoritative.

Branch review compares the selected head directly with merge-base(base, head), so merge commits are represented correctly in the aggregate diff. Commit metadata retains every parent of merge commits for future temporal review. Dirty index and working-tree changes are reported but never silently included. Detected renames keep distinct old and new paths for correct drill-down and navigation without adding persistent cross-tree connectors.

Two-file and directory drill-down comparisons detect binary content before decoding it as text. Images render side by side when they are small enough to preview inline; all binary comparisons report whether the underlying bytes are identical.

Change tours can layer an authored, code-connected narrative over the complete generated change set. Pass a .bygone file with --tour; named source anchors compile to exact commit and line references, while an independent Files rail keeps every changed file available without adding filler scenes to the narrative. The legacy .bygone.yaml spelling remains supported. Try the self-referencing example with bygone present --tour examples/bygone-history.bygone, then see the change tour format.

Packaged macOS builds register .bygone with the desktop app, so Finder can open a presentation directly. Windows and Linux builds currently require opening the file through Bygone or the bygone command; they do not install an operating-system file association.

Agents can validate anchors and structure with bygone tour validate <file.bygone> --json, compile a repository-bound manifest with bygone tour compile, and retrieve the authoring contract with bygone tour schema. See Generating change tours with an LLM.

Install the agent skill:

# project scope (PromptScript-safe; committed with the repo if you run it here)
npx skills add davidmashburn/bygone -s pr-tour-guide -y

# global scope — name agents to avoid PromptScript global-install noise
npx skills add davidmashburn/bygone -s pr-tour-guide -g -y -a cursor codex claude-code

The skill includes Bygone install instructions for macOS Homebrew, npm, and source checkouts. It also ships inside the @davmash/bygone npm package under skills/pr-tour-guide/. Source: pr-tour-guide skill.

Contributors should consult the internal product surface overview before adding a command, mode, tour scene, or packaged artifact.

bygone tour context [<head>] --base <base> produces a provider-neutral change dossier with bounded patches, changed ranges, file roles, symbol hints, commits, renames, and explicit binary omissions for an LLM to consume.

bygone dependencies [<head>] --base <base> compares static JS/TS module dependencies, labels initialization versus deferred use, and lists unchanged consumers of changed modules. Add --json for exact source evidence, or use bygone tour context --base <base> --dependencies to include it in a change dossier. See dependency evidence for resolution rules and coverage limits. Add --graph for Python, JS/TS, Go, Rust, and experimental Mojo symbol/call evidence; --html --output graph.html creates a standalone interactive viewer, and --mermaid exports a diagram. These analysis commands run through the npm/source Node CLI.

The desktop app also includes Help -> Install Command Line Tools... for non-npm installs. Homebrew cask installs can provide the bygone command automatically.

macOS says the app is damaged

Downloads from GitHub or Homebrew are unsigned (no Apple Developer ID signature yet). macOS Gatekeeper then shows a misleading “damaged” dialog.

Workaround (unsigned desktop builds):

xattr -cr /Applications/Bygone.app
open /Applications/Bygone.app

Or right-click the app → Open once, or allow it under System Settings → Privacy & Security.

Package For External Use

This repo is set up for local/private packaging. A typical release flow is:

npm install
npm test
npx @vscode/vsce package

That produces a .vsix you can install with Extensions: Install from VSIX....

Build the standalone desktop packages:

npm install
npm run package:desktop

That produces a macOS DMG in dist/. Cross-target packaging is split out because Windows and Linux builds may need additional Electron downloads or Wine support:

npm run package:desktop:mac:zip
npm run package:desktop:linux
npm run package:desktop:win
npm run package:desktop:all

Stage the scoped npm standalone package:

npm install
npm run package:npm
npm pack --dry-run ./dist/npm-package

The root package.json is the VS Code extension manifest and intentionally keeps the unscoped extension name bygone. The npm distribution is staged separately as @davmash/bygone so the global launcher can avoid the already-taken bygone package name while preserving the VS Code extension id davidmashburn.bygone.

Homebrew packaging templates live in packaging/homebrew/. They are staged for local validation only until release artifact URLs and checksums exist.

Build the full local release artifact matrix:

npm run release:build

That runs tests, rebuilds the VSIX, stages and dry-run checks the npm package, builds desktop artifacts, and installs the resulting CLI, shell completions, VSIX, and current-platform desktop app locally. A running macOS desktop app is asked to quit normally; installation stops if unsaved work prevents it from exiting, and the installed app is then restarted. If the local macOS DMG or Windows cross-build toolchain is unavailable, use node ./scripts/release.mjs --skip-dmg or node ./scripts/release.mjs --skip-windows while validating the rest of the matrix.

Publishing is intentionally explicit:

npm run release:publish

Run release:publish after committing the version and release changes. It aborts unless the worktree is clean and the current branch is main, pushes main, waits for that exact commit's GitHub Release Check workflow, rebuilds and installs all local artifacts, creates a GitHub release for desktop artifacts, and updates the Homebrew tap. The release tag triggers the protected GitHub Actions Release workflow, which publishes the npm package through trusted publishing after approval. The tap checkout defaults to the sibling homebrew-bygone directory; set BYGONE_HOMEBREW_TAP to override it. Until Marketplace trusted-publisher policies are publicly configurable, upload the packaged VSIX from the Visual Studio Marketplace publisher page.

Reinstall the current built artifacts without rebuilding:

npm run reinstall

This refreshes the global CLI, shell completions, VSIX, and desktop app from the existing artifacts. On macOS it performs the same graceful quit and restart, blocking installation when unsaved work keeps the app open.

Run the release checks:

npm run release:check
npm run standalone:smoke

The standalone smoke check is intentionally run directly because Electron can abort on macOS when launched from a longer nested npm command chain, while the same smoke check passes as a direct release gate.

In the standalone window, you can also drag and drop:

  • 1 file to open git history for that file
  • 2 files or directories to open a side-by-side compare
  • 3 or more files to open a multi-panel compare
  • 3 directories to open a three-directory compare

Git Difftool

Bygone can be launched from git difftool through either the standalone app or the VS Code extension.

Configure the standalone launcher:

./scripts/configure-git-difftool-standalone.sh

That registers:

git difftool -t bygone

Configure the VS Code launcher:

./scripts/configure-git-difftool.sh

That registers:

git difftool -t bygone-vscode

The VS Code path launches:

vscode://davidmashburn.bygone/diff?left=...&right=...

The wrapper scripts are:

./scripts/bygone-difftool.sh <left-file> <right-file>
./scripts/bygone-standalone-difftool.sh <left-file> <right-file>

Commands

  • Bygone: Follow Active Editor
  • Bygone: Pin Following File
  • Bygone: Resume Following
  • Bygone: Refresh Following Comparison
  • Bygone: Compare Active File With…
  • Bygone: Compare Selected Files
  • Bygone: Compare with Selected
  • Bygone: Cancel Staged Comparison
  • Bygone: View Active File History
  • Bygone: Open This Comparison in Desktop
  • Bygone: Compare Directories in Desktop…
  • Bygone: Compare Three or More Files in Desktop…
  • Bygone: Explore Current Branch in Desktop
  • Bygone: Present Current Branch in Desktop
  • Bygone: Open Authored Tour in Desktop…
  • Bygone: Install or Open Desktop App

Two-file comparisons open as independent editor tabs. Trusted local worktree panes edit through VS Code documents, so changes participate in dirty state, undo, save, and external-document updates. Historical and non-local inputs are read-only. Desktop hand-offs are unavailable in remote extension hosts.

Follow the active VS Code editor

Run Bygone: Follow Active Editor to open one comparison beside your source editor without moving keyboard focus. Switching source files updates that pane. The left side is HEAD; the right side is the VS Code document, including unsaved edits. Edit either the source pane or Bygone's working pane: both update the same document. Save, Undo and Redo in Bygone use that document's save and edit history. Typing neither saves the file nor stages it.

Source Control offers Open Staged Changes in Bygone (HEAD → index) and Open Working Changes in Bygone (index → working buffer), in the file's inline and context menus. Staged views exclude unsaved edits and are read-only. Native stage, unstage, discard, commit and checkout operations refresh live comparisons. The selected policy stays in place when a file leaves its SCM group; an empty comparison shows that there are now no changes. Enable bygone.followScmDiffs to follow supported native Git diff tabs during a following session. This does not change the SCM tree's default click behavior.

Use Bygone: Compare Symbol in Bygone, or enable bygone.followSymbol to follow Outline, Go to Symbol and cursor selections. Symbol focus preserves the selected comparison and uses the existing Strand matching engine. JavaScript and TypeScript are supported within the selected file pair, including Git-reported renames. Dirty-buffer selections in staged views require a verified mapping to the index. Unsupported or ambiguous selections show a reason and retain file context or a known one-sided symbol. Show File Context returns to the whole comparison; Reveal Source opens the working document or the exact read-only snapshot.

Working symbol slices are editable. Edits before a declaration move its tracked range; temporary syntax errors keep its editing range usable. Replacing or deleting the declaration externally returns to file context. If a concurrent edit makes a pending write stale, Bygone preserves the attempted text in an untitled recovery document instead of overwriting the source. Pending drafts are also recovered when the panel closes or the extension starts again after a reload.

Pin keeps the target, baseline and symbol focus. A pinned working endpoint continues to reflect edits; a pinned staged view holds both snapshots. Git changes show a notice until Resume Following resolves current endpoints. Refresh updates live comparisons; pinned snapshots remain fixed. Source navigation within the selected file preserves SCM policy; a different ordinary file selects HEAD → working. View File History and Manual Compare… pause following and open separate views. A restored following panel starts paused.

Labels identify the repository, paths, comparison policy and saved/unsaved state. New/deleted files and unborn HEAD use explicit absent endpoints. Following supports trusted local Git worktrees, including linked worktrees and multiple repositories. Each selected endpoint must be text, at most 128 KiB and 5,000 lines; Git snapshots must be UTF-8. Conflicts, unsupported diff inputs, symlinks, binary, remote, virtual and notebook inputs show an explicit unavailable state. Git failures clear the previous comparison. Arbitrary cross-file symbol moves and hunk staging inside Bygone are outside this integration.

Use Bygone: Open Evidence Review to inspect pinned requirement evidence, edit the working counterpart, and return to the original review. See the evidence workflow and PR Reviewer bridge.

See the integration contract and verification record for snapshot/edit safeguards, analysis budgets and reproducible Extension Host tests.

Limitations

  • Bygone is intentionally diff-focused; merge tooling is not exposed as a product feature.
  • Directory compare supports modified-file detection and file drill-down; deep tree ergonomics are still early.
  • The git history viewer currently steps through single-parent commit history for one file at a time.

Release Work

The current release checklist and remaining publication blockers are tracked in RELEASE_PLAN.md.

Codebase Guide

Architecture and implementation details are documented in CODEBASE.md.

Walkthrough

A screenshot-based walkthrough using Bygone on its own source tree lives in docs/walkthrough.md.

Why “Bygone”?

In short: this project is openly inspired by Meld, and Bygone is meant to carry that visual tradition into a more history-aware tool.

Meld was a direct inspiration for this project. Its visual diff metaphor is still one of the clearest and most human ways to understand change, and Bygone builds on that lineage while pushing further into revision history.

The name also nods to the bygone era before vibe-coding, when people were at least pretending to read, understand, and take responsibility for the code they were writing. This tool is about looking directly at what changed, where it came from, and how the current state emerged.

And yes, Codex, the irony is noted. Thanks for the assist.

Tests

Run the current unit checks with:

npm test
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft