version control where commit doesn't mean publish to everyone
wip is a proposed VCS built on jj's change model, with cryptographic read scopes. Sealed changes, per-path access, universal undo, and it lives inside your existing git repo. This page is a design RFC. There is no code. We want you to poke holes before there is.
RFC v0.1, July 2026. Free forever. Apache-2.0. Built on jj. Exit to plain git, anytime.
_
Simulated output. If the design survives review, it shouldn't stay that way.
§1 the problem
git has exactly one read permission: all.
Anything committed is readable by everyone with repo access, forever. Teams have normalized the consequences:
- Security fixes developed in out-of-band private forks, patch-over-email, ceremony outside the VCS.
- Monorepos split for access control long after tooling solved size, paid for in dependency hell.
- Secrets can't live in the repo, so every team bolts on a parallel universe: Vault, SOPS, sealed-secrets, .env files passed over Slack. Config drifts from the code that consumes it, and the drift causes outages.
- On every forge, "private repo" means the forge can read it. Private as policy, not as structure.
Separately: git's daily UX carries 20 years of accumulated fear. jj already proved a better model, working copy as a commit, no staging, no stash, undo for everything. Nobody has combined that model with cryptographic read scopes. That gap is the proposal.
§2 the design, six pillars
-
Sealed changes
wip commit --seal sec-teamencrypts the change: contents, message, file paths. Everyone else sees an opaque blob. When the embargo ends,wip revealpublishes one key and the change goes public with the same hash, so review threads and links survive.how it works + example
Each sealed change gets its own random data key. The diff, message, and paths are encrypted with it, and a copy of that key is encrypted to every reader's device key.
The change's hash commits to the plaintext from day one, so publishing the data key later changes access, not identity. No rewrite, no new hash, no broken links.
$ wip commit --seal sec-team -m "fix auth bypass in session check" change rk3v sealed · 4 readers · 8 device keys world sees: ▓▓▓▓▓▓▓▓▓▓ ciphertext · 4.1 KB $ wip push # GitHub stores ciphertext only $ wip reveal rk3v # embargo ends published data key · rk3v world-readable · hash unchanged
-
Standing path scopes
Persistent access rules per path.
/paymentsreadable only by payments-team. Your.envversioned in the repo, readable only by you. Replaces the SOPS/git-crypt/.env layer.how it works + example
Create a scope once. From then on, every commit touching that path encrypts those files with the scope key while the rest of the commit stays public. Non-readers see metadata ("file changed, 40 lines") so logs stay coherent.
Secrets stop living in a parallel system: config sits next to the code that consumes it, versioned in the same commit, so the two can't drift apart.
How does wip know payments-team's keys? Every grant is signed by someone who already has access, chaining back to the scope's creator.
wip grant payments-team @alicewraps the scope key to her device keys, and@aliceresolves through the SSH key GitHub publishes at github.com/alice.keys, which signs those device keys.$ wip grant payments-team @alice @bob # signed by you roster: 3 readers · 7 device keys $ wip id @alice # where keys come from ssh-ed25519 AAAA… · via github.com/alice.keys · 2 device keys $ wip scope create /payments --readers payments-team $ wip commit -m "add refund endpoint" # touches /payments/* /payments sealed to 3 readers · rest public $ wip scope create .env --readers @me $ wip commit -m "rotate api key" # .env sealed to you world sees: ▓▓▓▓▓▓▓▓▓▓ ciphertext · 1 reader
-
jj's proven model
The daily model comes from jj, a VCS in production use for years. Your working copy is already a commit: no staging area, no stash. Conflicts are recorded instead of blocking you. Every operation is undoable.
how it works + example
In git, your work sits in limbo until you commit, and half the UX exists to manage that limbo (staging, stashing, reflog). wip commits continuously, so you describe, split, and rewrite changes whenever you like.
Made a mess?
wip undosteps the whole repo back one operation. Ctrl-Z for the repository.$ wip describe -m "retry logic" # describe anytime, nothing staged $ wip rebase -d main # conflicts recorded, not blocking $ wip undo # wrong target? one step back restored repo to operation #42
-
Lives inside git + coach mode
wip init --coexistruns inside your existing repo. Colleagues and CI keep seeing plain git. Git commands still work: each does the wip-native thing and prints a one-line explanation.rm -rf .wip/and you're back to a plain git repo.how it works + example
wip keeps a valid git projection of the repo at all times, so nothing breaks for people who never install it. Sealed content appears on the git side as opaque pointer files, like git-lfs.
Adoption starts with one developer and zero team buy-in; coach mode converts your muscle memory one alias at a time.
# you typed git out of habit $ git commit -m "retry logic" wip: committed as change qpmv (working copy is always a commit) git compat: wrote commit 4f2a9c1
-
SQLite storage, filesystem as adapter
Repo truth lives in SQLite, not in files. The filesystem is only a checkout adapter, so platform quirks (case-insensitive volumes, unicode normalization, CRLF) are caught and warned about at checkout instead of silently entering history. A headless API mode serves CI and agents.
how it works + example
Two databases:
repo.dbholds history and syncs anywhere;local.dbholds worktree state and plaintext cache and never leaves the machine.Because checkout is an adapter, wip can also run against a virtual filesystem (ProjFS/FUSE/FSKit) or none at all, which is how CI and agents drive it through the API without a working copy.
$ wip status warning: src/Config.ts and src/config.ts differ only in case this filesystem (APFS, case-insensitive) cannot hold both checked out src/Config.ts · repo history untouched
-
Server as optimization, never as trust root
wip works fully offline. Any dumb remote (GitHub, S3) stores ciphertext and never holds your keys. A wip server adds conveniences (fetch ACLs, review UI, lazy fetch), and removing it costs you those conveniences, nothing else.
how it works + example
With git, "private repo" means the forge can read it. With wip, read access is key possession: a compromised remote leaks ciphertext, not code.
Revoking someone stops future fetches and rotates keys forward, and the server helps enforce that, but it never had read power to lose.
$ wip remote add origin [email protected]:acme/pay.git $ wip push # sealed scopes stay ciphertext github.com compromised tomorrow → attackers get ▓▓▓▓▓▓ ciphertext
Full detail in the RFC, including a plain-words walkthrough of how the keys actually work.
§3 why now: agents
git gives your agent the keys to everything.
wip gives it a keycard.
Every agent tool today handles safety by asking nicely: system prompts, allowlists, "please don't read .env". wip doesn't ask. An agent invited without a scope's key holds ciphertext, not a rule it promised to follow. Every agent change is signed by a session key and carries its delegation chain. Delegation only narrows: no invitee, human or agent, ever exceeds the inviter, enforced by the key wrapping itself.
One rule we hold ourselves to: never claim the agent can't do damage. Nothing can claim that. wip bounds the damage (crypto scopes) and makes it reversible (op log undo), and that's the whole promise.
§4 what can kill this
Every pitch has a graveyard section. Most hide it. Here is ours, stated plainly, because you'll find these anyway and we'd rather you attack the hard version.
- Adoption gravity. Git won on network effects; hg and bzr died anyway. The entire coexist strategy is the mitigation, and it's still risk #1.
- Sealed content breaks consumers. Teammates can't build code they can't read. Mitigations designed, unproven at scale.
- Crypto review burden. Nobody should trust an embargoed 0-day to this before professional cryptographic review. "We rolled our own" is disqualifying in this market, so the audit is on the critical path.
Six more, stated just as plainly, in the RFC kill list.
§5 the hostile review
Before publishing, the design went through two rounds of adversarial review, hostile personas attacking first the system, then the adoption plan. The full Q&A ships with the RFC. The hardest open questions, labeled:
If the hash covers ciphertext, the coexisting git side still contains ciphertext after reveal, so git blame, bisect, and grep stay blind to that change on the git projection. The wip side sees plaintext; the git side sees a pointer. Whether that trade is acceptable is a core open question of this RFC.
Metadata-only ("file changed, 40 lines") compiles nothing. The designed answer is scope boundaries aligned to the build graph plus granted build artifacts, and it is unproven. If this can't be made to work, the monorepo pitch shrinks to the secrets and embargo pitch.
Sealing needs a team; a solo dev gets jj's model, which jj already gives away. The bet is that sealed .env across your own devices plus undo plus coach is enough solo value. That bet is exactly what stage 0 measures, and if it's wrong, this dies cheap and early, by design.
No wrap row means the bytes are noise to you. No server checks a rule; the missing key is the mechanism. This holds for extensions, transports, servers, and agents alike. Transports never need, and never get, read capability on sealed scopes.
§6 status, honestly
exists
- full system design
- two rounds of hostile review + answers
- threat framing for the crypto layer
- this page
does not exist
- code
- a cryptographic audit
- any reason to trust real secrets to it yet
The plan is gated: if the design doesn't survive public review, or early users don't retain, this dies at stage 0. On purpose. What we ask from you today is review. Adoption can wait.
§7 poke holes
Break the sealing scheme. Find the metadata leak we missed, or show why the build-graph answer can't work. The best outcome of this page is someone killing the design cheaply, before the code exists.