Changelog
Every dx release, newest first. dx update installs the latest; dx version shows the one you have.
0.12.2
Now on ARM Linux.
Added
- dx installs on Linux on ARM (arm64): Docker and dev containers on Apple Silicon, ARM cloud servers and Raspberry Pis running a 64-bit OS. The documented install failed there before, because no ARM Linux build was made.
Changed
- dx connect now runs rsntr 0.3.0.
dx updatemoves the rsntr that dx installed to it: a checked download, then one restart of the node. A device set to LAN only stays on rsntr 0.2.1, because 0.3.0 can't do LAN-only between machines yet. - On a machine dx has no build for, the installer says so before it downloads anything, and names the builds there are. Windows on ARM installs the x64 build, which Windows 11 runs under emulation.
Fixed
- On Windows, sending a session no longer stops the node for a moment (rsntr 0.3.0).
- With rsntr 0.3.0,
dx connect forgetanddx share forgetnow also cancel the messages still waiting for that device or friend. - The folder that holds a device's connect key is now readable only by you on macOS and Linux.
- After
dx update, a running auto-sync restarts on the new dx; before, it kept running the old one until it was restarted. dx connect joinanddx receivetry a knock again when it couldn't dial (a node that has just started), up to three times. When the other device won't take another knock from this one yet (it takes one a minute), they now say so ("Try again in a minute") instead of "could not reach".- On Windows,
connect.logno longer has dx's lines overwritten by rsntr's own output. The serving rsntr now writes to~/.dx/log/rsntr.log. - A message that a device made earlier but delivered later, after a newer one had arrived, was skipped for good. dx now reads messages in the order they arrive.
- A session or message that arrived while dx was already receiving one no longer waits for the next message or an auto-sync tick. Windows with rsntr 0.3.0 hit this most.
dx sync disablestops auto-sync for real. A release'sdxruns the script as a child, and disable stopped only that parent while the sync loop kept running.dx updatestops a running daemon's loop everywhere, and on Linux, WSL and Windows also the loops an earlierdx sync disableleft running. On macOS such a leftover loop keeps running until you stop it:ps -A -o pid,command | grep '[s]ync daemon', thenkill <pid>.
0.12.1
Hooks where git runs them.
Fixed
dx enableputs the hook where git runs it. It works in a linked worktree or a submodule (both failed with "Not a directory"), and a repository's worktrees all share its hook. Withcore.hooksPathset, it no longer writes a hook git never runs: it names that folder, prints the two lines to add to itspost-commit, and exits 1.dx disablecleans both folders.dx enablealso makes the hooks folder when it is missing, and refuses a dx folder whose path holds a quote,$, a backtick or a line break.- A repo you removed dx from stays quiet. dx's hook line now does nothing once dx is gone. Before, a repo that dx was removed from without
dx disableprinted "No such file or directory" on every commit. A commit updates an older dx's line to the new form, anddx enablesays when it updated one. - A session you dropped could come back when another device sent it with its id in other capitals, and a dropped session that someone shared back could be dropped again at the next sync. A drop now holds however the id is spelled.
- On a file system that tells capitals apart, such as Linux's:
dx drop,dx tidyand a drop from another device now remove a session's transcript copy however its id is spelled, a sync pull no longer brings a dropped session's copy back, and a session that comes from two devices keeps a single copy. - A name not yet marked, that dx 0.11 wrote with gawk 5.3 on another device (the awk Git for Windows ships), is recognized as dx's own: the session's title replaces it, as it does any name dx chose. A name that 0.12.0 already marked as a person's keeps that mark.
Changed
- The Uninstall steps, in the README and on dxcli.com's docs page, say to run
dx disablein each repo first, then remove the files, and what happens to a repo you miss.
0.12.0
Name a session; it sticks.
Added
dx sessionslists every session, newest first, with what dx knows about it.dx sessions --jsonprints all of it as one JSON document for scripts and tools, the way dx itself reads it: sessions, groups, devices and contacts; which sessions are open here and on your other devices, and whichdx wakecan reopen (when last seen, before the last reboot or not, whether its folder still exists); where each session's transcript is, how big it is and when it last changed; and wheredx ui's page is and which sessions it lists.--here <folder>adds which sessions belong to that folder.--scanrescans first; without it the answer is as of the last scan, whose time the document gives.--transcriptsalso counts each transcript's messages and finds when it started; counts are kept, so a later run reads only what was added.--here,--scanand--transcriptswork only with--json, and--jsonneeds Node.js; the list for people does not.- Name a session from the command line.
dx name <session> <name>(aliasdx rename) gives a session a name,dx name <session>shows it, and--clearremoves it here. - Open a session in a new terminal tab:
dx open <session>. It opens where the session last ran, or in the folder--cwdnames, and dx returns at once, so scripts can use it;--jsonsays whether a tab opened, and gives the command to paste when none could. It usesdx wake's terminals (tmux, Windows Terminal, iTerm2, Terminal.app; in VS Code's terminal and anywhere else it prints the command), or the one--terminalnames. - Exit codes a script can rely on: 0 ok (a no-op too), 1 error, 2 usage, 3 not found, 4 ambiguous, 5 needs a person, 6 cancelled.
--no-input(right afterdxor after the verb) andDX_NO_INPUT=1: never ask.DX_INTERACTIVE=1asks even when the terminal reports a pipe.--jsonon the commands that change something: snap, drop, color, group, wake, tidy, send and receive print one object on stdout. It implies--no-input.--help(or-h) on every command: its usage, exit 0, nothing else runs.dx help <command>shows the same.dx ui --no-openbuilds the page without a browser,dx ui --out <path>writes it elsewhere, anddx ui --jsongivespage_path,built_atandsessions(the rows the page lists).dx resume -yalso answers the "commit outside this history" question.dx sync setuptakes-yand a URL.- dxcli.com has a changelog page (
dxcli.com/changelog.html, built from this file) and a privacy policy (dxcli.com/privacy.html), which every page links to.
Changed
- A session target matches whole, never as a substring.
dx resume,fork,drop,send,share,colorandgrouptake a session by its number in the list (resume and fork), its full uuid, a prefix of at least 4 of its hex characters, or its name — exactly, else ignoring the case of A–Z. They used to take the first session whose id merely contained what you typed, sodx drop 3removed whichever session's id held a 3. A target that fits several sessions is now an error that lists them; a prefix shorter than 4 characters is read as a name. - A name sticks. A name you give with
dx nameor in the picker (Ctrl+R), and a/renamein Claude, is replaced only by a later/rename: never by a re-snap, by a/renamemade before it, or by a device on an older dx. Names you gave in the picker before 0.12.0 stick too: the first snap after the upgrade keeps any name dx didn't make itself. When a re-snap keeps your name over a different/renametitle, it says so and prints thedx namecommand that switches to the title. A name made only of hex digits and dashes is refused, so it can't be mistaken for a session id. - dx finds a folder's Claude sessions by Claude's own rule. Claude names a project folder by turning every character but letters and digits into "-" (and shortens a very long name with a hash); dx turned only ":", "/", "\" and "_". Any folder with a dot, a space or another character in its path — every
.claude/worktrees/*checkout — got the wrong name: a plaindx snapthere found nothing, anddx resumelinked transcripts into a folder Claude never reads. - Resume and fork link the newest copy of a transcript into a folder that has none: the newest under any Claude project folder, else the copy dx keeps from another device — not whichever one a directory listing returned first. A copy already in the folder is still never replaced.
dx resume,dx forkanddx openfollow a Claude projects folder that is a link. A transcript copy that dx keeps as a link is not followed (dx keeps them as regular files).- Edits from a device that has the session open apply here. A rename, color or group change made on another device to a session that is open there is meant to take the session over; the receiving side never read that the session was open, and silently refused it.
- One row per session. Every write to
sessions.tsvand its sidecar files keeps a single row per session, and a rewrite folds away duplicates an older device or a hand edit left behind. A session keeps its newest row, and stays snapped when any of its rows was a snap — a sync or another device can no longer turn it back into an auto. In the sidecar files the last row wins, as it already did for the picker and the viewer. A commit hook that runs several agents records one session, under the first of them. - Usage errors exit 2, not found 3 and ambiguous 4; previously they exited 1. An unknown sub-command of
dx sync,dx connectordx _adminprinted its usage and exited 0; it now exits 2 with the usage on stderr. Cancelled (nat any prompt, Esc in the picker) is exit 6, previously 0 everywhere. A question with nobody to answer is exit 5; previously it was 1 at snap, resume, fork and sync setup, and 0 at tidy, wake and share. - dx asks nothing without a terminal: it says which flag answers instead. The picker needs a console.
dx help,-hand--helpchange nothing. An unknown command prints the help to stderr and exits 2; an unknown argument todx ui(it was silently ignored), or an unknown flag or extra argument todx sync setup, is a usage error (exit 2) too.dx logshows one line per session. A session that a person named on another device is now in the default list, because it already counts as claimed (the resume picker always listed it).-t autoand-t livefilter by the session's type. Rows with a broken id or time are hidden.--uuidsprints ids in lowercase, asdx sessions --jsondoes, and--groupand--deviceignore the case of A–Z only, as finding a session by name does.dx color --groupcolours the sessions the group lists, including a session named on another device. On a group whose sessions are all unclaimed it says so, and how to list them (exit 3).dx tidynever removes a session whose newest row it does not recognize, and decides per session: an older snap row keeps a session.dx connect listcounts sessions, not rows.dx connectnow sends the transcript of a session whose id is stored in capitals (it sent only the session's details before), and sends a session spelled two ways once.dx syncbundles transcripts from one listing of the whole store, keeps each copy's modification time, and no longer makes a second copy of a transcript whose id is spelled differently.- A session's
/renametitle, first message and folder are read in full: a quote in a title no longer cuts it short. - Names, group labels and the open sessions a device reports are stored without control characters, and cut by character instead of by byte. Names and group labels are also stored as valid UTF-8: a broken byte sequence is dropped. After the update, a device may receive once more the details of sessions whose name or row holds non-ASCII characters.
- A session's name in a message never carries a control character, even a name an older version stored.
- Messages name a session by the first 8 characters of its id, as
dx namedoes. The full id stays in commands and in--json. The help and every command's usage fit an 80-column terminal. dx forksays what a fork is: the copy remembers everything so far, then goes its own way. It never made a git branch, and its help no longer says so.dx uiopens its page through dx's shared page opener: from WSL that is the Windows browser, and when no opener works dx says where the page is instead of failing. The page is written private to its owner (0600).dx ui's count is "Snapped or named": the sessions you snapped or gave a name, whichdx loglists by default.dx initwrites a.dxfor Claude Code only, and notes that hook scripts for other tools exist but are untested and unsupported.dx update's "what's new" link opens this page on dxcli.com. It pointed at a release page on GitHub that most people could not open.- The copyright line in
dx versionand the LICENSE name Axiom DX Labs, LLC.
Fixed
dx connectanddx wakework with the awk Debian 12 and Ubuntu 22.04 install by default. That awk (mawk 1.3.4) has no{n}repeat count in a pattern, so dx never recognized a device, a transcript, a session open on another device or one to reopen: connect sent nothing and wake found nothing. A second mawk quirk would then have made every push send each session's details again; that is fixed too.- dx runs with busybox awk (Alpine and other small systems). busybox read a few lines of dx as calls to functions that do not exist ("Call to undefined function"): the resume and fork lists and device sync failed, and
dx connect pair,joinanddx feedbackprinted the error. - A name, group label or folder path whose bytes are not UTF-8 no longer breaks dx on a Mac. macOS's awk stops at such bytes when it matches a pattern, so
dx logcame out empty and device sync stopped; gawk cut the row short.dx logcolumns now line up on every system. dx feedbackworks in the bash every Mac ships (3.2). It stopped with "unbound variable" before sending, so a note could not be sent from a stock Mac, and a title with an accent, a dash or the ellipsis of a long first line reached the maintainer as bytes that are not UTF-8.- A device you pair or join gets your sessions right away, even while another send is running. dx skipped its own send when one was already going, and the one going had not heard of the new device, so the sessions waited for some later push. Pairing now waits for it (and says so after two seconds), and tells you when the sessions have to follow later; joining no longer says "Sent N sessions" when it sent nothing.
- A device whose sync hook had been switched off, or whose hook setup failed, could silently stop receiving from your other devices. dx now turns the hook back on, checks that it took, and says so if it can't.
dx uino longer leaves out the chat of a session whose folder has a dot or a space in its path.- dx reads a store file saved with Windows line endings or a BOM.
dx tidyno longer stops on a commit with a regex character in it.dx wakeon macOS read the wrong number for the last boot.
Notes
dx sessions --jsonand the--jsonresults are dx's own JSON: dx's own tools read them, and they may change until 0.13.docs/CONTRACT.mddescribes dx from a script: thedx sessions --jsondocument, the exit codes, the--jsonresults and the rule that dx never asks a question without a terminal.
0.11.13
Fewer places to trust.
Changed
dx connect installchecks rsntr against a hash pinned inside dx. It used to fetch the expected hash from the same GitHub release as the download, so anyone who could replace the release's files could replace both. The hashes of the five rsntr 0.2.1 files are now in dx itself, covered by the signed dx release, and a file that doesn't match is refused before anything is unpacked.DX_RSNTR_SHA256names a different hash to expect, for a mirror that holds another build.- dxcli.com and
dx uino longer load fonts from Google. Inter and JetBrains Mono (SIL Open Font License) are served from dxcli.com's own files, and the dx ui page embeds them, so neither page asks any other host for anything, and Google no longer sees your IP address when you open them. The pages look the same. - The key fingerprints are published on a second site. The README, the docs page and SECURITY.md point to axiomdxlab.com/security, so a first install can be checked against something other than dxcli.com.
0.11.12
Releases are signed, and the installer checks them.
Added
- The installer checks what it downloads.
install.shfetchesSHA256SUMSfrom the same site and stops, before it unpacks anything, if the tarball doesn't match its line in the list, so a corrupt or truncated download can't install.DX_SKIP_VERIFY=1skips the check, for a mirror that doesn't carry the list. - Releases are signed.
SHA256SUMShas an OpenSSH signature,SHA256SUMS.sig, from one of two keys listed inrelease-keys, which now ships in every tarball. An install keeps those keys as~/.dx/release-keys. From then on the installer anddx updatetake a release only if its list carries a good signature from one of them, so a taken-over dxcli.com can't get a swapped installer or tarball past an install that has the keys.dx updatealso checks the installer against the signed list before it runs it. - Verify a release by hand. The README and the docs page ("Verify a release") give both keys, their fingerprints and the
ssh-keygen -Y verifycommands. The very first install still trusts dxcli.com once, because there are no keys to check against yet; verify the release yourself to avoid that.
Changed
- Once keys are pinned,
dx updateand the installer needssh-keygen(OpenSSH 8.0 or newer). Git for Windows, macOS and current Linux have it. Without itdx updatesays so and stops;DX_SKIP_VERIFY=1goes ahead anyway.
0.11.11
Fork any session by name, snapped or not.
Changed
dx fork <name>anddx resume <name>find a session you never snapped. They only looked among your snaps, sodx fork dx-soc2said "no session matching" for a Claude session thatdx snap dx-soc2found a second later. When no snap matches, they now look through Claude's sessions the waydx snap <name>does (this folder first, then every folder), show what they found, and askSnap it and fork it? [Y/n]. Enter snaps it and carries on;-yskips the question; with no terminal to ask, dx prints thedx fork -y …command instead. A session from another folder is recorded as that folder's, the same asdx snaprecords it, and a name shared by sessions in different folders is listed for you to pick by uuid, never guessed.- A session you snapped and later renamed in Claude is found by its new name, without asking.
- Your first
dx resume <name>ordx fork <name>works before you have snapped anything.
Fixed
- Sessions the commit hook starts no longer inherit git's hook environment. Git runs hooks with
GIT_DIR,GIT_INDEX_FILEand the commit's author and date set, and an agent session started from the hook kept them: its git commands acted on the committing repo whatever folder it was in, and its own commits carried that commit's author and date. dx updatelinks the release notes at their new home, github.com/Axiom-DX-Labs/dx.
0.11.10
A note to the maintainer, in one command.
Added
dx feedback <note>— tell the maintainer something in one command: no account, nothing to install, no form.dx bug <note>anddx idea <note>say which kind it is; baredx feedbackasks for one line;dx feedback < notes.mdsends a longer note. Along with the note go the dx version, OS, bash and Claude Code versions and the terminal — the line printed before sending is exactly what is attached; never paths, names or sessions.--baresends the note alone,--dry-runshows the whole issue and sends nothing.- It always lands somewhere. The note goes to a small relay (
feedback.dxcli.com) that files it as an issue in the dx repo. If the relay cannot be reached it waits in~/.dx/feedback/outbox/and a detached worker retries for a few minutes. The next baredxsays when a note went through and gives waiting ones another try;dx feedback --retrysends them on demand. - Limits: a note can be up to 16 KiB, and one address can send six notes per ten minutes. Nothing is sent unless you run
dx feedback.
0.11.9
Call a group what you call it.
Added
dx project,dx tenant,dx herdanddx bucketare aliases fordx group, and so are the plurals (dx groups,dx projects,dx tenants). Bare, they list the groups.- The flags take the same words. In
dx log,--projectand--tenantwork as--group,--projectsand--tenantsas--groups, and--by-projectand--by-tenantas-g.dx colortakes--projectand--tenantfor--group. A missing value now names the flag you typed.
0.11.8
A maintenance release.
Unchanged
- Every command works as it did in 0.11.7: internal changes only.
0.11.7
The session viewer knows your session names.
Changed
dx uishows and finds sessions by name. Every row and chat view was titled by its git branch, and the search box never looked at names, so a session you knew by its name (the onedx logand the picker show) could not be found by it. A named session is now titled by its name with the branch beside it, and typing part of the name finds it. Unnamed sessions look as before.
0.11.6
The session viewer loads every history again.
- Fixed:
dx uicame up blank. The viewer inlines your sessions into a script block, and a browser ends a script at the first "</script" it meets — even inside a transcript that quotes HTML. Such a history showed an empty list, a syntax error in the console, and fragments of transcripts spilled across the page. The data now goes out with every "<" escaped, which reads back as the identical text.
0.11.5
A quieter install and update.
Changed
- The install is a handful of lines. It says what it is downloading, where it put it, and ends with one line:
ready. run 'dx' to get started.The detail that used to scroll past (platform detection, a temp "Source" folder, "Files copied", "Directory ready") is behindDX_VERBOSE=1. If~/.local/binis not on your PATH or Node is missing, the warnings come before the last line and it says "almost there" instead of "Done!", because dx would not run yet. The PATH hint names the right profile file for your shell. dx updatesays what it is doing, then the result, in the style ofherdr update:checking for updates... already up to date (0.11.5)An update prints
updating 0.11.4 to 0.11.5...andupdated. what's new: <link>. The installer no longer repeats its own ceremony inside an update, and no longer tells someone who just randx updateto rundx updateanytime.dx update --verboseshows the installer's detail.- Version numbers in these messages drop the leading
v, to matchdx version.
Fixed
dx update 0.0.1, a version that does not exist, printed a wall of gzip and tar errors. It now says that version is not available for your platform. An installer that cannot be reached sayscould not reach dxcli.com. dx 0.11.4 is unchanged.
Notes
- Anything that parses the old
==>lines of the installer should useDX_VERBOSE=1for the detail, ordx versionfor the version.
0.11.4
Windows receives again, and sends faster.
Fixed
- Windows stopped applying what its other devices sent, from 0.10.1 until now. The receive that the node's hook starts in the background was run through bash whenever
dxhad no.exe. An install can hold the compiled program under both names, bash refuses to run it, and the receive died the instant it started. So did the share-knock worker. Other devices showed as "seen days ago", their sessions and presence never arrived, and a new friend'sdx shareonly worked while its terminal stayed open. dx now decides by what the file is, not what it is called. If your Windows device is behind, rundx update, thendx connect _recvonce to apply what is waiting. - One attachment that cannot be fetched no longer freezes everything behind it. Receive stopped at such a message and every later one, presence and renames included, waited for as long as the sender stayed unreachable. It is still held back, but only for three passes over ten minutes. Then it is dropped, the rest flows, and the sender is asked, at most once an hour per session, for a fresh full copy. A dropped copy is never applied late over something newer.
Faster
- Sending to several devices on Windows pauses the node once, not once per device. Importing an attachment there means stopping the node and starting it again, about 9 seconds per send. A push now does that once, and again only after every 20 sends so a big backlog never keeps the node down for long. Ctrl-C brings the node back first. Each send also skips a helper start it did not need.
- A device not heard from for a day gets only the small record. Its transcripts used to pile up in an outbox that expires, and each one cost a node pause. The full copy follows once the device is heard from again.
dx send <session> <device>always sends everything.DX_CONNECT_OFFLINE_AFTERsets the limit in seconds and 0 turns it off. dx connect joinanddx connect pairshow what they are doing. They used to go silent while sending your sessions to the new device. They now say how many and show a counter.
Notes
DX_CONNECT_DEFER_TRIESandDX_CONNECT_DEFER_SECSchange those limits; the bookkeeping lives in~/.dx/connect/deferred.tsv.
0.11.3
Resume opens fast on Windows.
dx resume,dx forkanddx dropopen their picker in about a second on Windows (measured 27s → 0.9s on a 296-session store). Deciding which sessions belong to the current folder ran as a bash loop that started several processes per session — about 50ms each on Git Bash — and the same loop existed in five places. It is now one awk pass applying the same four matching rules, and the open-sessions refresh no longer blocks the picker on a terminal (scripts still get a settled ledger).- Fixed: a
"or\in a branch name made the picker fail to start, and rows missing a session id showed up as blank picker entries.
0.11.2
Snap a session from any folder.
dx snap <name>works from any folder. If no session in the current folder matches the name or uuid, dx looks through every folder Claude has sessions in, shows where it found one, and snaps it after a yes — Enter accepts,-yskips the question, and with no terminal to ask dx won't snap it and prints thedx snap -y …command instead (a snap also goes to your paired devices). The snap records that folder's repo, branch and commit, as if you had run it there; a session whose folder was deleted is recorded by path, and one started in a subfolder of the current repo needs no confirmation.- dx never guesses between folders: the same name on different sessions in different folders is listed for you to pick by uuid. A session
dx resumelinked into several folders counts once, as its newest copy. - Fixed: a snap target found in the folder's path snapped an arbitrary session. The uuid-fragment match ran over each transcript's full path, so
dx snap dxinside~/…/dx(ordx snap .) matched every session and silently snapped whichever sorted first. Fragments now match session ids only, literally; an id fragment several sessions share is an error listing them, unless one session's exact name settles it.
0.11.1
One color for a whole project.
dx color --group <group> <color>colors every session in a group at once. Each member gets its own color, sodx wake, replication to your devices,dx shareand.dxsessionbundles behave exactly as for a session colored by hand.--clearclears them all;dx color --group <group>lists the members and their colors. Membership is whatdx log -gshows (snaps and claimed autos); a session added to the group later is not recolored until you run it again.- Plain
dx color <name> <color>also accepts a group name when no session matches it — a session always wins a name clash, and--groupforces the group. A miss on both now saysno session or group matching. dx log --uuidsprints just the uuids of the listed sessions, one per line, honoring every filter — for scripting.
0.11.0
Sessions by project.
dx group <session> <group>— put a session in a project group. Every session already belongs to one: by default the repo it was snapped in (the same namedx logshows under REPO), so twenty sessions fall into six projects with no setup; a label moves a session elsewhere — two repos into one project, or one repo split into several.dx group <session>shows its group,--clearreturns it to its repo's group, and baredx grouplists every group with counts.dx log -ggroups the listing under one header per group, newest activity first;--group <g>shows one group (case-insensitive);--groupsprints one line per group with its session count and last activity. All combine with-t,-rand-n.- Wherever names and colors go, groups go too.
groups.tsvmerges withdx sync, replicates to your devices overdx connect, rides along withdx send,dx shareand.dxsessionbundles, anddx drop/dx tidyclean it up. The resume picker shows a#groupbadge on labelled sessions and searches by group. Grouping an auto session claims it, like naming or coloring it.
0.10.1
Share works from Windows.
Fixed
dx shareand whole-session sends from a Windows machine never left it. rsntr 0.2.1 has no control socket on Windows, so sending a transcript as an attachment (chat send --file) found the blob store locked by dx's own serving node and failed.dx sharestill said "sending…" and waited ten minutes for an acknowledgement that could not come, and the same failure silently kept whole sessions from replicating from Windows to your other devices. dx now pauses its node for the import (a couple of seconds offline; peers retry on their own) and starts it again — one pause per attachment.- A failed send is reported.
dx shareprints✗ could not send to <friend>: <reason>and the retry command — the friend is a contact by then, so no new code is needed.dx share <session> <friend>exits 1 with the reason. rsntr's error text is on its stdout, which dx used to discard;connect.lognow keeps it. dx connect statuson Windows reported the node as not running while it was.- A friend who received from you before can redeem a new share string. Their node is admitted by yours, so a second knock is answered on the spot and never reached the owner:
dx receivewaited five minutes anddx shareten, with nothing in between. The code now travels as a message when the knock comes back pre-admitted, and the sharer redeems it the same way. - A transcript from a peer that restarted meanwhile now arrives. When the sender's node came back on new ports (a Windows sender does that for every attachment; LAN-only mode has no relay to find it again), the receiver kept dialing the old address, and the hello that carried the new one waited behind the very message it was needed for. A blob that cannot be fetched now looks ahead for the peer's newer ticket and tries once more before deferring.
- Windows: a brand-new device received nothing until its node was restarted. Hooks registered after the node started were not seen by it; a fresh node now gets its hooks before it starts.
- Windows: a dropped session's transcript that another process had open at that moment is now deleted after a short retry rather than left behind.
Notes
- Windows: a share knock that arrives through the node's hook is handled by a detached
dx connect _knocksworker, since pausing the node cannot happen inside its own hook.docs/rsntr-feedback.mddescribes what an rsntr-side fix would look like.
0.10.0
A session for a friend.
Added
dx share <session>— hand one session to someone else who has dx. It prints a share string (good for 24 hours, once); your friend runsdx receive <string>and gets the session with its transcript, thendx resumecontinues it as their own fork: the received transcript stays as received, their continuation gets its own id, and sharing back never collides. Before anything leaves, dx shows what goes (name, size, messages, repo) and asks — a transcript can quote file contents and secrets.- Contacts. The first share pairs you as contacts; later shares are
dx share <session> alice, no code. A contact is never a device: no introductions, no presence, no replication, and nothing they send but a share is ever applied here.dx share list,dx share forget <who>. dx share <session> --filewrites a.dxsessionbundle (row, name, color, transcript) for email, chat or a USB stick;dx receive <file>imports it. No node needed on either side.- A received session is yours: it replicates to your own devices,
dx logand the picker show who shared it, and the prompt mentions new arrivals once. - Share is for people, not for your own devices — those already get every session.
dx receiverefuses a string from one of your paired devices on the spot and points atdx send, instead of waiting in silence and leaving a stray contact behind;dx sharesays the same on screen if such a device knocks. - Fixed:
dx shareon Linux and WSL printed astatfilesystem report and aninteger expression expectederror before the confirmation prompt. Finding the newest transcript tried BSDstat -ffirst, which on GNU systems means filesystem-stat; it now usesstat -cfirst and falls back to BSD on macOS.
Notes
- Wire: a
sharemessage from a contact carries the row and the transcript as a verified attachment; the receiver answersshare-ack, which is whatdx sharewaits for. Share codes are single use with a 24-hour life; the node hook handles the knock, sodx sharedoes not have to stay open.
0.9.0
Your devices, connected.
Added
dx connect— pair your own devices into a network; every snap, rename, color and drop then replicates to all of them, peer to peer, with no repo or account in the middle. The transport is rsntr: an encrypted QUIC node per device (iroh), whichdx connect installdownloads for your platform, sha256-verified, into~/.dx/bin. Pairing is one paste:dx connect pairon a device you already have prints a string,dx connect join <string>on the new one — and every device already in the network is introduced to it automatically.dx connectlists devices (online/offline, last seen, sessions, what is open where);name,forget,statusandstopdo what they say.- Live mirroring. Sessions open on a device are mirrored to the others as they grow — whole lines only, small tails inline, big ones as verified attachments — and show as type
liveuntil they are snapped.dx resumeof a session from another device works like a synced one, and the device where a session is open owns it while it is open. dx send <session> [device]— push one session now, to one device or to all;--fullresends from scratch.- Presence.
dx connectshows which sessions are open on each device right now. - Device-aware surfaces.
dx loggains a DEVICE column once a session from another device exists, plus--device <name>and-t live; the resume picker shows an@devicebadge and searches by it;dx uigets a Device filter and reads synced transcripts fromblobs/, so a session from another device opens in the viewer. - The sync daemon carries peers.
dx sync enablenow runs on paired devices alone — a git target stays optional;dx sync statuscounts them. Each push cycle sends what changed, each pull tick receives and reports presence. Without the daemon,dx snap,dx drop,dx coloranddx sendpush on the spot, and the rsntr message hook receives the instant something lands, with no dx process running.
Notes
- rsntr is at 0.2.1 and can only serve detached on unix: Windows (Git Bash) is best-effort in this release — dx runs the node as a foreground child and polls for messages on daemon ticks.
~/.dx/nodeholds this device's private key: never copy it to another machine, never put it in a synced folder (dx refuses iCloud/Dropbox/OneDrive paths). It is not part ofdx sync.~/.dx/data/origin.tsv(which device a session came from) is a uuid sidecar likenames.tsv, sosessions.tsvkeeps its 8 columns. rsntr 0.2.1 has no blob garbage collection: the sending node's store keeps every full session copy it ever sent.- The design, the wire format and the ownership rule are in
docs/CONNECT.md.
0.8.4
Snap by name.
dx snap <name>snaps a session by the name you gave it with/rename— the same name Claude prints inclaude --resume "<name>"when a session exits. A uuid (or any fragment of one) still matches first; then names, case-insensitively: an exact name wins (the newest session if several share it), a partial name is accepted only when it matches a single session, and an ambiguous partial name lists the candidates instead of guessing.- A target that matches nothing now says so explicitly:
no session matching '<target>' found (by uuid or name).
0.8.3
Snap-first views.
dx logshows your own snaps by default. The per-commit auto sessions the hook records are behind-t auto;-t allshows everything. New TYPE and NAME columns, and REPO/BRANCH now mean what they say: auto sessions record the real branch at commit time, non-git sessions show<path> (folder)with-for commit and branch, and old auto rows that stored the commit slug in the branch field display it under NAME instead.- The resume picker opens on your snaps too.
Ctrl+Tcycles snaps → all types → autos; the footer counts what's hidden. Naming an auto session (Ctrl+Rin the picker) or coloring it (dx color) claims it — it then counts as one of yours. A search that matches nothing in the current lens quietly widens to all types, so filtering never dead-ends. dx tidy --older-than 90dprunes old auto sessions — rows, names, colors, and synced blobs, each tombstoned so a later sync can't resurrect them. Snaps and claimed autos are never candidates, and Claude's transcripts under~/.claudeare never touched.--dry-runpreviews,-yskips the prompt.- Auto sessions now keep their commit slug as the session name and record the real branch in the branch column.
0.8.2.1
Non-git snap fixed on Windows.
- Fixed: session commands in a non-git folder on Windows. On Git Bash,
dx snap(and resume, fork, drop,log -r) in a folder that isn't a git repo always failed withno Claude sessions found for this repo.— dx keyed the folder by its MSYS path (/c/Users/...) while Claude Code, a Windows process, keys its project dir by the Windows path (C:/Users/...). The folder identity now uses the Windows form. macOS, Linux and WSL are unchanged. - Fixed: silent exit when a snap target matches nothing.
dx snap <target>with a target that matches no session exited with no output at all; it now printsno session matching '<target>' found.
0.8.2
Session colors.
dx color <session> <color>— pin a tab color to a session (a palette name likeblue/tan, or#rrggbb);dx color <session>shows it,--clearremoves it, baredx colorlists the palette and every colored session. Colors live in~/.dx/data/colors.tsv(uuid → hex) and sync across devices with the same union merge as session names;dx dropcleans them up.dx wakereopens colored sessions colored. Windows Terminal tabs get--tabColor; iTerm2 tabs get the color via iTerm's OSC 6 sequence from inside the tab. Terminal.app has no tab colors. Colors you set through the terminal's own UI are not captured — pin them through dx and they survive wakes, reboots, and machines.- Only a strictly validated lowercase
#rrggbbis ever stored, and it is re-validated at every point of use before reaching an argv or an escape sequence.
0.8.1.2
Build provenance in the banner.
- Packaged builds stamp the short commit hash into
dx version—dx 0.8.1.2 (wake) [abc1234]— so a bug report pins the exact commit an install was built from. Display-only: nothing parses it, and the version machinery is unaffected. Dev checkouts show no ref (honest: they aren't a published build); a "+" suffix marks a build from a dirty tree.
0.8.1.1
Four-segment versions.
- Versions may now carry an optional fourth segment (
X.Y.Z.W) for small same-patch respins. Unlike the retired "build N" suffix — whichdx updatecould not see, so rebuilds needed--force— the fourth segment is part of the version proper:dx updatetreats0.8.1 -> 0.8.1.1as a normal forward update, and the weekly update nudge announces it. No parser changes were needed: the version machinery (update, nudge, installer, build script) already accepted dotted tails; this release just starts using them. The version string drops the build suffix:dx 0.8.1.1 (wake). dx updatenow says how to reinstall the same version. The "already up to date" no-op mentionsdx update --force, so the escape hatch is discoverable at the moment it's needed.- Supersedes 0.8.1 build 2 and carries its wake-tab transcript relink.
0.8.1 build 2
Wake relinks transcripts before resuming.
dx waketabs no longer fail with "No conversation found" for sessions whose recorded folder differs from their launch folder. Claude scopes--resume <id>to the current folder's transcripts, but a session started in folder A that moved into a worktree (e.g. a Claude-harness worktree under.claude/worktrees/) records the worktree as its cwd — so the transcript lives under A's project dir and the resume died in the freshly opened tab._wake-tabnow relinks the transcript into the recorded folder's project dir before launching claude — the same find-and-copydx resumehas always done — covering moved sessions, harness worktrees, and synced-in sessions alike. Found live on macOS during the 0.8.1 release verification; the hold-open-on-failure tab is what made it visible.
0.8.1
Your sessions survive the reboot.
Added
dx wake— reopen the Claude Code sessions that were open before a reboot, a crash, or an accidentally closed tab. Each one comes back in its own terminal tab, in its own folder, resumed where you left off. Alias:dx restore.- Session ledger — dx now remembers which sessions are open while it runs. It reads Claude Code's process registry (
~/.claude/sessions/) and records the live, interactive ones to~/.dx/run/live-sessions.tsv. The scan is cheap and silent, and happens on every commit (via the dx hook), on baredx, ondx snap/dx resume/dx fork, on each sync-daemon tick, and on demand withdx wake --scan. - Terminal adapters —
dx wakeopens tabs using whatever you're in: tmux, Windows Terminal (all tabs in one atomic launch), iTerm2, or macOS Terminal. Inside VS Code — which can't be scripted to open terminal tabs — and anywhere else, it prints ready-to-paste commands instead. Force one with--terminal <t>orDX_TERMINAL. - Wake flags —
-y/--yesto reopen everything without asking,--listto look without touching,--dry-runto see the exact commands,--since <dur>to widen or narrow the window (default 72h),dx wake <n>to reopen just one. - Post-reboot hint — once per boot,
dxmentions how many sessions are waiting to be reopened.
Changed
- The sync daemon refreshes the session ledger on each pull tick, so with
dx sync enablerunning the list is never more than ~30s stale.
Notes
dx wakereopens sessions, not window layout — tabs and their conversations come back; pane geometry and scrollback do not.- The ledger lives under
~/.dx/run/and is never synced — your project paths and session names stay on the machine that recorded them.
0.8.0 build 2
Snap anywhere, plus a critical installer fix.
install.shno longer silently aborts on macOS/Linux.detect_platform's last line was a bare[ "$os" = "windows" ] && BIN_NAME="dx.exe"; on any non-Windows host the test is false, so underset -euo pipefailthe&&-list returns 1, and as the function's final command that becomes its exit status — aborting the whole installer with zero output and nothing downloaded. Every 0.8.0 build 1curl -fsSL https://dxcli.com/install.sh | bashon macOS/Linux was a silent no-op. It's now anif-statement, so the non-Windows path always returns 0.install.shlocal installs exit 0 again. Sameset -eclass, in the EXIT trap:cleanup()'s only line —[ -n "${CLEANUP_DIR:-}" ] && rm -rf …— returns 1 when nothing was downloaded, and a failing EXIT trap overrides the script's exit status.bash install.shfrom a checkout or extracted tarball (README methods #2/#3) exited 1 right after printing "Done!", breaking anything that checks the exit code.curl | bashwas unaffected (the download path setsCLEANUP_DIR).cleanupnow ends withreturn 0.dx snap/resume/fork/drop/log -r/uinow work outside a git repo. A session taken in a plain (non-git) folder is keyed by its absolute path — the same identity Claude Code uses for~/.claude/projects/<mangled-path>— with empty commit/branch/remote insessions.tsv.resume/dropscope to the folder by exact path (plus the existing JSONL-in-project-dir fallback);forkforks the session without cutting a branch and says so;log -rfilters to the folder. Behavior inside a git repo is unchanged.enable/disable/initstill require git — hooks are meaningless without it. Because these rows carry empty middle columns, everywhile readoversessions.tsvnow goes through a\x1freflow first — tab is IFS whitespace, so consecutive tabs would otherwise collapse and shift every later field (uuid into the agent column, etc). Anddx snaprefuses a folder path containing a literal tab or newline rather than write a corrupt TSV row.
0.8.0
Continuous sync.
Added
dx sync enable— start a background daemon that watches~/.dx/data/and~/.claude/projects/and pushes changes to the configured sync target. Defaults: 10s push debounce, 30s pull interval, overridable via--push-debounce Nand--pull-interval N. Intervals are persisted to~/.dx/run/sync.conf.dx sync disableanddx sync status— stop and inspect the daemon. Status shows PID, target, last push/pull timestamps, configured intervals, and last error.dx sync trigger— tell the running daemon to do an immediate push+pull, bypassing debounce and interval. Silent no-op if no daemon is running, so it's safe to wire into git hooks unconditionally.- Hook integration —
dx enablenow installs both apost-commithook (existing behavior: auto-snap sessions on commit) and apre-pushhook. Both nudge the auto-sync daemon viadx sync triggerso your latest commit and its session ride along with the very next sync cycle instead of waiting for debounce.dx disableremoves both hooks. Pre-existing hook content is preserved. - Aliases —
dx watch/dx unwatch/dx watch-statusanddx auto-sync on|off|statusall dispatch to the same handlers. - Squash-push transport — the daemon force-pushes a single orphan commit per cycle so the sync repo never grows beyond one commit. Manual
dx sync pushis unchanged. Periodicgit gc --prune=nowevery 50 pushes keeps the local clone small. - Cross-platform file watcher —
inotifywaiton Linux,fswatchon macOS, pure-bash polling fallback on Git-Bash / MSYS / Linux-without-inotify-tools / macOS-without-fswatch. DX_WATCHERenv var forces a specific watcher (inotify,fswatch, orpoll) regardless of what's on PATH — useful for testing and for opting out of native watchers on a system where they misbehave.
Changed
- Constants moved together near the top of the script;
BLOBS_DIRis no longer defined mid-file. - New state directories
~/.dx/log/and~/.dx/run/are created on demand and safe to delete at any time.
Fixed
dx resume/dx forkwith an all-digit UUID prefix (e.g.dx resume 1111for session1111abcd-…) no longer misreads the argument as a list index and fails — index resolution falls back to prefix and name matching before giving up.- Cold-start
dx resume <session>on a fresh device no longer exits silently when~/.claude/projectsdoesn't exist yet — the session is restored from synced blobs as intended.
0.7.5
Quiet update nudge.
Added
- Tip in install.sh. A single trailing line —
Tip: run 'dx update' anytime to pull the latest release.— now follows the existing "Done!" message at the end of every install. Pure discovery, no state file, no network call. Update availability nudge at the bottom of
dx(no args) anddx version. Parses${DX_VERSION:-X.Y.Z}out ofhttps://dxcli.com/install.sh(the same trickdx updateuses — no separate/latestendpoint, no Render rewrite-rule exception), at most once every 7 days. Caches the result in$DX_HOME/.latest-knownplus a$DX_HOME/.last-update-checktimestamp. When a newer version is published, prints one line to stderr:dx 0.7.6 is available — run 'dx update' to installSilent on every failure mode: no curl on PATH, network error, malformed response (a strict semver-shape
[0-9]*.[0-9]*.[0-9]*check drops HTML / error pages / truncated downloads), current already ≥ latest (sort -Vhandles preview/dev installs correctly).DX_NO_UPDATE_CHECK=1env var disables the check entirely.DX_INSTALL_URLbeing set also skips it (preview installs shouldn't be told the production version is "available").
Why it's quiet by design
The git post-commit hook (dx hook-run), the snap/resume/fork/drop flows, and the table/sync commands (dx log, dx sync, dx ui) all skip the check by design — it only appears on the two attentive-but-non-task surfaces where a single trailing line is on-topic.
Build 2 — resume / fork / hop stop failing with Argument list too long
- The interactive picker was handed the entire sessions JSON as a
nodecommand-line argument. Once you'd accumulated enough snaps, the blob exceeded the OSARG_MAXlimit and the picker launch died withnode: Argument list too long(E2BIG) —dx resume(and thefork/hopaliases that share the picker) printed the error and cancelled before the picker could open. The sessions JSON is now written to a temp file and the path is passed instead, so the size of your session history no longer matters.picker.jsaccepts either an inline JSON array (backward compatible) or a path to a file holding it.
0.7.4
In-place update.
Added
dx update— re-runs the official installer in place so you can upgrade without remembering the curl one-liner. UX patterns synthesized from a survey of brew, gh, rustup, deno, bun, uv, mise, and atuin:- No-op short-circuit. If you're already on the latest published version,
dx updateexits withdx is already up to date (v0.7.4)— no wasted download. Reuses the version embedded ininstall.shas the source of truth, so no separate/latestendpoint is needed and preview installers carry their own version naturally. - Version delta in the framing. A forward update prints
Updating dx: v0.7.3 -> v0.7.4...so you see exactly what's about to change. - Pin / downgrade.
dx update 0.7.2(alsodx update v0.7.2) installs that exact version. Useful for pre-1.0 rollback. The framing flips toInstalling dx v0.7.2 (current: v0.7.4)...so the intent reads as install-this-specific-version, not "newer is better". --force/-fbypasses the no-op short-circuit to repair a broken install.- Release-notes link. After a successful forward update against the production source, prints
release notes: https://github.com/ghgugle/dx/releases/tag/v0.7.4on its own line. Suppressed for pinned versions and preview installs. - Pairs naturally with
dx _admin preview <N>from 0.7.3: try a PR preview build, thendx updateback to the official release.
- No-op short-circuit. If you're already on the latest published version,
DX_INSTALL_URLenv var overrides the installer source (defaulthttps://dxcli.com/install.sh). Useful for installs from a Render preview, and used internally by the test suite to mock the installer without hitting the network.
Build 2 — install.sh stops deleting the new dx.exe on Windows
install.sh's Windows cleanup was deleting the binary it had just written. On MSYS, when onlydx.exeexists,rm -f dxauto-resolves todx.exe— so the cleanup intended for the stale extensionless shim from pre-0.7.3 installs was actually shooting the freshly-installed binary in the foot.link_binarythen crashed withcp: cannot stat $DX_HOME/dx.exeandset -eaborted, leavingwhich dxpointing at the old version. Bothrm -fcalls ($DX_HOME/dxand$BIN_DIR/dx) are nowfind -maxdepth 1 -type f -name "dx" -delete, which matches filenames literally and never auto-resolves. The first Windows install from 0.7.4 build 1 worked because a real staledxstill existed; every subsequent upgrade silently failed. Build 2 fixes it.
0.7.3
Install builds from deployment previews.
Added
dx _admin preview <N>(aliaspreview-<N>) — install the dx build from a Render PR preview deploy. Resolveshttps://dx-pr-<N>.onrender.com, then runs that preview'sinstall.shwithDX_BASE_URLpointed back at it, so the install pulls exactly that PR's build with no dxcli.com round-trip and no Render dashboard config.--dry-runprints the resolved command without installing.DX_BASE_URLininstall.sh— overrides the tarball download base (defaulthttps://dxcli.com), so installs can target a preview or mirror.
Fixed
- Windows install replaces
dx.execorrectly.install.shwas copying$src/dxeverywhere, but the Windows tarball shipsdx.exe. MSYS quietly auto-resolved the source-side filename, so~/.dx/dx.exewas getting written — butlink_binarythen propagated the stale extensionless~/.dx/dxfrom prior installs onto~/.local/bin/dx, andwhich dxreturned the old version even after a "successful" upgrade. install.sh now picks the right binary name per platform (dxvsdx.exe) for every cp/chmod/exists-check, and deletes stale extensionless shims left behind by older installs.
Notes
_adminis a hidden developer/maintainer namespace, omitted from the main help output.- Provider URL resolution is factored out so non-Render preview hosts can be added later — see ROADMAP.md.
0.7.2
Resume finds sessions opened in a different repo.
Fixed
dx resume/dx fork/dx dropnow match by JSONL existence when the row's stored repo doesn't match the cwd. If you open a session in repo B that was originally auto-snapped in repo A (Claude writes the JSONL into B's project dir onclaude --resume), dx now surfaces that session as "current" in B. Previously the row's stored remote was checked against B's remote, didn't match, and dx reported "no sessions found for this repo" — whiledx snapin the same folder happily said "already snapped". One symptom, two commands giving opposite answers; the JSONL existence check resolves it.
Unchanged
- The existing match priority — git remote URL → cwd basename — is preserved. JSONL existence is a tertiary fallback, so on a clean install where every session is in its original repo, nothing about resume changes.
0.7.1
Resume sessions across repos.
Added
dx resume -a/--all— open the picker (or resolve a numeric index) across every saved session, not just sessions from the current repo. Use this to pick up a Claude conversation started in repo A while working inside repo B. The picker opens pre-toggled to all-projects mode;Ctrl+Astill toggles it back.dx fork -a/--all— same flag ondx forkfor parity. Branch any saved session into a fresh one without first switching directories.
Changed
- When the picker has no current-repo matches, the error message now suggests
dx resume -a(ordx fork -a) instead of stopping cold.
0.7.0
Session forking.
Added
dx fork [id]— branch any saved session into a fresh one without touching the original. Wrapsclaude --resume <uuid> --fork-session, so the original UUID stays intact and Claude assigns a new ID to the fork. Reuses the same picker, numeric-index, and partial-UUID resolution asdx resume.dx branch— alias fordx fork.
0.6.0
Internet-based session sync via private git repo.
Added
dx sync setup— one-step sync configuration. Auto-detects theghCLI, creates or reuses a private<user>/dx-sessionsGitHub repo, and writes the target to$DX_HOME/config. Falls back to a prompted git URL for users withoutgh.- Git-repo transport for
dx sync push|pull— treats a private git repo as a free, store-and-forward relay across devices. Reuses the existing TSV union-merge and tombstone logic; git is only the transport. Supports HTTPS and SSH URLs on GitHub, GitLab, Bitbucket, Codeberg, and any self-hosted git. - Global sync config —
sync=<url>in$DX_HOME/config, checked betweenDX_SYNCenv var and per-repo.dx, so the relay is configured once per device.
Changed
dx sync pushon a divergent target now fetches and re-integrates remote changes before pushing, retrying once on non-fast-forward rejection.- Legacy local-path and rsync targets continue to work unchanged.
0.5.7
Compiled binary distribution.
Changed
- Binary build — dx ships as a compiled Go binary with XOR-encoded bash script, protecting source from casual inspection
- Per-platform tarballs —
dx-0.5.7-linux-amd64.tar.gz,darwin-arm64,darwin-amd64,windows-amd64 dx hook-run— post-commit hook logic merged into dx as a subcommand;dx-hook.shis now a backward-compat shim- JS minification —
picker.jsandbuild-data.jsminified with esbuild in release builds - Remote URL normalization —
dx resumeanddx lognow match sessions across SSH and HTTPS clones of the same repo (e.g.git@github.com:user/repoandhttps://github.com/user/repo) - Resume picker order — newest sessions shown first in interactive picker
0.5.6
Session management.
Added
dx drop [uuid]— remove a snapped session fromsessions.tsvandnames.tsvwithout touching the original Claude session files. Supports interactive picker or direct UUID lookup.
0.5.5
Cross-device session sync, public website, curl-pipe installer.
Added
dx sync push|pull— sync sessions and JSONL blobs to a local path (USB, NAS, shared folder) or rsync remote. Renames and updates from the push side take precedence on merge.- Resume from synced blobs —
dx resumechecks~/.dx/data/blobs/for JSONL files pulled via sync when not found in Claude projects - curl-pipe install —
curl -fsSL https://dxcli.com/install.sh | bashdownloads the tarball and installs automatically - Public website at dxcli.com — docs page, download button, no private repo references
build-public.sh— assembles thepublic/deploy folder with site files and release tarball
Changed
- Install URLs updated from GitHub to dxcli.com
DX_SYNCenv var orsync=in.dxconfig for default sync target- Copyright notice added to
dx versionoutput and site footer
0.5.0
Cross-folder and cross-OS session resume, redesigned installer.
Added
- Cross-folder resume —
dx resumenow works when resuming a session from a different clone of the same repo. The session file is automatically copied into the current project's Claude directory. - Cross-OS resume (WSL ↔ Windows) — sessions created on Windows can be resumed from WSL and vice versa. Handles the path mismatch between
C:\Users\...and/mnt/c/Users/...project directories.
Changed
- Installer redesign — styled
==>output with platform detection, version display, and structured progress messages - Remote install —
curl | bashnow downloads tarball from GitHub releases with SHA-256 checksum verification (supportssha256sum,shasum, andopenssl) - Windows binary linking — installer uses
cpinstead ofln -son MINGW where symlinks are unreliable for Windows programs - Git-clone migration — installer auto-converts old git-clone installs to file-based installs
0.4.0
Resume picker UX improvements.
Changed
- Session viewer redesigned from table to card layout with search and filter dropdown
- Ctrl+C double-tap safety check in resume picker
- Minimalistic search icon in resume picker
hop/zapaliases fordx resume, entity renamed to "snap" in picker- Responsive search, lighter focus styling, search footer in picker
0.3.0
Session viewer, snap/resume, chat history, and interactive picker.
Added
dx snap— save your current interactive Claude session (aliases:dx slap,dx yoink)dx resume— resume a saved session from any checkout of the same repo- Interactive TUI picker with search, arrow-key navigation, and scroll
- Ctrl+R to rename sessions with custom display names (persisted in
~/.dx/data/names.tsv) - Ctrl+A to toggle between current repo and all projects
- Ctrl+B to toggle branch — shows current branch badge and folder paths per session
hopandzapaliases fordx resume- Entity renamed to "snap" in picker UI ("Resume Snap", "No matching snaps.")
- Session detail line shows canonical repo name, commit, agent, type, and uuid
- Lists sessions by number, matches repos by git remote URL
- Warns if session's commit is ahead of current HEAD
dx ui— opens a local session viewer in your browser- Stats bar: total sessions, unique repos, snap count, agent breakdown
- Filterable by repo, agent, and type (snap/auto)
- Sortable columns with clickable headers
- Click any session with a chat icon to view the full Claude conversation
- Chat detail view with user/assistant messages, thinking blocks, tool calls
claude --resume <uuid>shown for easy copy- Responsive design matching the dx site style
app/template.html— self-contained HTML/CSS/JS template for the session viewerapp/build-data.js— Node script that reads sessions.tsv + Claude JSONL files, outputs JSON- Session type tracking:
snap(manual) vsauto(post-commit hook) - Git remote URL stored in sessions.tsv for cross-folder repo matching
dx log(existing) — show recent agent sessions in terminal- Canonical repo identity — sessions from different folders of the same repo (same remote URL) now group under one name in UI and stats
- Folder path shown as tooltip in UI table and as detail line in resume picker
Changed
sessions.tsvformat extended with two new columns: type (snap/auto) and remote URLinstall.shcopiesapp/directory (template + build script) to~/.dx/app/install.shcreates~/.dx/data/directory on install- Post-commit hook now records session type as
autoand includes git remote URL
How it works
dx snapfinds the most recently modified Claude JSONL in~/.claude/projects/<project>/and records itdx uiuses Node to parse sessions.tsv + Claude JSONL files, injects the data into an HTML template, and opens the resultdx resumematches sessions to the current repo by git remote URL (or basename fallback), then runsclaude --resume <uuid>
0.2.0
Multi-agent support and Entire-style install.
Added
- Multi-agent architecture: Claude Code, plus hook scripts for other coding tools
- Modular agent extensions (
agents/<name>.sh) withdx_agent_runcontract .dxconfig file for per-repo agent selection and argsDX_AGENTSandDX_<AGENT>_ARGSenvironment variable overridesdxCLI withenable,disable,initsubcommands- One-liner install:
curl -fsSL .../install.sh | bash - Custom agent support — drop a
.shfile inagents/
Changed
- Renamed from
claude-session-forktodx install.shis now a global bootstrap (installs to~/.dx, links CLI to PATH)- Per-repo setup via
dx enable/dx disableinstead ofbash install.sh - Config parsing is generic — any
<name>_args=maps toDX_<NAME>_ARGS
Removed
claude-session-fork.sh(backward compat handled by install migration)
Migration
- Repos with the old
# claude-session-forkhook guard are auto-migrated ondx enable
0.1.0
Initial release.
- Git post-commit hook creating Claude Code sessions per commit
- Deterministic UUID session IDs from commit hashes
- Slug generation from commit messages
install.shfor per-repo hook installation