Skip to main content

onevcs

Version control and its remote host behind one host-neutral vocabulary, for agent workflows.

The review unit is a change request — GitHub maps it to a pull request, and a later host maps it to whatever it calls the same thing. Vcs owns the repository side (identities, sessions over an isolated worktree, preserved work); RemoteHost owns the host side (opening a change, reading its checks, merging it); a rules file decides, per repository, how a change publishes and what verifies it. Everything a run does is emitted as an NDJSON event stream.

The public surface is the approved contract — docs/contract.md — compiled, and it is implemented: the registry with its lazy migration, the rules engine, sessions over borrowing clones, bounded git, the FIFO merge queue, both publication strategies, recovery and provenance, the merge train, and the event stream.

What one change looks like

onevcs register ~/projects/widgets                 # once per checkout
onevcs rules check widgets                         # which policy, and why
token=$(onevcs session open widgets --branch feature/thing | jq -r .token)
# …work in the worktree the session printed…
onevcs publish "$token"                            # verify, then land it
onevcs events "$token"                             # everything it did, as NDJSON

A branch that outlived the session that cut it is landed by name instead, under that same rules-resolved policy: onevcs publish-branch feature/thing --repo ~/projects/widgets for work that finished, and onevcs recover for a step that stopped half way, which publishes it with the attestation that verification cleared it. Whichever of the three refuses a branch names the one that takes it.

onevcs status REF answers what became of a piece of work, asked by whichever name you hold — a change request's URL, a session token, a branch, or a commit. It reports the identity's resolved policy, the session, every checkout and per-run clone holding the branch, whether the change landed and what says so, the host's checks, the last thing its merge path said about it, and the command that advances it. Landing is decided from the base's own history — a recorded landing, the change request's number in the base's log, or a landing trailer — so a change that squash-merged reads as landed rather than as unpublished however far the base has moved since, and one that history cannot decide reads as unknown rather than as work nobody published. A host that cannot be reached leaves its section unavailable instead of failing the command.

onevcs import BRANCH --repo PATH [--from SOURCE] [--as NAME] makes a branch reachable from an identity's registered checkouts, so a later run's clone can see work a stopped run left in its own. It writes refs and nothing else — no checkout, no working tree — and refuses a non-fast-forward overwrite by naming the commits it would lose.

onevcs sweep [--dry-run] [--min-age-hours HOURS] reclaims the workspaces those landings leave behind. Every branch published by name cuts a run root — a clone, a worktree, and the merge path's preserved logs — under the state root, and until this rule existed nothing removed one; thirty-one of them filled a host's disk twice in a single run. The rule runs whether or not anybody asks: each landing enforces it over its own family before cutting the next run root, and this verb is the same judgement asked deliberately and over every family at once.

A workspace is removed only where this tool can prove it is finished: its merge path recorded a verdict, no live session holds its occupancy lease, it was last written outside the age floor --min-age-hours sets, and removing it is something this host can do at all. Everything else is retained and reported with the reason — a workspace somebody is still publishing in is never removed, and neither is one belonging to another manager on a shared state root — and the per-run lifecycle clones a session keeps as recovery history are outside it entirely.

Two things a proven-finished workspace still gets to keep. Its preserved logs last at least as long as the age floor, because they are what an operator reads after a publication failed; and a clone still holding work that never reached the origin is kept past the floor too, until enough newer ones stand in front of it — under the same bound the per-run lifecycle clones a session keeps are kept under. Reclaiming a workspace also stops the processes that publication left running — a publication runs the repository's own verification and verifications start daemons, and unlinking files a live process holds open frees none of their blocks.

Everything durable lives under one state root — ONEVCS_HOME, otherwise ~/.onevcs.

GitHub is reached through gh, so whatever gh auth status reports is the credential. A fine-grained personal access token needs Actions: Read on the repository beside its contents and pull-requests access: GitHub will not let that credential class resolve a check run at all — there is no Checks permission to grant one — so a change request's checks are read from its workflow runs, and change_checks says so in the sources it answers with. Anything a third-party integration posted as a check run or a commit status is invisible to such a token, and a credential that can read neither source is refused rather than reported as having no checks.

Install

cargo install onevcs      # crates.io
pip install onevcs-cli    # a prebuilt wheel, no Rust toolchain
npm install -g onevcs-cli # a prebuilt binary, no Rust toolchain

All three install the same onevcs binary. Prebuilt binaries exist for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64); every release also attaches the archives and their .sha256 checksums for a direct download.

Use

onevcs --help

--help is the command surface, and publish reserves its own exit codes for a verification that failed, a request that was invalid, and a base that moved under it.

Embed it

A command answers a process: an exit code and a line of prose. A caller embedding the crate wants the decision, so the same operations answer values.

let published = onevcs::publish(&providers, &token, &PublishRequest::default())?;
match published.outcome {
    PublishOutcome::Merged(sha) => journal.landed(sha),
    PublishOutcome::ChangeOpen(url) | PublishOutcome::Queued(url) => journal.awaiting(url),
    PublishOutcome::NothingToPublish => journal.nothing(),
    PublishOutcome::Failed { kind, reason, retained } => journal.failed(kind, reason, retained),
}

close_session and session are the same for the rest of a session's life, and EventStream::open(&token) reads its events as Envelopes, each attributed to the session that wrote it — so a caller following several publications at once can tell them apart. The command line is a rendering of these rather than a second path through them.

A consumer that wants some of what a session writes reads it through the filter grammar the three producing libraries share — EventStream::open_filtered(&token, filter), or onevcs events TOKEN --filter SPEC with the spec inline as JSON or in a file. An envelope passes when it matches any include matcher (or include is absent) and no exclude matcher, matching source by family, kind by glob (change-*), and the reserved label keys exactly:

include:
  - {source: vcs, kind: "gate-*"}
exclude:
  - {kind: lock-wait}

Before a caller has a token, session_holders(repo) answers who is in a repository: one SessionHolder per recorded session, carrying the token the calls above take, the branch and worktree it holds, and whether its owner is still running (Liveness::Live) or the session is the remains of a run that stopped.

Test against it, without a real GitHub

Embedding the crate, run_with(&cli, providers) takes the two implementations a run reaches Vcs and RemoteHost through; run is that with Git and GitHub, and every entry point above goes through the same seam. onevcs-testing ships in-memory and file-backed implementations of both, so a consumer's suite drives a real onevcs through a real journey against a host it seeded:

cargo add --dev onevcs-testing

They emit the events the real implementations emit — a claim this repository's own suite checks by running one publication journey on both backends and holding the two event streams to each other.

Develop

just bootstrap   # from a clean clone
just check       # the deterministic gate: format, clippy, tests, coverage, docs
just gate        # check, plus the diff-scoped LLM-judge tier — the pre-push bar

just --list is the full index.

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

onevcs_cli-0.11.0-py3-none-win_amd64.whl (1.3 MB view details)

Uploaded Python 3Windows x86-64

onevcs_cli-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

onevcs_cli-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

onevcs_cli-0.11.0-py3-none-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

onevcs_cli-0.11.0-py3-none-macosx_10_12_x86_64.whl (1.2 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file onevcs_cli-0.11.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: onevcs_cli-0.11.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for onevcs_cli-0.11.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 394c1bad8fbce3eea4416576e8bd221034a583aebb3d3c2455a10bae9af3b74d
MD5 0d87148a95b2511b5d10607cd96d0952
BLAKE2b-256 67da409ef7006bdb148e5669b359d60a0aab0619e21be45ee1aaf3c9107937ca

See more details on using hashes here.

File details

Details for the file onevcs_cli-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for onevcs_cli-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 59e529602e87eead655397c0571f8173c9a14087d534df327b78aff2a5e6a348
MD5 69a0ad583974259cbeb6e0045890e655
BLAKE2b-256 713aa8d7a6b5b7d11f029b475a64a039fa027b5273ad440e046fbc5a72522080

See more details on using hashes here.

File details

Details for the file onevcs_cli-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for onevcs_cli-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b289ce7d0e3f5ea31f846ec50975a5ac75a32cc21be06a9a61184b5afcbb934c
MD5 f84bd52dc8fe32bf4328d32410e11795
BLAKE2b-256 a2d760cbd9036eb133de4534ee117dc258aaf15c4eae563b0a0cc4930ee189ba

See more details on using hashes here.

File details

Details for the file onevcs_cli-0.11.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for onevcs_cli-0.11.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b9e8e990f2072ed6fe464953d76edcad18f97654b3f37e901e81ad2894a45503
MD5 aa7fdff6c163ad1c735804b71cb70a79
BLAKE2b-256 56f5f05ded40fde2d5e6c0240fbdc15dbd14c1ce86bb321cad1c571364b8c9f6

See more details on using hashes here.

File details

Details for the file onevcs_cli-0.11.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for onevcs_cli-0.11.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8e2e5e99bb04f6c6ae624f265273928aeb4903737d84be1e3e18466fe72ef1cb
MD5 f4997aae05b0b316760e6e1312972583
BLAKE2b-256 4a978d0374f78dd04e598e323f9c030243aa07db707ec9c70e8939de77e74b42

See more details on using hashes here.

Release history Release notifications | RSS feed

0.18.0

5 files

0.17.1

5 files

0.17.0

5 files

0.16.3

5 files

0.16.2

5 files

0.16.1

5 files

0.16.0

5 files

0.15.10

5 files

0.15.9

5 files

0.15.8

5 files

0.15.7

5 files

0.15.6

5 files

0.15.5

5 files

0.15.4

5 files

0.15.3

5 files

0.15.2

5 files

0.15.1

5 files

0.15.0

5 files

0.14.1

5 files

0.14.0

5 files

0.13.0

5 files

0.12.3

5 files

0.12.1

5 files

0.12.0

5 files

0.11.1

5 files

This release

0.11.0 This release

5 files

0.10.0

5 files

0.9.0

5 files

0.8.1

5 files

0.8.0

5 files

0.7.0

5 files

0.6.1

5 files

0.6.0

5 files

0.5.0

5 files

0.4.2

5 files

0.4.1

5 files

0.4.0

5 files

0.3.1

5 files

0.3.0

5 files

0.2.10

5 files

0.2.9

5 files

0.2.8

5 files

0.2.7

5 files

0.2.6

5 files

0.2.5

5 files

0.2.4

5 files

0.2.3

5 files

0.2.2

5 files

0.2.1

5 files

0.2.0

5 files

0.1.3

5 files

0.1.2

5 files

0.1.1

5 files

0.1.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page