Docs

Search Vex documentation

Search public documentation, commands, and release notes.

Browse documentation

CLI

CLI changelog

Versioned release notes for the Vex command line interface.

On this page

All notable changes to the Vex CLI are documented here. The format follows Keep a Changelog. The version tracks the [workspace.package] version in the repo-root Cargo.toml (which vex-cli inherits). See the vex-cli-release skill for how releases are cut.

[Unreleased]

[1.12.0] - 2026-08-22

Added

  • vex setup installs the Vex setup, MCP, CI, deployment, identifier, and source control reference guides with the managed skill bundle, so agents can use that guidance offline.

Changed

  • Release builds tell noninteractive users to refresh an older managed skill bundle when the CLI contains a newer copy.
  • The shipped skills document noninteractive conflict resolution and the snapshot boundary used for transcript capture.

Fixed

  • Conflict hints rename an indented jj new command to vex new, matching the command available in a Vex checkout.

[1.11.1] - 2026-08-21

Fixed

  • vex sync restacks a checkout that has nothing to publish instead of failing with Error: Empty revision set. A clean working copy on a trunk that has moved is now refreshed and rebased onto the new trunk, and nothing is uploaded. vex pull --rebase shared the bug and is fixed with it.
  • vex sync no longer refuses to run because a selected change has no description. An undescribed change is restacked like the rest of the stack and left out of the upload, so the one command that keeps a checkout current keeps working as soon as you start typing. vex submit, and any selection named with -r, still require a description.
  • vex push publishes the objects it is about to move a ref onto when the checkout records a slug the catalog treats as an alias. An organization's Home is cloned as main and resolves to the canonical home, and the mismatch skipped the upload silently, so the push failed with cannot resolve git/ref target …: object is missing or pending deletion for a commit that had simply never been uploaded.

[1.11.0] - 2026-08-20

Added

  • vex setup now configures this machine and the repository it is run in. Project skills go in .agents/skills. --skill-scope global|local|both chooses which skill trees to write (default both in a Vex checkout, otherwise global). A generic target covers Pi and other Agent Skills clients that load that shared tree (--targets pi and --targets universal still work).
  • --with-mcp is the scripted way to enable MCP. Interactive setup starts with MCP off. Transcripts stay on by default in a Vex checkout; --no-agent-checkpoints omits them.

Changed

  • Windsurf is Devin: --targets devin (alias windsurf). Detection still accepts Devin.app, Windsurf.app, and leftover Windsurf config.
  • Global skills are written once to ~/.agents/skills rather than a per-client copy of the same tree. Claude Code in a checkout gets .claude/skills/<skill> as a relative symlink into .agents/skills.

[1.10.0] - 2026-08-20

Added

  • vex change list takes --limit N (default 25) and prints how many changes it left out, instead of silently printing every change in the repository.
  • The generated-resource commands — vex app, env, desired-state, release, rollout, runtime, reconciler-tick, hosting, execution, identity, obs, artifact — describe themselves in --help: the actions they accept, what each one does, and the arguments it needs.

Changed

  • vex whoami leads with the identity you asked for — name, email, user id, organization, and which repository the current checkout points at — rather than the full organization-policy dump. --format json is unchanged.
  • Hints and errors inherited from jj now name vex as the command to run. Following one no longer lands you on command not found or a stock jj that refuses to open a Vex repository.
  • vex change list asks the server for a page. The changes endpoint now returns the newest 25 by default instead of every matching change; use --limit for more.

Fixed

  • vex describe, vex commit, vex split and vex squash fail immediately with a message when there is no -m and no terminal to open an editor in. Run from an agent, a script, or CI they used to paint an editor into the pipe and hang.
  • Revsets accept the raw-hex change id that Vex itself prints — from vex change show --format json, CI payloads, issue bodies — so pasting a Vex identifier back into vex log -r resolves instead of reporting that the change does not exist.
  • vex deploy logs says which of the six things went wrong — unknown app, wrong allocation, expired logs, and so on — instead of collapsing them into 404: Not Found or 502: Nomad request failed.

[1.9.1] - 2026-08-19

Fixed

  • vex submit from a Home checkout publishes one working-copy tree that can span every repository in that checkout. It no longer treats an unlanded previous Home change plus the current working copy as two submits, and no longer requires returning to the clone-time revision before starting the next Home change.
  • vex clone of a federated Home no longer fails when a member repository contains .gitmodules or other Git submodule metadata.
  • vex clone of a repository that contains empty files no longer fails checkout with blob object is not finalized for SHA-256 of empty bytes. The CLI synthesizes that implicit blob locally; jj-backend serves it the same way so older clients still clone.
  • Hosted agent sandboxes clone a federated Home with a manifest-bound vexhome_ credential instead of a raw repository access token, matching vex clone. The Blaxel runner floor is now the published 1.9.0 linux-amd64 CLI.

[1.9.0] - 2026-08-17

Added

  • vex submit supports stacking a Git-mode branch (submitted from a plain git clone, no native Vex workspace) on top of another already-submitted Git-mode branch: pass --target <parent-branch> to create a genuinely stacked GitHub pull request — base is the parent's branch, not trunk — instead of a flat diff. See /docs/submit-and-stacking.
  • vex sync gained --restack/--no-restack to control whether it rewrites the local stack when pulling the target, mirroring gt sync's flag pair.

Fixed

  • A Git-mode submission rejected before any branch was claimed or PR touched (for example, --target naming an incompatible stack parent) no longer renders the misleading "Vex adopted the branch but the PR failed" message; it now surfaces the server's real rejection reason.

[1.8.11] - 2026-08-14

Fixed

  • vex pull now refreshes flat federated Home repositories from their signed component snapshots without requesting forbidden raw access to the physical backing repository.
  • vex submit prints {origin}/{org}/change/{number} (for example https://vex.sc/roder/change/15) instead of the Vex Home shortcut /change/{number}, which opens the wrong organization's review.

[1.8.10] - 2026-08-14

Fixed

  • changes/* and stacks/* review refs are no longer immutable heads. They are in-flight patchset tips (changes/832@vex), so vex edit can rewrite them. Ordinary untracked remotes stay protected.

Changed

  • vex submit, vex sync, and vex push print what they are doing while objects upload and the review is created, including a live object-transfer line on a TTY, so a long submit no longer looks hung.

[1.8.9] - 2026-08-13

Fixed

  • Home clones batch selected-snapshot metadata transfers while preserving the snapshot authorization boundary, so large federated repositories no longer fetch thousands of loose objects one request at a time.

[1.8.8] - 2026-08-13

Changed

  • Agent checkpoint upload and export verify zlib hashes and the opaque session-id envelope. They no longer clone an already-scrubbed transcript and re-run the bundled secret scanner over every JSON string. Capture still scrubs fail-closed before anything is written to the outbox.
  • Strings shorter than 8 bytes and payloads larger than the bundled scanner's 1 MiB cap skip that scanner instead of blocking the session. Local credential, token, and private-key detectors still run.

Fixed

  • vex setup doctor and vex session doctor classify the local transcript outbox from manifests instead of decompressing and privacy-rescanning every outstanding archive. A mature checkout can hold hundreds of megabytes of already-scrubbed Codex transcripts; opening them made doctor appear to hang.

[1.8.7] - 2026-08-13

Fixed

  • Private GitHub App imports now supply Git's expected fixed username and ignore unrelated machine credential helpers, so installation tokens clone repositories reliably.
  • Eager Home clones fetch loose objects through verified presigned downloads before falling back to gRPC, so individual large files no longer exceed the gRPC message-size limit.

[1.8.6] - 2026-08-13

Fixed

  • Clones fetch large manifests in bounded, retryable ranges, so composed Home repositories with substantial imported history no longer exceed the gRPC message-size limit.
  • vex submit prints the canonical review URL {origin}/change/{number} instead of /changes/{number}/browse.

[1.8.5] - 2026-08-12

Fixed

  • Agent checkpoint delivery now runs as one renewable machine-wide drain. A stale owner is replaced after its heartbeat expires, while concurrent Vex commands exit without multiplying privacy scans across repositories.
  • Retrying an already-uploaded checkpoint no longer decompresses and privacy-rescans its local transcript just to attach the existing remote checkpoint to a commit.

[1.8.4] - 2026-08-12

Changed

  • vex setup and vex setup refresh now trust the exact Vex-managed Codex hooks in the repository the command is configuring. Setup discovers each hook first and refuses to trust a modified, foreign, incomplete, or user-global hook, so the one-time approval prompt no longer interrupts a normal Vex checkout setup.

Fixed

  • Long agent sessions remain checkpointable and attributable across multiple Changes. Capture now accepts substantially larger transcript payloads while keeping interactive reads bounded, so a long-running agent's work continues to appear on its Change and in trunk History.

[1.8.3] - 2026-08-11

Added

  • Failures now exit with a code that says which failure it was, so a script or agent can branch on the outcome instead of matching stderr prose. Previously every recoverable condition — a lost op-head race, an expired login, an unreachable API, a refused revset — exited 1, indistinguishable from a typo in a revset.

    CodeMeaningRecovery
    10Not a Vex-backed checkoutRun inside a Vex checkout, or vex clone
    11Not authenticated (401)vex login
    12API unreachable or 5xxRetry
    13Repository busy / rate limitedRetry after Retry-After
    14Op-head CAS conflictRerun verbatim; files are untouched
    15Working copy stalevex workspace update-stale, then retry
    16Not a fast-forwardvex pull --rebase --dest <bookmark>
    17Revset selection refusedScope or widen -r
    18Land gates unmetWait for CI/approvals, or override

    Codes 0, 1, 2, 3, and 255 keep their existing meanings, and an unclassified failure still exits 1 — a new code is never guessed. vex repo import keeps its own documented 0–7 scheme, which it also publishes as the exit_code field of its JSON events.

Fixed

  • vex session doctor now identifies captured agent sessions that never reached a checkpoint and prints an exact recovery command: vex session attach --session <id> --revision <revision>. Manual attachment accepts the harness session id directly and creates the missing checkpoint when necessary.
  • Agent hooks route transcript capture through the repository that owns the tool's working directory, and large transcript imports finish in a detached process instead of being cut off when the invoking agent exits.
  • Transcript attachments carry the JJ change id to the server. Change pages and trunk History can therefore find the producing session after the merge queue builds a new landing commit with a different commit id.

[1.8.2] - 2026-08-11

Changed

  • Pulled Change and Stack refs read as changes/595@vex and stacks/ABJY@vex in the local view. They were recorded under the backend's canonical ref name, so every vex status and vex log line spelled the namespace twice — refs/changes/595@vex — in the one position that holds bookmark names, never ref names. The canonical server spelling is unchanged, and refs/heads/changes/<n> still expands to it on push. A checkout that pulled these refs with an earlier CLI keeps the old entries until its next vex pull --refs changes|stacks|all, which deletes them as it writes the renamed ones.

    Upgrading is the sharp edge, so it is worth knowing in advance: while some checkouts run this version and some do not, the local view flaps between the two spellings. A 1.8.1 or earlier binary does not recognise the bare names, so a plain vex pull against a view this release has already migrated deletes every bare entry at once — which reads exactly like data loss and is not. These refs are remote-only; a single vex pull --refs changes restores them.

[1.8.1] - 2026-08-10

Added

  • vex deploy logs and vex deploy allocation no longer need a Nomad allocation id. Pass --service and --environment — or nothing at all in a repo with a deploy profile — and the server resolves the allocation currently serving them, preferring a live one and falling back to the most recent terminated one so a crashed service still answers. When the selectors match more than one service it refuses rather than guessing: reading api logs while debugging jobs is worse than an error. The allocation id still works when you have one.

Fixed

  • vex change show and vex change log were dropping most of what Rails publishes about a CI check. Only the name, status and required flag survived deserialization, so --format json reported a check with no job, run or pipeline id and nothing to open. Every published field now comes through, including timings and the reason a check could not be scheduled, along with the change's rolled-up checks_status.

[1.8.0] - 2026-08-09

Added

  • CI runners stream a step's output while it runs. vex node run used to read a step's stdout and stderr to completion before uploading anything, so a long build reported nothing at all until it finished — a forty-minute cargo test was a blank log until the moment it ended. Output is now uploaded as it is produced, every 16 KB or two seconds, and the Vex web UI tails it. Segments always end on a line boundary so secret masking cannot be defeated by a token landing across two uploads.
  • VEX_SETUP_OFFLINE=1 skips the online Agent Skill publication entirely and keeps the bundle compiled into the CLI. vex setup is documented to work offline but always reached for vex.sc first; this makes that opt-out explicit, for air-gapped installs and for anywhere the network answer does not matter.
  • VEX_APPLICATIONS_DIR overrides the applications directory harness detection reads, alongside the existing CODEX_HOME. It was the last detection input that nothing could redirect.

Fixed

  • vex setup --yes --targets <harness> installs for a harness you name even when the CLI finds no evidence it is installed. Naming a target is the clearest statement of intent there is; it previously installed nothing and still exited 0, so a scripted setup could silently do nothing at all.
  • Terminal sessions no longer assume /bin/zsh exists. The login-shell fallback now picks the first shell actually present (/bin/zsh, /bin/bash, then /bin/sh), so a terminal opens on Linux hosts where zsh is not installed instead of failing to spawn.

[1.7.0] - 2026-08-09

Added

  • vex prune finds and removes the residue a long-lived checkout accumulates: workspaces whose directory was deleted by hand, workspaces whose work has landed and that now hold only an empty commit, and empty undescribed commits left behind by sessions that went nowhere. It reports the plan and changes nothing by default; --yes takes all of it, --interactive opens a checkbox picker over the same plan, and --format json makes it machine-readable for an agent. Everything applies in one transaction, so vex undo reverses a whole prune. --delete-files is the only flag that touches the disk, and it runs last. Commits it cannot read are reported and never acted on.

Fixed

  • vex dash no longer dies when a commit in its revset cannot be read. A single object the backend returns but that fails the native-only decode used to abort the dashboard before it drew a frame; it is now a row carrying the error, the Revisions title counts them, and the rest of the graph loads. A revset walk that stops early — the 1000-commit cap, or an error mid-stream — now says so instead of silently returning a short list.

[1.6.0] - 2026-08-09

Added

  • Roder is a capture adapter, so the Vex dashboard agent's sessions can attach to the commits they produce like any other harness. Roder is hosted rather than local: it installs no hook file here and has no provider transcript on this machine, so vex agent-checkpoints doctor reports it as hosted instead of counting zero hooks and calling that installed. The sandbox-side emitter that feeds it is not shipped yet, so nothing is captured through this path today.
  • vex session continue --agent accepts claude-code, cursor, and grok alongside codex, so a transcript can be continued in whichever harness you actually have open. Each is launched with its own ask-before-acting default and is given access to the private handoff and nothing else; no permission-bypass flag is ever passed. vex session resume accepts the same values, but only Codex can resume a still-local native session exactly — the rest start from the sanitized handoff, which is what continue does.
  • vex session attach with no arguments now lists the local sessions it could attach, newest first, with their titles. Finding the session ID was previously left to the reader.

Fixed

  • Grok transcripts reach the product. The upload path validated the adapter against its own codex | claude | cursor list, so every Grok checkpoint was captured, scrubbed, checkpointed and linked to a commit — and then failed before any network request, for every checkpoint it ever produced. Delivery is best-effort by design, so nothing surfaced it. The list is now derived from the harnesses Vex actually captures, so a new harness cannot be left out of it.
  • vex session attach no longer attaches everything by default. With no --session it linked every checkpoint in the outbox that had no commit — 1,859 of them on the machine this was found on, because per-turn lifecycle hooks legitimately leave that field unset — to a single revision, and a link cannot be corrected afterwards, so every genuinely later commit could then never be linked to those sessions. It now refuses and lists. --all still attaches in bulk, asks first, and takes --yes for scripts.
  • One unhealthy checkpoint no longer discards the links already written for the others in the same vex session attach run.

[1.5.1] - 2026-08-08

Fixed

  • Grok sessions are recorded as Grok. Grok merges hook files from every harness it is compatible with and does not read a project's .grok/hooks/, so it ran the Claude Code hook exclusively and every Grok session was captured as claude-code — with no model, no version, and no transcript, because Claude's extractor and transcript resolver both look in the wrong place. The harness is now read from Grok's own payload, so its model, reasoning effort, and native transcript are captured, and one session is recorded instead of a mislabelled twin. Sessions captured before this release keep their old label.
  • Agent transcripts sync from a vex ws create workspace. .jj/repo is a pointer file rather than a directory in a workspace, so resolving the shared repository configuration through it always failed and every delivery attempt gave up — silently, because the drain runs detached. Capture had been working the whole time, so a workspace accumulated transcripts that could never upload or attach to a commit. vex agent-checkpoints doctor reported that store as unavailable rather than as full of undelivered work; it now reads the same store the capture path writes to.
  • A Grok compaction no longer discards the turn's context. PreCompact is terminal for Grok, as it already was for Claude Code and Cursor.

[1.5.0] - 2026-08-08

Added

  • vex service create adds a service to an existing app. The API endpoint already existed but nothing reached it — vex service was list/show/update only, so a second service (a cache, a worker) could only be added by writing the record directly. A created service is internal-only with auto-deploy off unless asked otherwise.
  • vex deploy verbs accept the #number they print, so the id from vex deploy list can be pasted back into show/logs/cancel without reformatting.
  • vex dash is a k9s-style infra console for watching hosted services and related platform state from the terminal.
  • vex bench clone --format json reports hydration_manifest_ms and hydration_walk_ms, splitting the hydration phase into its server-side pack build and the local tree walk that feeds it.

Fixed

  • install.sh resolves latest through the CLI release registry — the same source of truth vex update uses — instead of the mutable cli/latest/… CDN alias. That alias tracks the dev channel and moving it forward was an optional release step, so it had drifted to 0.8.1 on macOS and 0.10.0 on Linux while 1.4.0 was released for both: every new user got a months-old CLI, and a different one per platform, while anyone who had run vex update was current. The alias has also been moved forward, and remains the offline fallback.
  • vex setup ships a valid agent-skills bundle again after a packaging break left the installed skills unusable.
  • Operator GC campaign tooling no longer treats a signed-plan inventory mismatch as a hard interlock: a pack set that moved between dry-run and apply is a normal repeat signal, not an operator halt.
  • GC plan-scope assertions carry the per-kind collectable tallies the gate needs, and a permanently unprovable roll-up row no longer fails an otherwise good pass.

Changed

  • vex hub is now vex registry, matching registry.vex.sc (the registry stopped being "Vex Hub" when it moved off hub.vex.sc). vex hub still works as a hidden alias so existing scripts keep running.

[1.4.0] - 2026-08-06

Added

  • vex import git supports --standalone --slug <slug> to provision a dedicated physical Vex repository and materialize at root . (cloneable as <org>/<slug>), in addition to the existing Home monorepo folder weave.
  • Generic git sources accept local paths, .git directories, HTTP(S), and SSH remotes; clone uses ambient git credentials on the machine.
  • Federated Home workflows: virtual-root clone/submit planning, and packing import objects as compressed VXPK packs for faster large git history imports.
  • Tree and commit uploads during git import are pipelined with concurrent mapping writes so long imports spend less time waiting on the backend.

Changed

  • Local pnpm dev:local defaults jj-backend object storage to MinIO/S3 so list/purge/presign match production (JJ_OBJECT_STORE_PROVIDER=valkey remains available as an opt-in reduced path).
  • Home monorepo submits that touch both jj/ and other roots are accepted from a Home checkout without splitting into separate changes.

Fixed

  • Virtual-repository lands enqueue on the matching VR merge queue instead of the physical Home queue.
  • Landing a monorepo Space no longer rewrites unchanged sibling folder tree ids, so Space-scoped history stays limited to commits that actually touch that tree.

[1.3.1] - 2026-08-06

Added

  • Platform references and stacks are available through the CLI, including their canonical native-reference form.

Changed

  • Configuration-variable reclassification no longer rewrites the stored value.
  • Queue entry commands accept a change number directly.
  • GC plan JSON now preserves the plan's classification mode.

Fixed

  • vex pull recovers a stale trunk() alias instead of blocking the update.
  • Pack-reclamation output reports successful reclaimed work correctly and treats an unreadable quarantine manifest as a real blocker.

[1.3.0] - 2026-08-04

Changed

  • vex submit and vex sync now infer the review repository from the changed paths.
  • --repo is now a checked override. Vex rejects it when the selected changes belong to a different repository.
  • A selection containing changes from several repositories now fails before Vex mutates local or remote state.

[1.2.5] - 2026-08-03

Fixed

  • An agent transcript no longer goes missing because another agent's session was unhealthy. When a commit sealed, one session that could not be checkpointed — a blocked privacy scan, an unreadable archive — aborted the whole batch, discarding the links already written for the healthy sessions. The commit then reported No agent transcript attached to this change and, seeing no checkpoints, skipped the upload retry, so a correctly captured transcript stayed on disk indefinitely. Checkouts shared by several agents at once were hit hardest. Each session is now handled independently.

Changed

  • vex session doctor and vex agent-checkpoints sync no longer re-verify checkpoints that are already delivered. The outbox keeps every checkpoint ever captured, and both commands were decompressing and re-scanning all of them on every run, so they slowed down as a checkout aged rather than with the work actually outstanding. On a store with ~1,800 delivered checkpoints, session doctor ran for over fourteen minutes without printing anything; it now finishes in about twelve seconds, and a sync that had eighteen checkpoints to send takes under a minute instead of twenty.
  • vex session doctor now reports how much of its answer came from archives rather than manifests: checked: 1875 (18 archives verified). Already delivered checkpoints are read from their manifest, so local corruption in a spent archive is no longer counted — Rails holds the authoritative copy, and vex session doctor --remote still reconciles against it.

[1.2.4] - 2026-08-03

Fixed

  • A failed hosted Git clone now says what actually went wrong. When Vex's own clone endpoint is misrouted, Git reports repository not found against a hosted URL you never typed, which reads as "your repository is missing" when it means the service is misconfigured. git clone vex://org/repo and vex git clone org/repo now check the endpoint after a failure and say so explicitly, including that your repository and access are fine. A successful clone is unaffected — the check runs only once the transport has failed.

[1.2.3] - 2026-08-03

Added

  • vex submit -m "…" (and --message) now describes the selected JJ revisions before uploading — the quick path for vex describe -m "…" && vex submit — and still seeds the initial rich-text Change description with the same text. Whitespace-only messages are rejected up front.

Fixed

  • vex materialize --land now reads the current hosted trunk before building its weave. If the trunk moves during the operation, the command rebuilds against the new tip instead of replacing existing trunk history.
  • vex materialize now uploads its staged commits and file objects before it writes any refs. This fixes land failures under the default batch upload setting, including failures caused by copied file objects that were still local.

Removed

  • The VEX_DURABILITY durability lattice is gone (roadmap/088 Stage 9). It had been inert since Stage 7 made the operation log local: there is no queue for a deferred mode to defer into, so every operation is already durable before the command returns. vex doctor no longer prints the durability / durability_note fields. A vex.json that still carries "durability" keeps loading — the key is ignored, and rewriting the file simply drops it.

[1.2.2] - 2026-07-31

Fixed

  • Agent sessions started in Cursor were captured twice, and the duplicate was attributed to Claude Code. Cursor also runs .claude/settings.json hooks, and capture trusted the hook file that invoked it over the payload, so one session was reported as two: the real Cursor session, and a Claude Code twin that carried no model or version and could never attach a transcript. Because the Claude-compatible hooks fire on every tool call, that empty twin usually won the commit attachment. The emitting harness is now read from the payload, which collapses the two into the single real session.

[1.2.1] - 2026-07-30

Fixed

  • vex land --dry-run and vex change log printed a "Landing stopped" block for changes that never had a stopped landing, with every field of it blank. The server sends attention: null when there is nothing to report, and the CLI treated that JSON null as a present payload.

[1.2.0] - 2026-07-30

Added

  • vex land --dry-run and vex change log now report why a landing stopped. Previously the CLI never read the server's attention payload at all, so an ejected landing surfaced only in the web UI. The block names the failing required checks and the conflicting file paths, says explicitly when no structured detail was recorded, and ends with the commands that dig further (vex change log, vex queue status --format json, vex queue retry <id>).
  • vex queue status --entry <id> and --change <n> resolve those entries directly instead of hoping they fall inside the terminal-history window.

Fixed

  • vex queue status could not show a recently ejected entry. The terminal history was sorted by queue position rather than recency, so its limit kept the oldest entries and a landing that stopped minutes ago was unreachable no matter how it was queried. The window is now ordered by recency and is much deeper.

[1.1.1] - 2026-07-29

Fixed

  • A source-built CLI reported no version to the backend at all. The x-vex-cli-version header added in 1.1.0 is only sent when the value fits the server's 64-character field, and a dev build's version is X.Y.Z-<full 64-char commit> — 70 characters — so the header was dropped entirely and the client was invisible. The effect was the opposite of the intent: released builds (CI, installs) reported fine, while source builds — what developers and agents actually run, and the likeliest place for an old client to hide — reported nothing. The commit suffix is now shortened to 12 hex characters instead of the header being dropped, matching the short-sha convention already used for image tags and the release registry. The semver core is untouched, and a clean release version is still sent verbatim.

[1.1.0] - 2026-07-29

Added

  • The CLI now sends its version to the backend as x-vex-cli-version gRPC metadata on every request. This exists to answer one question the platform previously could not: which CLI versions are actually running. Nothing about your repository is sent — only the version string this binary already prints for vex --version. It is attached in one place, adds no new requests, and is recorded server-side off the request path so it cannot slow a command down.

Removed

  • VEX_PUBLISH_OP_LOG is gone. It was documented as the compatibility escape that would restore the pre-1.0 publishing behaviour, and on a shipped 1.0.x client it did not work — the client no longer had a publishing path and the server refused the old one regardless. An escape hatch that silently does nothing is worse than no escape hatch, because it is reached for during an incident, when discovering it is fake costs the most. If you have it set, it has not been doing anything; remove it.
  • VEX_CLONE_SNAPSHOT_PACKS is gone, along with the snapshot-pack subsystem it controlled. Snapshot packs were a precomputed trunk-worktree closure chain embedded in the clone manifest; they had been disabled server-side since 2026-07-24 and a production benchmark measured their contribution at exactly zero. Ordinary clone packs — which is what actually makes vex clone fast — are untouched and unaffected.

[1.0.1] - 2026-07-28

Fixed

  • The freshness line no longer goes to stdout. In 1.0.0 it was appended to command output, so vex log --no-graph -T commit_id returned the 64-character commit id followed by Refs: up to date with the server (...) — 106 characters — silently corrupting scripts and any agent parsing templated output. The note is a status message about the repository, not part of a command's data, so it now goes to stderr with the rest of jj's hints, where a human still sees it. Anyone scripting against 1.0.0 output should upgrade.

[1.0.0] - 2026-07-28

First major release. The operation log is now local-only: it lives in .jj/repo/ on the machine that produced it and is never uploaded, which is what upstream jj intends ("operations and views are not meant to be exchanged between repos or users"). Vex had been using the op log as its sync plane; refs are the sync plane now. vex undo, vex op log, vex op restore and --at-op all keep working exactly as before — they have always been local.

Changed

  • Breaking: vex push is the publication verb. Objects written by vex commit are staged durably on disk and uploaded by the next vex push, before any ref moves. Previously they were uploaded as a side effect of the operation publish during commit. A commit is still durable locally the moment it returns, but it is not on the server until you push.
  • Breaking: the client no longer publishes operations. No CommitOperation call and no Op/View object upload happens on the default path. Servers keep accepting them for older clients during the compatibility window.
  • vex status and vex log always show a freshness line with three distinct states — current, behind (naming vex pull), or unknown. "Unknown" is deliberately distinguishable from "current"; a failed or slow freshness probe never fails the command.
  • Tracked bookmarks auto fast-forward using jj's own three-way merge against the last-known server target. A local bookmark that has moved is never fast-forwarded — it becomes a conflicted bookmark, as in jj. The working copy and @ are never moved by this, and every advance is reported.
  • --durability and VEX_DURABILITY are transitional and will be removed with the compatibility path.

Added

  • vex checkpoint publishes a commit as a ref under vex/checkpoints/<agent-session>/<workspace> without moving a bookmark, so an agent's work can be made visible to CI and to agent surfaces. CI opts in with an explicit on: checkpoint: workflow key, so a checkpoint never fires a bare on: push: workflow.
  • vex status --format json exposes typed freshness fields so an agent can branch on data instead of parsing prose.
  • --no-refresh (and its env equivalent) skips the freshness probe for scripting and benchmarks.

Removed

  • vex debug publish and the deferred publish queue it drained. Publication is vex push.
  • The op-head conflict machinery, including its retry ladders. With no repository-global op-head compare-and-swap there is no such conflict to recover from, and the per-ref CAS on push is now the only conflict a user can encounter.

Fixed

  • The recurring "working copy is stale" / "sibling operation" lockup. Upstream jj's merge-based stale-working-copy recovery needs an op-heads store that can hold more than one head transiently; the old strict single-head CAS rejected that and forced a recovery-commit workaround. Local op heads hold several heads natively, so upstream's recovery path works again and the workaround is gone.
  • Concurrent commands in two workspaces of one repository can no longer lose an operation head, and N concurrent readers of a divergent repository now produce one merge head instead of N.

[0.18.0] - 2026-07-27

Added

  • vex stack submit accepts a stack-level Markdown PR description via --message, --file, or --stdin, and can clear an existing one with --clear-description. Repeatable --attach ALIAS=PATH uploads private proof assets referenced from the description as vex-asset:<alias>.

Fixed

  • vex ws resolves the organization from the repository when no default org is configured, instead of failing or guessing from an unrelated context.
  • Agent checkpoint hooks are more resilient: they ignore the working copy while capturing, stop routine tool hooks from rescanning a growing transcript, and resume from the checkpoint that holds the most context rather than the latest upload by capture time.

[0.17.1] - 2026-07-26

Fixed

  • vex node run now retries reporting a job's terminal result instead of giving up after one attempt. That report is the only record that a job finished, so a single transport error or a brief API interruption used to leave the lease dangling until the server's expiry reaper failed the job minutes later — discarding a build whose image had already been pushed. A repeat report answered by "lease is not active" is treated as already recorded rather than retried.

[0.17.0] - 2026-07-26

Added

  • vex rebase now requires an explicit -r, -s, or -b. jj's default of -b @ moves the whole branch containing @, which rewrites already-published commits into conflicts when the destination bookmark is stale, and it has no dry-run or confirmation in front of it. The rejection reports how many commits the default would have touched and points to vex pull --rebase --dest <bookmark>; pass -b @ to opt back in.

Changed

  • Automatic stale-working-copy recovery now stops after two consecutive attempts within fifteen minutes. Recovering repeatedly against a degraded backend re-snapshots whatever is on disk each time, which can split one change across several commits or commit a half-written file. The refusal explains how to check backend health, recover manually, and undo a bad recovery from the operation log.
  • Push and pull conflict errors now recommend vex pull --rebase --dest <bookmark> instead of a bare vex rebase -d <bookmark>@vex. The old hint named the exact command whose default sweeps in published commits.

[0.16.1] - 2026-07-25

Fixed

  • vex pull now behaves like jj git fetch for tracked bookmarks: it merges each refreshed <bookmark>@vex into the local bookmark of the same name, so a fast-forward advances local master and real divergence becomes a conflicted bookmark. Pull previously marked every hosted ref as tracked but never carried the local bookmark, leaving local trunks silently stale — which made vex rebase -d <bookmark> aim at an old commit and, with jj's default -b @, rewrite already-published commits into conflicts.

Changed

  • vex pull --update is now only the working-copy move, since tracking carries the bookmark on every pull. Its refusal rules are unchanged for the working copy: it will not move over a description, uncommitted changes, or a working copy that is not a descendant of the target.

[0.15.2] - 2026-07-25

Fixed

  • vex repo import no longer panics immediately after selecting repositories. Lease heartbeats now run independently of Tokio, matching the command executor used by the CLI.

[0.15.1] - 2026-07-25

Fixed

  • A commit's agent transcript no longer disappears when the commit is rewritten. Checkpoints were attached to one immutable commit ID, but a rebase during non-fast-forward push recovery, a vex land, a squash, or a describe all replace that commit — leaving the attachment on a hidden commit that never lands, and the commit that did land with no provenance on History. Links now also record the jj change ID, which survives rewrites, and are re-pointed at the change's current commit after vex commit and after vex push so the outbox attaches the commit that actually exists.

[0.15.0] - 2026-07-25

Fixed

  • vex import git, vex import github, and vex space add now import through native materialization instead of git subtree add plus a Git push. The old projection wrote Git-format commits and trees onto the target repository's trunk. Since that target defaults to the organization home — one physical repository shared by every virtual repository inside it — a single import could leave native clones of every folder failing while reading a tree object. The new path is the same engine the web import, GitHub onboarding, and vex repo import already used, so both surfaces now produce identical history.
  • vex materialize and every other caller of the materialization engine refuse to weave onto a trunk tip that is a Git-format commit, instead of carrying those objects into the merge.

Changed

  • An import weaves the source default branch only. Non-default branches and tags are no longer projected into imports/<slug>/* — that projection was the Git-format write that corrupts a native trunk. The command names what it is leaving behind before it starts, and reports it as skipped_branches / skipped_tags under --format json.
  • Imports no longer record Git import baselines. Native materialization writes the git-to-native commit identity map itself, which is what later sync reads.

[0.14.1] - 2026-07-25

Fixed

  • A repository that was cloned and then only read no longer shows a frozen view. A clone keeps its workspace registration local until its first write folds it away, and until then op-head reads never asked the server anything — so work done by a teammate or an agent in another workspace was invisible indefinitely. Reads now fold that registration onto the current server head, which rejoins the server's history and makes everything published since the clone visible. Every failure path still falls back to the local view, so a read can become fresher but never fail.
  • One op-head refresh per process now answers every caller in that process the same way. Previously the first caller fetched the server head and every later one silently fell back to the stale local head, which is how a freshly fetched head could be discarded within a single command.
  • The end-of-command freshness refresh no longer gives up before it can finish: its budget was below a normal round trip, so it timed out every time and never recorded a server head.

[0.14.0] - 2026-07-25

Added

  • vex pull --update fast-forwards the local bookmark and working copy to the bookmark it just pulled, instead of only refreshing <bookmark>@vex. It refuses without changing anything when the local bookmark is not an ancestor of the pulled target, when it is conflicted, or when the working copy holds a description or uncommitted changes.
  • vex pull -d/--dest <bookmark> names the destination for --update and --rebase, following Sapling's split between what to pull and where to move. With a single pulled bookmark that bookmark is the destination; with none it is the repository trunk. --update also accepts Sapling's -u.
  • repo_pull over MCP exposes the same update and dest parameters.

Changed

  • vex pull --rebase now actually pulls before it integrates: it refreshes the hosted bookmarks, reports that on stderr, and then rebases the current mutable stack onto the pulled target. Previously it delegated straight to vex sync, leaving the local <bookmark>@vex projection stale and taking its target from the control plane.
  • vex pull --rebase is a pure graph operation and no longer requires diff descriptions or a review record, so it works on an in-progress stack. It previously failed with diff <change> has no description whenever the working copy was undescribed. Use vex sync when a submitted stack also needs its landed prefix removed and its review state reconciled.
  • When the repository access catalog does not report a default branch (the usual case for an existing checkout authenticated with a cached token), vex pull now falls back to the repository's trunk() alias instead of failing to resolve a target.

[0.13.0] - 2026-07-25

Changed

  • Local-first durability is now the default. A command returns once its operation is durable on local disk, and a background publisher moves it to the server; push, pull, submit, and land still flush the queue and confirm the server has everything before doing their own work. Working-copy snapshots no longer block on a round trip, so vex status on a dirty tree and vex commit return in local-disk time. Set VEX_DURABILITY=sync to restore the previous behaviour, where a command does not return until the server has acknowledged the operation.
  • CI and other disposable machines (anything exporting CI=true, including Vex's own runners) default to flush-on-exit instead: the same deferred fast path, but the process will not exit with operations still queued, so a runner that is destroyed at the end of its job cannot lose work. VEX_DURABILITY overrides this.

Fixed

  • A repository whose queued operations diverged from the server now converges by itself. Both publish paths merge a moved server head and retry rather than asking you to reload and re-run the command, and a clone whose registration is still pending no longer hides the moved head from that merge — which previously left such a repository unable to publish at all until its marker files were removed by hand.

[0.12.1] - 2026-07-25

Fixed

  • MCP server repo resolution now follows client workspace roots per call instead of a stale baked-in --repo path. Setup guardrails block invalid repo pins, and vex setup doctor reports them.

[0.12.0] - 2026-07-25

Added

  • Local-first durability modes for the op log (VEX_DURABILITY=local-first|flush-on-exit; sync remains the default): mutations return after local durability and a background publisher drains the pending-publish queue with sequential per-operation CAS, so vex status on a dirty tree drops from ~1.1s to ~0.08s and clean status/log from ~0.16s to ~0.06s on a converged repo (op-head reads served locally, refreshed in the background without blocking).
  • vex debug publish — force-drain the local-first publish queue and report the CAS outcome (--dry-run lists the queue).

Changed

  • Synchronous publishes now fail fast instead of freezing the repository: the inline op-head publish path is bounded (per-attempt request timeout 30s via VEX_GRPC_REQUEST_TIMEOUT_MS-family overrides, 2 attempts instead of 24), cutting the worst-case wedge from over two hours to about 90 seconds while holding the working-copy lock. A timed-out publish leaves files untouched; re-running the command publishes again.
  • vex push, vex pull, vex submit/sync, and vex land flush the local publish queue before their server work (sync barriers), so deferred-mode operations are always server-visible before refs move.

[0.11.1] - 2026-07-24

Added

  • vex setup now installs six focused agent skills (vex, vex-stack, vex-apps, vex-deploy, vex-secrets, and vex-workspace) from a single catalog with per-skill manifests and conflict detection.
  • The interactive setup TUI preselects Skills, MCP, and Agent Context checkpoints, shows destination paths and state badges, and remembers deselections across runs. Non-interactive setup remains deterministic, and scripted --yes behavior is unchanged.
  • vex setup status provides a per-target, per-plane overview. Setup doctor output is grouped by target with recovery commands, and setup refresh and setup uninstall support --planes scoping.

Changed

  • vex setup doctor distinguishes stale Vex-managed skills from user-modified skills and reports Codex trust gaps with exact, read-only remediation.
  • Agent Context checkpoint hooks now warn instead of breaking the harness when vex is unavailable. Invocation-time self-healing repairs clobbered Vex-managed hooks, refreshes stale unmodified skills, and caches version nudges; set VEX_NO_SELF_HEAL=1 to opt out.

[0.10.1] - 2026-07-24

Fixed

  • git clone vex://<org>/<repo> now accepts Git's conventional URL form, where the organization is parsed as the URL authority. The explicit vex://vex.sc/<org>/<repo> form remains supported.

[0.10.0] - 2026-07-24

Added

  • Vex releases now include git-remote-vex, enabling stock git clone vex://vex.sc/<org>/<repo> with catalog-resolved, short-lived repository authentication. vex git clone <org>/<repo> is also accepted as shorthand for the canonical hosted Git HTTPS projection.
  • vex repo import now provides a session-backed GitHub App repository picker with keyboard selection, browser authorization continuation, resumable local clone/conversion/upload/landing, short-lived rotating credentials, per-item failure isolation and retry, and versioned JSON/JSONL output. Existing vex repo <resource> <action> commands remain API passthroughs, and vex import github remains available as the legacy compatibility flow.

[0.9.1] - 2026-07-23

Fixed

  • vex submit and vex sync send compact JJ commit pointers rather than uploading full file diffs, allowing large stacks to be materialized by the server from pushed JJ objects.
  • Stack submit output now includes a Vex Home review permalink such as https://vex.sc/stack/19.

[0.9.0] - 2026-07-23

Added

  • vex clone now renders a per-stage progress timeline (Connect / Manifest / Transfer / Index / Hydrate / Publish / Checkout): each stage shows live detail while it runs (pack counts, bytes, transfer speed, hydrated objects, file counts) and leaves its final detail and duration in the terminal after the clone completes.
  • vex bench clone --format json reports pack-phase timing counters (pack_presign_wait_ms, pack_http_wait_ms, pack_download_ms, pack_unpack_ms, pack_loose_object_ms).

Changed

  • Fresh clones build the commit index from the head operation's view instead of walking the full inherited operation log, cutting clone indexing from ~6.9 s to ~0.3 s on a 11k-commit repository. Historical operations index lazily on first use; VEX_CLONE_FULL_INDEX=1 restores the exhaustive build.
  • Historical view reads during full index builds are fetched concurrently (16-way) instead of one at a time.
  • Clone pack/chunk fetch concurrency defaults retuned (8 packs x 16 chunks) for the new server pack shape (~16 MiB compressed packs, 2 MiB chunks); VEX_CLONE_PACK_CONCURRENCY / VEX_CLONE_CHUNK_CONCURRENCY still override.

Fixed

  • Output printed after the clone progress UI (such as Set trunk()) no longer lands at a stray column.
  • The clone summary no longer reports "0 files" on reflink-only checkouts.

[0.8.2] - 2026-07-22

Added

  • Hosted-app deployment config can be edited from the CLI: service visibility, config vars, and path rules.

Changed

  • vex clone is now strictly native: the checkout target resolves only through native bookmarks (the server-advertised default branch is authoritative), and native reads never traverse raw Git objects or git/object/sha1/* mappings. Use vex git clone for Git-format data. This removes the dominant checkout cost on converted repositories.
  • If the advertised default branch has no native bookmark, vex clone now fails before checkout with an actionable error instead of silently falling back to Git refs.
  • vex bench clone --format json reports new native-path counters (native_trunk_resolutions, native_trunk_missing, git_compat_commit_decodes, git_compat_tree_decodes, git_mapping_names_resolved, git_mapping_rpcs, git_mapping_elapsed_ms); any non-zero git_* counter on a native clone is flagged as a correctness regression.

Fixed

  • 0.8.1 regression: fresh native clones of repositories whose history includes Git-imported commits (including vex/home) failed during index build under the native-only contract. Index builds now skip non-native historical commits and truncate ancestry at the native/Git boundary; selected checkout targets still fail closed.
  • vex convert / vex materialize can repair repositories whose views reference raw Git commits: conversion explicitly opts into Git-compatibility reads in memory (never persisted to vex.json).

[0.8.1] - 2026-07-22

Fixed

  • Fresh signed macOS CLI release for the current Vex 0.8.1 source.

[0.8.0] - 2026-07-22

Added

  • vex setup can now configure project-local Agent Context checkpoint hooks alongside Skills and MCP with --with-agent-checkpoints (alias --with-agent-context). Supported detected harnesses are Codex, Claude Code, and Cursor. Captures are scrubbed before local persistence or upload, attach to immutable Vex commits without rewriting them, and can be inspected or exported through vex agent-checkpoints.

Fixed

  • Claude Code checkpoints retain selected reasoning effort from current hook payloads and capture the direct session before a normal vex commit.

[0.7.0] - 2026-07-20

Added

  • vex docker setup — one command to configure the local Docker daemon for the Vex registry, like gcloud auth configure-docker. By default it installs a docker-credential-vex credential helper (so tokens refresh automatically and are never written stale to config.json) and registers it for the registry; --static writes a classic base64 auths entry instead. Idempotent, with --dry-run, --registry, --docker-config, and --bin-dir.
  • vex secrets get --org / vex secrets env --org — read org-scoped secrets (admin-only, audited), the counterpart to the existing app-scoped read.
  • Org and app auto-detection for vex secrets when run inside a Vex repo: bare --org / --app (no value) resolve from the current folder, and with neither flag it defaults to the folder's app. Explicit ids still work everywhere.

Changed

  • The default registry is now registry.vex.sc (multi-region active-active across dc1/lon1/or1, Tigris-backed). vex hub login / vex hub push and the credential helper target it; hub.vex.sc still parses as a Vex host during the transition.

Removed

  • The hub.vex.sc registry hostname is discontinued; use registry.vex.sc.

[0.6.1] - 2026-07-20

Changed

  • Vex CLI builds now reuse Cargo artifacts across local workspaces, Docker builders, and CI, reducing repeated dependency compilation.

[0.6.0] - 2026-07-11

Added

  • vex update — self-updater for macOS/Linux that checks the CLI release registry, downloads the latest release binary, verifies its checksum, and atomically replaces the running executable.
  • A background, off-main-thread check on startup for a newer release, cached locally; if one is available, the next vex invocation prints a one-line hint to update (release builds only; set VEX_NO_UPDATE_CHECK=1 to disable).
  • A real "release" build channel (VEX_RELEASE=1) that embeds a clean X.Y.Z version with no commit suffix, distinct from the commit-suffixed "dev" builds published on every push. Releases are registered in a new, immutable API-backed CLI release registry (POST/GET /api/v1/cli_releases) that rejects re-publishing an already-released version under a different commit.

Changed

  • The organization Home repository is now addressed as <org>/home. Existing bare-organization flows—including clone, convert, materialize, import, Space, and publish—now select Home while explicit vex init and jj vex targets remain explicit.
  • Release builds compile the jj/ source committed in the same Vex revision on every platform, so their embedded source identity is reproducible.

Fixed

  • Existing <org>/main remotes, checkouts, and stored repository configs keep working through the permanent compatibility address and resolve to the same repository identity as <org>/home.
  • Repository-address catalog matching now accepts canonical and legacy Home metadata without creating duplicate physical entries, while Git branches and bookmarks named main remain unchanged.

[0.5.0] - 2026-07-02

Added

  • Pack transfer is now parallel end to end: pack chunks download concurrently within each pack (VEX_CLONE_CHUNK_CONCURRENCY, default 8, on top of the existing 4-wide pack pool), over pooled HTTPS connections with connect/read timeouts (VEX_HTTP_CONNECT_TIMEOUT_SECS / VEX_HTTP_READ_TIMEOUT_SECS).
  • Presigned direct object-store reads: when the server mints presigned URLs (JJ_PRESIGN_GET_TTL_SECS, on by default server-side), pack bytes download straight from object storage instead of riding the gRPC control path. Every presigned chunk is SHA-256-verified before use, response sizes are capped, and any failure falls back to verified gRPC transparently.
  • Pack-resident metadata cache: clone metadata (commits, trees, ops, views — ~97% of unpacked objects) stays in per-pack payload files with an index instead of exploding into ~130k loose cache files, cutting clone cache-write time roughly in half. Blobs stay loose so copy-on-write checkout still works. Disable with VEX_CACHE_PACK_RESIDENT=0.
  • Resumable transfers harden: corrupt transfer state self-heals, interrupted chunked downloads resume via truncate-to-state, and decode-poisoned transfers refetch cleanly.
  • vex bench clone reports the new counters: presigned_fetches, presigned_bytes, objects_pack_resident, loose_writes_avoided, chunk_fetch_concurrency.

Added

  • Fast initial clone materialization (roadmap/032). Clones of snapshot-packed repos download the working tree as a few streamed snapshot packs instead of one RPC per file (vex/main: 2,930 per-file fetches → 0; cold clone 82.8s → ~28s), and repeat clones with a warm shared cache send have negotiation so the server skips already-held snapshot sets entirely (VEX_CLONE_SNAPSHOT_PACKS=0 disables).
  • Batched checkout hydration: lazy clones without snapshot coverage prefetch missing file/symlink blobs in bounded GetObjectsInline batches before checkout instead of one GetObject per file (VEX_CLONE_HYDRATION=0 restores per-file fetching).
  • Parallel + copy-on-write checkout: working-copy materialization uses a bounded writer pool (VEX_CHECKOUT_WRITERS, default min(8, cores)) and, on APFS/reflink filesystems with a same-volume cache, materializes files via clonefile/FICLONE (VEX_CHECKOUT_REFLINK=0 disables).
  • Clone pack prefetch downloads packs in parallel (VEX_CLONE_PACK_CONCURRENCY, default 4) over the same resumable chunked transfer; clone progress gained hydration and per-file materialization phases.
  • vex bench clone: end-to-end clone benchmark with per-phase wall-clock attribution (connect / manifest / pack transfer / hydration / checkout) and client counters (per-file RPCs, pack chunks, hydrated objects, files/bytes written, reflinked files), text or --format json; supports --samples, --dest, --keep, and --have <commit> for incremental-transfer runs.

Changed

  • vex clone progress UI now shows a live detail line explaining what each phase is doing. Most importantly, while the server builds the clone manifest (cold cache) it shows backend is building the clone manifest (cold cache) · waited Ns with a live counter instead of an opaque 0% Connecting, and it surfaces transient backend errors it is retrying.
  • vex clone now rides transient errors while fetching the clone manifest (edge 502 / backend restart / deadline) up to the max-wait instead of aborting after the short retry window.

Fixed

  • vex clone Ctrl+C (and q/Esc) during an in-progress clone now exits with an clone interrupted error instead of painting 100% ✓ while a detached worker kept running in the background. Clone failures are rendered in the progress block too.

[0.3.1] - 2026-07-01

Fixed

  • vex clone working-copy materialization is now genuinely parallel. Blob reads during checkout were dispatched through a blocking block_on on the shared runtime, which stalled the single-threaded executor driving the concurrent checkout stream — collapsing the intended 32-way concurrency to one fetch at a time (≈one network round-trip per file). Object reads now run as spawned tasks and are awaited cooperatively, so up to concurrency() fetches are in flight at once. On a ~2,900-file clone of vex/main this turned a checkout that appeared to hang at "Connecting/Materializing" into a ~73s end-to-end clone.

[0.3.0] - 2026-07-01

Fixed

  • vex clone no longer fails intermittently during working-copy checkout with "Failed to create parent directories … No such file or directory": the parallel checkout now retries the transient directory-creation race (observed on case-insensitive/APFS macOS clones) instead of aborting the whole clone.
  • vex clone object and pack fetches survive a transient backend restart or edge blip. gRPC reads now retry with exponential backoff + jitter over a ~40s window (was a fixed ~2s), so a mid-clone 502 / "service currently unavailable" no longer aborts the clone. Tunable via VEX_GRPC_RETRY_ATTEMPTS, VEX_GRPC_RETRY_BACKOFF_MS, and VEX_GRPC_RETRY_BACKOFF_CAP_MS.

Changed

  • vex clone no longer holds one RPC open while the server builds a large clone manifest. It requests accept_pending and polls until the manifest is ready (tunable via VEX_CLONE_MANIFEST_POLL_MS / VEX_CLONE_MANIFEST_MAX_WAIT_SECS), so a cold manifest on a large repo can't trip the client/edge timeout.

Added

  • vex materialize — weave a source Git repo's full history into a native Vex trunk under a subpath (staged on a bookmark for review before landing); --repo-token lets the control plane authorize server-side runs directly.
  • vex stack land --squash / --rebase — choose how an accepted stack lands on its target branch, overriding the repo's default landing method. --squash collapses each diff into a single clean commit on the current target tip; --rebase preserves the original commit message and author. The flags are mutually exclusive; omitting both falls back to the repository default.
  • vex ws (alias vex workspaces) — create and manage local jj/vex workspaces under a single configurable root (default ~/.vex/workspaces/<org>/<name>), driven by a ./.vex/workspace.toml policy file. The default root lives outside the repo so per-workspace node_modules/target dirs don't sit in, or confuse tooling in, the parent working copy. <org> is the configured vex default-organization slug (falling back to the repo's directory name); root accepts a leading ~ (expands to $HOME) or a repo-relative path.
    • vex ws create <name> attaches a jj workspace and runs on_workspace_create hooks; vex ws remove <name> runs on_workspace_remove hooks, forgets the workspace, and deletes its files; vex ws list and vex ws config round it out (vex ws config --init scaffolds a starter policy file). The name is optional — omit it and a random adjective-noun name (e.g. swift-otter) is generated.
    • Hooks are ordered shell commands per event. Before each runs, __WORKSPACE_DIR__, __WORKSPACE_NAME__, and __REPO_ROOT__ are substituted (and exported as VEX_WORKSPACE_DIR / VEX_WORKSPACE_NAME / VEX_REPO_ROOT) — e.g. to copy .env into a new workspace, or to symlink target/ back to the main checkout so per-workspace Rust build caches don't each balloon to many GB.
    • When the workspaces root is configured inside the repo (a repo-relative root), vex ws create auto-ensures it is ignored before attaching the workspace: it appends the path to an existing .gitignore (or .vexignore/.jjignore), creating .vexignore when no ignore file exists. Idempotent; skip with --no-ignore. With the default outside-the-repo root this is a no-op (nothing in the repo to ignore).

[0.2.6] - 2026-06-27

Added

  • vex pat — create, list, and revoke Personal Access Tokens from the CLI. vex pat create --name <NAME> [--expires-in <DUR>] prints the raw token to stdout (so it pipes into vex secrets set); vex pat list shows metadata only; vex pat revoke <ID> revokes. Backed by a new PAT-management API.

[0.2.5] - 2026-06-26

Fixed

  • vex clone now checks out the server-registered trunk (the repository's default_branch) and seeds the repo-local trunk() revset to match, instead of guessing a local main/master/trunk bookmark and sometimes landing on an unrelated branch (e.g. an agent/feature branch).

[0.2.4] - 2026-06-26

Added

  • -v is now a shorthand for --version (replaces clap's default -V).

Changed

  • vex runner run (the self-hosted runner) is now safe by default: it defaults to an isolated workspace (~/.vex/runner/workspace, configurable via the vex.runner.workspace config key) instead of the current directory, is off by default (vex.runner.enabled, with --enable for a one-off run), and refuses to operate on any repository outside its dedicated workspace.

[0.2.3] - 2026-06-26

Changed

  • Maintenance release.

[0.2.2] - 2026-06-26

Changed

  • Maintenance release; no functional CLI changes since 0.2.1.

[0.2.1] - 2026-06-26

Added

  • Started this changelog and a vex-cli-release skill documenting changelog upkeep and the CLI release process.

No functional CLI changes since 0.2.0.

[0.2.0] - 2026-06-26

Added

  • vex secrets org/CI support: --org <slug>, --ci, and --env-key <KEY> on set/list/unset to manage org-scoped CI secrets via the identity secrets API. Secrets are referenced in workflow YAML as ${{ secrets.NAME }} and injected into the declaring job's step environment at run time.
  • The CI runner (vex node run) injects resolved per-step secrets into the step process environment and masks secret values out of captured step logs.
  • Local-write mode for read-only CI workspace clones: the initial working-copy commit and operation log are written to the local cache instead of the backend, so a READ_ONLY runner token can check out without a backend write.

Changed

  • CI workspace clones use the shallow/lazy blob mode by default (metadata-only clone manifest; file blobs hydrate on demand), matching vex clone's default and dropping CI clone size dramatically.