wip: the RFC v0.1

Version control where "commit" doesn't mean "publish to everyone". This is the full system argument: the design, the decisions behind it, and everything we think can kill it. Read it hostile. The comment thread is on GitHub.

§1 problem

git has exactly one read permission: all.

Anything committed is readable by everyone with repo access, forever. Consequences teams have normalized:

Separately, git's daily UX carries 20 years of accumulated fear: staging area, stash, detached HEAD, rebase-conflict lockups, force-push, lost work. Jujutsu (jj) has already proven a better model. Nobody has combined it with cryptographic read scopes.

§2 the design

wip: a VCS built on a forked jj-lib (Apache-2.0, Rust), with:

  1. Sealed changes

    wip commit --seal sec-team encrypts content, message, and paths. World sees an opaque blob in the DAG. Per-change data key, wrapped per recipient (HPKE). A salted plaintext commitment sits inside the hashed portion, so wip reveal = publish a 32-byte key: the change becomes world-readable with the same hash, no rewrite, no rebase, review threads intact. Coordinated vulnerability disclosure becomes a native workflow.

  2. Standing path scopes

    For monorepos and secrets. wip scope create /payments --readers payments-team. File deltas under the path auto-encrypt; the rest of the commit stays public. A metadata-only tier ("file changed, 40 lines") keeps builds, blame, and logs coherent for non-readers. Same mechanism gives secrets a legitimate home in the repo: encrypted config versioned in the same commits as the code that consumes it, readable only by the deploy scope. wip is not a runtime secrets manager (no dynamic leases, no runtime audit); it replaces the SOPS/git-crypt/.env layer and complements Vault above it. Pitch: one repo for the whole company, where reads have owners too.

  3. jj's proven model

    Working copy is a commit (no staging, no stash), stable change IDs across rewrites, first-class conflicts (rebase never blocks), operation log with universal undo.

  4. Coach mode

    Git commands work as aliases, do the wip-native thing, and explain the difference in one line. Muscle memory converts one alias at a time. wip init --coexist runs inside an existing git repo; for public work, colleagues, CI, and GitHub never notice. Sealed content surfaces to plain-git colleagues as LFS-style opaque pointer files, never as editable text. Adoption unit = one developer.

  5. SQLite storage, filesystem as adapter

    Two databases: repo.db (syncable, safe to replicate anywhere) and local.db (never syncs: worktree state, plaintext cache). Working copy is a pluggable adapter: native FS, virtual FS (ProjFS/FUSE/FSKit), headless (API-only, for CI and AI agents), WASM/OPFS later. Db-as-truth quarantines the cross-platform bug zoo (case collisions, unicode normalization, path limits, CRLF) to the checkout adapter: lossy mappings are detected and warned, never silently committed as repo truth.

  6. Server as optimization, never as trust root

    Fully functional offline; any dumb remote (GitHub, S3) carries ciphertext. A server adds fetch ACLs (existence hiding), forward revocation, equivocation prevention, review UI, and lazy fetch at monorepo scale.

§3 how the keys work, in plain words

The whole crypto story is five moves. Three people for the walk-through: you, Alice (on your security team), and Bob (not on it).

  1. Identity

    You already have an SSH key; GitHub even publishes it at github.com/you.keys. wip uses it exactly once: to sign a fresh decryption key for each of your devices. The SSH key says who you are. The device key does the decrypting. Rotate your SSH key next year and nothing breaks, because access points at device keys, and those get re-signed by whatever SSH key replaces the old one.

    A team like payments-team is a chain of signed grants. Every wip grant payments-team @alice is a statement signed by someone who already reads it, chaining back to the creator. Resolving --readers payments-team walks that chain, fetches each member's SSH key, and wraps one copy of the scope key per signed device key. The honest hole: key discovery leans on GitHub, so an account compromise can enroll an attacker's device key. Pinning and cross-signing are planned hardening; the kill list already says so.

    $ wip grant payments-team @alice @bob  # signed by you
    roster: 3 readers · 7 device keys
    
    $ wip id @alice                         # key discovery
    ssh-ed25519 AAAA… · via github.com/alice.keys · 2 device keys
  2. Sealing

    wip commit --seal sec-team generates a random key for this one change, the data key, and encrypts the diff, the commit message, and the file paths with it. Then it encrypts a copy of that data key to every member of sec-team, one copy per device key. Those copies are called wraps. The sealed blob and its wraps travel through any remote, GitHub included, as ciphertext.

  3. Reading

    Alice's wip finds the wrap addressed to her device key, unwraps the data key, decrypts the change. Bob has no wrap, so Bob has noise. No server checked a permission table; there is no table. He just doesn't have a key.

  4. Granting

    wip grant sec-team @carol: someone who can already read the scope wraps its key for Carol's devices. You can only hand out what you already hold, and that one sentence is the security model: no grant can ever exceed the granter. Works the same for a teammate, a CI job, or an agent with an 8-hour TTL. Revoking Carol stops all future wraps and rotates the key forward; it cannot take back bytes she already fetched. Culprit 2 below says that plainly, because overselling revocation is how you lose the security crowd.

  5. Revealing

    The embargo ends: wip reveal rk3v publishes the change's data key itself, 32 bytes, for anyone to use. From the start, the change's hash covered the ciphertext plus a commitment to the plaintext, so decrypting it changes nothing about its identity. Same hash, no rewrite, review threads still attached. Disclosure day is publishing one key.

Everything else in the design is bookkeeping around these five moves.

§4 key design decisions

§5 culprits: what can kill this, stated plainly

  1. Adoption gravity. Git won on network effects; hg and bzr died anyway. Mitigation is the entire coexist/coach strategy, but it remains the #1 risk. wip must be adoptable by one engineer, invisibly, with zero team buy-in, or it dies.
  2. Revocation is forward-only. Crypto cannot retract bytes someone already fetched. Honest framing required: revoke = stop future fetches + rotate keys. Overselling this destroys credibility with the exact security audience the product courts.
  3. Metadata leaks. A sealed blob on a public remote leaks existence, size, timing, and recipient list; for an embargoed exploit fix, existence alone tips attackers. Requires a "dark" tier (keyholder-only sync) and discipline in defaults. Easy to get subtly wrong.
  4. Sealed content breaks consumers. Teammates can't build code they can't read; nobody can merge what they can't decrypt. Mitigations (metadata-only tier, scope boundaries aligned to build graph, awaiting-keyholder rebase states) are designed but unproven at scale.
  5. Fork maintenance. jj-lib is pre-1.0 and churning. Label propagation hooks cut below the pluggable-backend boundary, so wip carries a real fork. Strategy: keep it surgical, upstream generic hooks, accept the rebase tax.
  6. Key loss = data loss. Lose every wrapped copy of a data key and the sealed history is gone, permanently. Needs org escrow/recovery keys by default, which reintroduces trust decisions the product must surface honestly rather than hide. Secrets-in-repo raises these stakes further: an unreadable sealed scope containing production config is an outage, not just lost history.
  7. Auto-snapshot vs secrecy. A tool whose pitch is confidentiality must not auto-record .env into synced history. Paranoid ignore defaults, size guards, and undo coaching are mandatory, not polish.
  8. Crypto review burden. Commitments, HPKE envelopes, key rotation, convergent-encryption pitfalls: this needs professional cryptographic review before anyone trusts an embargoed 0-day or production secret to it. Budget for audits; "we rolled our own" is disqualifying in this market.
  9. Ecosystem surface. Hooks, IDE integrations, submodules, LFS-class files: each gap bounces a real team. Git interop covers most, headless API helps tooling, but the long tail is long.

§6 why now

Supermodel-class coding agents change two things: the multi-year build-a-VCS effort is compressible, and agents themselves are a new VCS client. Headless mode with crypto-enforced path scopes means an AI agent physically cannot read code it isn't granted, an answer to a question every engineering org is currently asking. jj's rise proves the market will move off git's UX; nobody has yet given it a reason to move off git's trust model.

§7 what wip is not

Not a blockchain, no tokens. Not end-to-end "zero-trust collaboration" theater: the server, when used, is honestly scoped. Not a runtime secrets manager: it versions encrypted config, it does not lease database credentials. Not a git killer by frontal assault: it lives inside git repos until it doesn't need to. And not a future paywall: the tool is free and stays free, whole, sealing included. The cryptography is never the thing you pay for.

§8 now break it

This design survived two rounds of hostile review before publication. The first, attacking the system itself, is published; the second attacked the adoption plan and stays private until there is something to adopt. The hardest open questions are on the front page, labeled. The best outcome is you finding the one we missed.