Handoff transfers uncommitted Git changes between developers through a small self-hosted server. The server does not need repository access, GitHub credentials, or a copy of the codebase. The same binary works as the server and the client.
Developer A Handoff server Developer B
handoff push ── package ──> stores package ── ID ──────> handoff pull ID
│
local Git changes
(no final commit)
- One command to upload changes and one command to apply them.
- Interactive, staged-only, worktree-only, exclusion, and dry-run push workflows.
- Repository-scoped team inbox with sender, branch, message, and file summary.
- Native VS Code Source Control drafts with multi-repository management.
- Optional per-user tokens, private recipients/teams, assignment, comments, lifecycle state, revoke, read/archive state, and audit history.
- Transfers tracked, untracked, deleted, staged, and unstaged files.
- Sends all changes or only selected paths.
- Uses Git's three-way merge and reports normal Git conflicts.
- Backs up existing receiver changes before applying a handoff.
- Leaves the result local and uncommitted.
- Single binary for Linux, Windows, and macOS.
- Filesystem storage: no database or repository integration.
- 100 MB package limit and 30-day retention by default.
- Receiver safety limits of 100 MB expanded changed-file content and 10,000 changed paths per handoff.
Git LFS files and submodule changes are not supported in version 1.
If Node.js 18 or newer is installed, npm can install the official CLI and the correct native binary for the current platform:
npm install -g @walid-baharwal/handoff
handoff versionThis is the same Go application as the standalone download, not a separate JavaScript implementation. Upgrade or remove it with:
npm install -g @walid-baharwal/handoff@latest
npm uninstall -g @walid-baharwal/handoffDownload the binary for your system from the repository's Releases page:
| System | Binary |
|---|---|
| Linux x86-64 | handoff-linux-amd64 |
| Linux ARM64 | handoff-linux-arm64 |
| Windows x86-64 | handoff-windows-amd64.exe |
| Windows ARM64 | handoff-windows-arm64.exe |
| macOS Intel | handoff-darwin-amd64 |
| macOS Apple Silicon | handoff-darwin-arm64 |
Install the downloaded binary system-wide (replace the filename with
handoff-linux-arm64 on ARM64):
sudo install -m 755 ~/Downloads/handoff-linux-amd64 /usr/local/bin/handoff
handoff versionRun these commands in PowerShell:
New-Item -ItemType Directory -Force "$HOME\bin" | Out-Null
Copy-Item "$HOME\Downloads\handoff-windows-amd64.exe" "$HOME\bin\handoff.exe"
[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";$HOME\bin", "User")
$env:Path += ";$HOME\bin"
handoff versionFor Apple Silicon (M1, M2, M3, or newer):
sudo mkdir -p /usr/local/bin
sudo install -m 755 ~/Downloads/handoff-darwin-arm64 /usr/local/bin/handoff
handoff versionFor an Intel Mac, use handoff-darwin-amd64 instead. If macOS blocks the
unsigned binary, allow this specific download and try again:
sudo xattr -d com.apple.quarantine /usr/local/bin/handoff
handoff versionConfigure the shared server once, then run the other commands inside a Git repository:
handoff setup --server https://handoff.example.com
cd project
handoff push -m "backend for invoice task"The sender receives a handoff ID. In another clone of the same repository, inspect and apply it:
handoff list
handoff inspect abcdef123456
handoff pull abcdef123456For path selection, previews, staged/worktree modes, inbox filters, conflict recovery, server operation, JSON output, and every flag, read the Handoff command reference.
Handoff provides a versioned JSON command interface for lightweight editor
extensions. Inbox listing, inspection, push preview/upload, pull preview/apply,
and recovery status support --json. Automated setup can pass the team token
through standard input without exposing it in process arguments:
printf '%s\n' "$HANDOFF_TOKEN" | handoff setup --server https://handoff.example.com --token-stdin
handoff list --json
handoff status --jsonSee the editor integration API for the exact stdout, stderr, exit-code, response, and error contract.
The Handoff Visual Studio Code extension provides one native Handoff Source Control provider per Git repository, persistent file/message drafts, rich diffs and statuses, a multi-repository Activity Bar inbox, safe pull previews, collaboration actions, setup profiles, and conflict recovery. It ships as a platform-specific VSIX with the matching Go binary included, so users do not need to install the npm package globally.
Install it from the Visual Studio Marketplace after the first extension release, or use Extensions: Install from VSIX... with the matching asset attached to the GitHub Release. Repository owners can follow the VS Code publishing guide to configure automated Marketplace releases.
Requirements:
- Docker with Compose.
- A public or private HTTPS URL that every developer can reach.
- A reverse proxy such as Coolify, Caddy, Traefik, or Nginx for TLS.
Clone the repository and generate a team token:
git clone https://github.com/OWNER/handoff.git
cd handoff
printf 'HANDOFF_TOKEN=' > .env
openssl rand -hex 32 >> .env
docker compose up -d --buildThe service exposes port 8080 inside its Docker network. Connect the reverse proxy for https://handoff.example.com to the handoff service on that port. Verify it with:
curl https://handoff.example.com/healthzThe Compose volume handoff_data keeps uploaded packages across restarts.
- Create a Docker Compose resource from this repository.
- Add
HANDOFF_TOKENwith a value generated byopenssl rand -hex 32. - Deploy the stack.
- Assign your HTTPS domain to the
handoffservice on port8080. - Open
/healthz, then test a push and pull between two temporary clones.
| Variable | Default | Purpose |
|---|---|---|
HANDOFF_TOKEN |
required unless HANDOFF_USERS is set |
Legacy shared administrator token, minimum 32 characters |
HANDOFF_USERS |
empty | Optional JSON array of per-user tokens, identities, roles, and teams |
HANDOFF_ADDRESS |
:8080 |
Server listen address |
HANDOFF_DATA_DIR |
/data |
Package storage directory |
HANDOFF_DOWNLOAD_DIR |
/downloads |
Client binary download directory |
HANDOFF_MAX_BYTES |
104857600 |
Maximum package size |
HANDOFF_MAX_STORAGE_BYTES |
10737418240 |
Maximum total stored package bytes |
HANDOFF_MAX_UPLOADS |
4 |
Maximum concurrent package uploads |
HANDOFF_RETENTION |
720h |
Package retention period |
Packages are protected in transit by HTTPS and access-controlled by the shared token. They are not encrypted on disk; anyone with server filesystem access can read them.
Use a dedicated, access-controlled directory for HANDOFF_DATA_DIR; do not point it at a repository, home directory, temporary directory shared with other users, or another application's data. Handoff creates, expires, and deletes files within this directory as part of normal operation.
cmd/handoff/ executable entrypoint
internal/handoff/ client, server, Git transfer, packaging, and domain tests
With Go 1.24 and Git installed:
go test ./...
go build -o handoff ./cmd/handoffOr use Docker:
docker run --rm -v "$PWD:/src" -w /src golang:1.24 go test ./...
docker build -t handoff .Fork the repository and open pull requests against sandbox, not main.
See CONTRIBUTING.md for the complete workflow.
CI runs tests on every push and pull request. Pushing a version tag builds all supported binaries, creates checksums, publishes the matching npm packages, and publishes a GitHub Release:
git tag v0.2.0
git push origin v0.2.0Repository maintainers must complete the one-time npm setup before the first npm-enabled release. See npm publishing for repository owners.
Handoff is available under the MIT License.