Install

One command:

curl -fsSL https://dxcli.com/install.sh | bash

Or download a tarball for your platform and install manually:

tar xzf dx-0.7.0-linux-amd64.tar.gz
bash dx-0.7.0/install.sh

Available: linux-amd64 · darwin-arm64 · darwin-amd64 · windows-amd64

Then enable in any git repo:

cd my-project
dx enable

That's it. Make a commit and a session appears.

Commands

dx enable          # Install post-commit hook in current repo
dx disable         # Remove hook from current repo
dx init            # Create a .dx config file with defaults
dx snap [uuid]     # Save current Claude session (aliases: slap, yoink)
dx resume [id]     # Resume a saved session (by number or uuid)
dx ui              # Open session viewer in browser
dx log             # Show recent sessions in terminal
dx log -a          # Show all sessions
dx log -r          # Filter to current repo
dx log -n 50       # Show last 50 sessions
dx sync setup      # One-step cross-device setup (auto-detects gh CLI)
dx sync push [dst] # Push sessions to a private GitHub repo, local path, or rsync remote
dx sync pull [src] # Pull and merge sessions from the same

Snap & Resume

Save your current interactive Claude session at any point:

dx snap
# => Snapped! Session d29c9dca-4f49-459a-9a01-7241213d3db0 (27 messages)
#      repo:   my-project
#      branch: main
#      commit: b56e1a6
#      resume: claude --resume d29c9dca-4f49-459a-9a01-7241213d3db0

Resume from any checkout of the same repo — even across different clones or from WSL when the session was created on Windows:

dx resume
# => Recent sessions for my-project:
#   * [1] 5m ago   b56e1a6  claude  main      d29c9dca...
#     [2] 1h ago   463be4a  claude  feature-x  463be4ab...
#
# => Use: dx resume <number> or dx resume <uuid>

dx resume 1
# => Resuming session d29c9dca-4f49-459a-9a01-7241213d3db0...

Running dx resume with no arguments opens an interactive picker with search, arrow-key navigation, and keyboard shortcuts:

  • Ctrl+A — toggle between current repo and all projects
  • Ctrl+B — toggle branch badge and folder paths
  • Ctrl+R — rename the selected session (persisted across invocations)
  • Type to search by branch, commit, agent, folder, or custom name
  • Tab toggles between search and list focus

If the session was created on a commit ahead of your current checkout, dx warns you before resuming.

Aliases: dx slap and dx yoink do the same as dx snap. Aliases: dx hop and dx zap do the same as dx resume.

Session Viewer

dx ui

Opens a local web viewer showing all your sessions — both auto-created (from commits) and manually snapped. Click any session with a chat icon to see the full Claude conversation with messages, thinking blocks, and tool calls. Filter by repo, agent, or type.

Supported Agents

Agent Binary Session resume Status
Claude Code claude claude --resume (deterministic UUID, interactive picker) ✅ Tested
Gemini CLI gemini gemini --resume (search by commit slug) 🚧 Untested
Cursor Agent agent agent resume or agent --resume="<id>" 🚧 Untested
OpenCode opencode opencode run -s "<slug>" 🚧 Untested
OpenAI Codex codex codex resume [ID] 🚧 Untested
GitHub Copilot CLI gh copilot / copilot gh copilot --resume 🚧 Untested

By default, only claude is enabled. Other agents have hook scripts but are not yet tested. Configure via .dx file or DX_AGENTS env var. Missing binaries are silently skipped.

Configuration

.dx file

Run dx init to create one, or add it manually to your repo root:

# .dx
agents=claude gemini
# claude_args=--model opus
# gemini_args=
# cursor_args=--cloud
# opencode_args=
# codex_args=
# copilot_args=

Environment variable override

DX_AGENTS overrides the .dx file:

DX_AGENTS="gemini" git commit -m "test"

Per-agent args via env: DX_CLAUDE_ARGS, DX_GEMINI_ARGS, etc.

Priority: DX_AGENTS env var > .dx file > default (claude).

Sync

Keep your snapped sessions in sync across machines — laptop, Mac mini, workstation. dx uses a private git repo you already own as the transport, so there's no server to run, no account to create, and no ongoing cost. Since it's git, sync is store-and-forward: push while the other device is offline, pull whenever it comes back online.

One-step setup (recommended)

On each device, run:

dx sync setup

If you have the gh CLI installed and logged in, dx auto-creates a private <you>/dx-sessions repo on the first device and offers to reuse it on the others:

# Device 1 (laptop)
$ dx sync setup
=> Detected gh CLI logged in as @alice
? Create private repo github.com/alice/dx-sessions for sync? [Y/n] Y
=> Created github.com/alice/dx-sessions (private)
=> Saved sync target to ~/.dx/config
=> Done.

# Device 2 (Mac mini), same GitHub account
$ dx sync setup
=> Detected gh CLI logged in as @alice
Found existing repo github.com/alice/dx-sessions
? Sync from it? [Y/n] Y
=> Fetching existing sessions...
=> Saved sync target to ~/.dx/config
=> Done.

From then on, on any device:

dx sync push    # upload local sessions
dx sync pull    # download remote sessions and merge

Without gh — any git URL

If you don't have gh, dx sync setup asks for a git URL. Any private git repo you can push to works — GitHub, GitLab, Bitbucket, Codeberg, Gitea, self-hosted. Paste either form:

https://github.com/you/dx-sessions.git
git@github.com:you/dx-sessions.git

Auth uses whatever you already have set up — SSH keys, credential helpers, Keychain, Windows Credential Manager, or a PAT. dx doesn't manage credentials itself.

Cross-device walkthrough

# On the laptop
dx snap                   # save the current Claude session
dx sync push              # upload it

# Later, on the Mac mini
dx sync pull              # fetch and merge
dx resume                 # picker shows the session — hit Enter to resume

Conflicts and merges

When two devices push independently, dx fetches and re-integrates remote changes before committing, then retries the push. Merges are non-destructive:

  • Session list — unioned by UUID; both devices' sessions are kept.
  • Names — remote wins on TSV conflict (last push wins).
  • Blobs — UUID-named, never collide; existing local blobs are never overwritten.
  • Dropsdx drop writes a tombstone that propagates to other devices on the next pull, removing the session there too.

Target resolution

dx picks the sync target in this order (first match wins):

  1. Explicit arg: dx sync push <target>
  2. DX_SYNC environment variable
  3. sync=<url> in ~/.dx/config (written by dx sync setup)
  4. sync=<path> in the current repo's .dx config

Alternative targets (no git)

If you'd rather not use git, dx sync push|pull still works with:

dx sync push /mnt/backup           # local path (USB, NAS, shared folder)
dx sync push user@host:~/dx-data   # rsync over SSH

You can also point DX_SYNC at a folder synced by iCloud, Dropbox, or Syncthing — those services handle the transport, dx handles the merge.

Security notes

The repo is private, TLS in transit, and encrypted at rest by your git host. dx doesn't add client-side encryption, so sessions are readable by anyone with repo access (including, in principle, the git host's staff). For most threat models this is fine; if you need stronger guarantees, host on your own server or wrap blobs in age or gpg before snapping.

How It Works

A git post-commit hook runs after every commit. It:

  1. Extracts the commit message and hash
  2. Generates a slug: fix-login-redirect-bug-a1b2c3d
  3. Launches each configured agent in the background with the slug as prompt
  4. Logs the session to ~/.dx/data/sessions.tsv

dx snap finds the most recently modified Claude session file in ~/.claude/projects/ and records it. dx ui reads the session data and Claude's JSONL conversation files, builds a self-contained HTML viewer, and opens it in your browser.

The hook never blocks git. It skips during rebase, merge, and other non-interactive operations.

Requirements

  • git and bash (always required)
  • node (required for dx ui only)

Platform Support

Platform Status
macOSSupported
LinuxSupported
Windows (Git Bash / MSYS2)Supported
WSLSupported

Uninstall

Remove from a repo:

dx disable

Remove globally:

rm -rf ~/.dx ~/.local/bin/dx

If you added the PATH export to ~/.bashrc, remove that line too.