A changeset-oriented version control system — a Git alternative, built from scratch in Rust — with a deployable, multi-user server.
chip is not a Git clone. Its model is deliberately different:
- No staging area. There is no
add. The whole working tree is snapshotted oncommit. - Stable change IDs. Every change has a random
change-idthat persists across rewrites, distinct from its content hash (a BLAKE3commitid). - First-class conflicts. A conflicting merge never aborts — it produces a conflicted change you keep working with, then resolve with a normal commit.
- Universal undo. Every mutating command records an operation;
chip undoreverses the last one. - Stacked changes & evolution. Because change-ids are stable,
chip stackvisualizes a chain of dependent changes andchip evolutionshows a change's versions over time (acrossamend/rebase). - Content-addressed store (BLAKE3 + zstd) behind a pluggable backend: local filesystem today, S3-compatible object storage (MinIO/AWS) by config.
Coming from Git? chip import git <path> brings an existing repo's full history
(branches, tags, authors, dates) into chip.
| Crate | What it is |
|---|---|
chip-core |
The VCS engine: object store, snapshot, dag, three-way merge, oplog |
chip-cli |
The chip binary — local VCS + gRPC remote client |
chip-proto |
gRPC service definitions (proto/chip.proto) + generated stubs |
chip-server |
The server — gRPC sync + axum web UI + Postgres auth + object store |
For a deep dive into the data model, object store, encryption, sync protocol, and server internals, see ARCHITECTURE.md.
Prebuilt chip binaries are published for macOS (arm64/x64), Linux (x64/arm64,
static musl), and Windows (x64) on each tagged release — no Rust or protoc needed.
# macOS / Linux
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/koneb71/chip/releases/latest/download/chip-cli-installer.sh | sh# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -c "irm https://github.com/koneb71/chip/releases/latest/download/chip-cli-installer.ps1 | iex"Or build from source (needs Rust + protoc): cargo install --path crates/chip-cli.
Windows notes: keys live in
%USERPROFILE%\.ssh, config in%APPDATA%\chip. The SSH transport uses key files (ssh-agent integration is Unix-only); the HTTP transport works everywhere. Releases are produced by cargo-dist (.github/workflows/release.yml) on av*tag.
From zero to a synced repository (assumes a server at http://localhost:8080 —
see Server to run one):
# 1. make a local repo and a first change (no staging step)
mkdir demo && cd demo
chip init
echo "# Demo" > README.md
chip commit -m "first commit"
# 2. create an account on the server
chip register http://localhost:8080 -u alice -e alice@example.com
# 3. create the remote repo and push to it
chip repo create http://localhost:8080/alice/demo --description "My first chip repo"
chip remote add origin http://localhost:8080/alice/demo
chip push origin
# (shortcut: skip `repo create` — the first push to your own namespace
# auto-creates a private repo)
# 4. clone it somewhere else
cd .. && chip clone http://localhost:8080/alice/demo demo-cloneBrowse the result at http://localhost:8080/alice/demo.
chip init # create a repository
chip commit -m "msg" # snapshot the whole tree as a new change
chip log # history, organized by change id
chip status # working-tree changes since the last commit
chip diff # unified diff of those changes
chip bookmark <name> # create/move a bookmark (named branch)
chip checkout <name|commit> # switch and update the working tree
chip checkout -b <name> # create a bookmark at HEAD and switch to it
chip tag <name> # tag the current commit
chip show [rev] # change metadata + diff (rev defaults to @)
chip merge <name|commit> # three-way merge (conflicts stay first-class)
chip rebase <name|commit> # replay the whole branch onto a new base (keeps change-ids)
chip cherry-pick <rev> # copy one commit's change onto the current change
chip revert <rev> # new commit that undoes a previous commit
chip restore [path] # discard uncommitted changes (whole tree, or a file)
chip amend [-m msg] # rewrite the current change, keeping its change-id
chip resolve # clear resolved conflict markers (keeps change-id)
chip undo # reverse the last operation (any command)
chip op log # list recorded operations
chip stack # show the stack of changes above the trunk
chip evolution [rev] # how a change evolved across amend/rebase (its versions)
chip import git <path> [dir] # import a local Git repo's history into a new chip repo
# Remotes — HTTP (token) or SSH (key)
chip register <url> -u alice -e a@x.com # HTTP; password prompted if -p omitted
chip login <url> -u alice
chip repo create <url>/alice/proj [--public] [--description "…"] # create a server repo
chip clone http://host:8080/alice/proj # HTTP transport (bearer token)
chip clone ssh://chip@host:2222/alice/proj # SSH transport (your key)
chip remote add origin <url>/alice/proj
chip push origin [--force] # first push to your own namespace auto-creates the repo
chip pull origin # fast-forward; warns (never clobbers) on divergence
chip pull origin --rebase # on divergence, rebase local changes onto the remote
chip pull origin --merge # on divergence, create a merge commitlog, show, diff, and status have token-efficient, machine-readable modes
for AI agents (color is auto-disabled when output isn't a TTY):
chip log --oneline # one dense line per change: @ <change> <commit> Nf +A -R summary
chip log --format json # compact JSON array (change, commit, parents, author, ts, stat, summary)
chip show <rev> --stat # per-file +/- summary, no line content
chip show <rev> --name-status # A|M|D path per file
chip show <rev> --format json # structured diff summary; add --patch to include hunk line content
chip diff --format json # same, for the working tree
chip status --format json # working-tree changes as [{status, path}]Add your public key under "SSH keys" in the web UI, then use an ssh://
(or scp-style chip@host:owner/repo) remote. The CLI authenticates via
ssh-agent first (so passphrase-protected keys work), falling back to
~/.ssh/id_ed25519 (or id_ecdsa/id_rsa) — no token needed; the server maps
your key's fingerprint to your account. The server host key is pinned on first
use in ~/.config/chip/known_hosts and verified on every connection. SSH tunnels
the same gRPC sync protocol, so clone/push/pull behave identically to HTTP.
Revisions (rev) accept a bookmark, a tag, @/HEAD, or a commit id —
abbreviated ids (the 12-char prefix chip log prints) resolve against the
commits visible from refs.
There is no staging step: edit files, then chip commit.
chip amend and chip rebase rewrite a change in place — the content
(commit) hash changes but the change-id stays the same, so the change keeps its
identity in chip log:
$ chip commit -m wip # change cc7ae5… commit a1a2db…
$ chip amend -m done # change cc7ae5… commit 367eed… (same change, new commit)
The server hosts repositories, authenticates the CLI with bearer tokens, serves a web UI, and enforces per-repo access control (public/private + read/write collaborators). gRPC and the web UI are multiplexed on one port, so a deployment needs a single mapped domain.
The web UI includes:
- Change requests — propose merging one bookmark into another, review the combined diff, comment, approve / request changes, and merge in-browser (a server-side three-way merge; conflicts stay first-class and are surfaced rather than force-merged).
- Code browser — file tree and blob views with syntax highlighting, a rendered (sanitized) README on the repo page, and per-file history.
- Change/diff views, a repository overview, and token/SSH-key settings.
Safeguards: passwords are Argon2-hashed; CLI tokens are stored only as BLAKE3
hashes (revocable); pushes are fast-forward by default (a non-fast-forward
update is rejected unless --force); and state-changing web forms carry a CSRF
token derived from the session and CHIP_SECRET.
| Variable | Default | Purpose |
|---|---|---|
CHIP_BIND |
0.0.0.0:8080 |
Listen address |
DATABASE_URL |
(required) | Postgres connection string |
CHIP_OBJECT_STORE |
local:///data/repos |
local://<path> or s3://<bucket> |
CHIP_SECRET |
(required) | Secret for CSRF tokens; refuses default unless CHIP_DEV=1 |
CHIP_DATA_KEY |
(required) | 64-hex (32-byte) AES key for encryption at rest |
CHIP_BASE_URL |
http://localhost:8080 |
Public URL shown in the UI |
CHIP_COOKIE_SECURE |
auto (true if base URL https) | Force the Secure flag on session cookies |
CHIP_TLS_CERT / CHIP_TLS_KEY |
(none) | PEM paths to serve native TLS (h2 + http/1.1) |
CHIP_DB_MAX_CONNECTIONS |
25 |
Postgres pool size per server instance |
CHIP_SSH_BIND |
0.0.0.0:2222 |
SSH transport bind (empty disables SSH) |
CHIP_SSH_HOST_KEY |
chip_ssh_host_key |
Path to the SSH host key (generated on first run) |
CHIP_DEV |
(unset) | Relax prod requirements for local dev |
For s3://, credentials/region/endpoint come from the standard AWS_* env vars
(which also cover MinIO via AWS_ENDPOINT + path-style).
- Encryption at rest. Every stored object is AES-256-GCM encrypted (per-object
nonce, the object's hash bound in as AEAD associated data). The object id is the
hash of the plaintext, so content-addressing and sync are unaffected.
⚠ Losing
CHIP_DATA_KEYmakes stored repositories unrecoverable — back it up out-of-band. Generate one withopenssl rand -hex 32. - Transport. Set
CHIP_TLS_CERT/CHIP_TLS_KEYto terminate TLS in-process, or terminate at a proxy (see Dokploy note). The CLI uses system CA roots forhttps://endpoints. - Auth. Argon2 passwords; CLI tokens stored only as BLAKE3 hashes, revocable, optionally expiring; failed logins are rate-limited per username.
- Other. Usernames/repo names are restricted to
[A-Za-z0-9_-](no path traversal into the object store); web mutations carry CSRF tokens; pushes are fast-forward unless--force.
docker compose up --build # Postgres + server, objects on a volume
# open http://localhost:8080, register, create a repo, then `chip push`
docker compose --profile s3 up # also start MinIO to exercise the s3:// backendPostgres holds only relational metadata (users, tokens, repos, collaborators, refs). Repository object data lives in the object store.
- EC2 (single instance, Docker Compose + native TLS): see DEPLOY.md
— uses
docker-compose.prod.yml+.env.production.example. - Scaling out (replicas, RDS, S3, CDN): see SCALING.md.
- Provision a Postgres database in Dokploy (or keep the compose
postgresservice). - Create an application from this repository (Dokploy builds the
Dockerfile). - Set env:
DATABASE_URL, a strongCHIP_SECRET, aCHIP_DATA_KEY(openssl rand -hex 32, backed up — losing it loses the data),CHIP_BASE_URL, andCHIP_OBJECT_STORE(local:///data/reposon a persistent volume, or ans3://bucket withAWS_*creds — no code change). - Map a domain to the app's port
8080. Health checks hit/healthz. The proxy should terminate TLS (the cookieSecureflag turns on automatically whenCHIP_BASE_URLishttps://).
Note: gRPC behind a reverse proxy needs HTTP/2 cleartext (h2c) to the backend. Traefik (Dokploy's proxy) supports this; if your proxy makes single-port gRPC awkward, run the web UI and gRPC on separate ports/domains.
The server is stateless (source-of-truth lives in Postgres + the object store), so it scales out as identical replicas behind a load balancer. See SCALING.md for the architecture and the infra path to ~10k users / repos / RPS.
cargo test # object store, dag/merge-base, three-way merge, oplog, syncContributions are welcome! See CONTRIBUTING.md for build prerequisites, the dev workflow, and the lint/format/test gate CI enforces. Security issues should be reported privately — see SECURITY.md.
Licensed under either of
- MIT license (LICENSE-MIT), or
- Apache License, Version 2.0 (LICENSE-APACHE)
at your option. Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.