# Versions and updates {#root}

@status:doc/work @audience:user

[p01] A version is a promise about behaviour, not a snapshot of files. Your project asks for a range, vibe records the one number it chose, and an update moves that number on purpose. vibe itself follows the same rule: one number stands for one contract, however often the binary behind it is rebuilt.

[p02]
```sh
vibe outdated --path hello-vibe
```

```output
PACKAGE VERSIONS
GROUP                 NAME                          INSTALLED      LATEST         STATUS
org.vibevm.world      wal                           1.0.0           -               unknown

0 of 1 package have updates available
```

## Asking for a version {#asking}

[p03] Package versions follow semantic versioning: three numbers, where the first changes when a package breaks compatibility. In the [manifest](../glossary/index.xml#manifest) you name a constraint, not a version: `^1.0` means any 1.x from 1.0 up, `=1.2.0` means exactly that one, and a bare [coordinate](../glossary/index.xml#coordinate) means the newest stable release. The resolver picks one version per package that satisfies every constraint in the graph, and the [lock file](../glossary/index.xml#lock-file) records the choice.

> [p04] `flow:wal@^0.3` → semver range.
>
> <spec://org.vibevm.core/vibevm/common/PROP-000#CF-RANGE>

> [p05] `flow:wal` → latest stable.
>
> <spec://org.vibevm.core/vibevm/common/PROP-000#CF-LATEST>

[p06] A [family](../glossary/index.xml#family) of packages that must move together pins its members exactly, so that a language guide and the server that serves its tools always resolve to one version set. You will meet these pins in the manifests of bundles; they are deliberate.

> [p07] The aggregator's exact pins are deliberate, not kind-mandated: a stack may pin
> its dependencies however it likes, but a family is a *tested version set*, so
> the aggregator holds its members equal.
>
> <spec://org.vibevm.core/vibevm/common/PROP-028#AGGREGATOR-PINS-DELIBERATE>

## Moving the pin {#moving}

[p08] `vibe outdated` reads the lock file and the [registry](../glossary/index.xml#registry) and lists the packages with a newer version available; it changes nothing. `vibe update` re-resolves and moves the pins, preferring to keep every package you did not name at its current version, so that updating one package does not silently drag the others along.

> [p09] **`DepSolver` trait — minimal additions.** The trait gains one method:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-resolver/PROP-003#TRAIT-PIN-PREFERENCES>

[p10] After an update the dependency tree and the boot files are regenerated, and the diff of the lock file is the change log of what your agent will now read.

## What a version promises {#what-a-version-promises}

[p11] A version number is a contract: version 1 does what version 1 is documented to do. Inside a version the files behind it may be rebuilt, corrected or re-published, and a reader of the documentation does not see that kitchen. This is also how vibe treats its own releases. The binary you get from `vibe self install latest` is whatever the main branch holds today, under one version number. The manual describes the contract of that number rather than the files of one build.

> [p12] **A version is a behavioural contract, not a frozen set of files.** Inside a version the product changes as often as it likes — amend, rewritten history, `vibe self update --force` — and this is invisible by design. The only event by which the documentation computes «a difference between versions» is the owner's conscious bump of the version number: no checksums, no file hashes, no history.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#OBS-VERSION-CONTRACT>

[p13] A package version is a snapshot by default, in the sense the word has in Maven: its content may change under the same number, and `vibe update` brings the fresh content. A frozen version is the exception a publisher declares. Before the first public release, breaking changes ship without migration notes; the switch that ends that regime is the owner's alone.

> [p14] **2a. Frozen and snapshot versions (owner rulings,
> 2026-08-10; terminology fixed 2026-08-13).** A version is a **snapshot by
> default** — the word carries its Maven sense, *mutable*: content may change
> under the same version string, `vibe update` brings the fresh content without
> regard for hash continuity, and the lockfile pins the delivered capture's
> `content_hash` plus an opaque provider locator for reproduction. The
> **freeze** is the package author's one-way act: `frozen = true` in the
> manifest — never a registry's opinion, never part of the version string. The
> carrier decisions and their reasons: *(i)* the flag lives **inside the hashed
> content**, so a frozen version self-describes even offline and every registry
> serving those bytes necessarily agrees — in a multi-registry world with no
> global journal, content is the only carrier that cannot diverge; registries
> merely *observe* a freeze in their journals and project it into catalogs;
> *(ii)* the version string carries version ordering **only** — two entities
> never share one name, which keeps the full matrix expressible: a frozen
> prerelease (an immutable published beta) and a mutable bare version (being
> stabilised in place) are both legal; *(iii)* the transition is **one-way and
> single** — unfreezing is forbidden, further work is a new version string; a
> registry may never accept a frozen coordinate's re-publication with different
> bytes; *(iv)* same coordinate + different bytes + any party claiming frozen =
> **loud conflict** through the candidate machinery, never a quiet pick.
> **Every surface that shows a version shows its frozen state** — machine
> outputs carry the field by schema; CLI, TUI, GUI and MCP render it always
> (the Maven lesson: mutability a human cannot see is mutability that will
> surprise them). Yank remains journal-borne — it is the act frozen content can
> no longer carry itself.
>
> <spec://org.vibevm.core/vibevm/common/PROP-044#THE-FREEZE-MODEL>

> [p15] **The pre-publication regime, and the switch only the
> owner can flip (owner ruling, 2026-08-10, near-verbatim: «я пока ничего не
> публиковал на большую публику… я хочу, чтобы мы не применяли миграции до тех
> пор, пока я не скажу, что состоялось первое представление публике… технически
> этот факт нельзя определить никак — только владелец может сказать, что это
> произошло»).** Until that declaration the system is in the pre-publication
> regime: breaking is free *and unmigrated* — no codemods run, no bot PRs, no
> parallel worlds, no sunset calendars; break machinery reports instead of
> demanding (corpora regenerate freely, break notes are optional records);
> readers of old shapes are conveniences deletable at will; the standing user
> recipe is «regenerate / re-init / re-fetch». The fact of the first public
> presentation is technically undetectable **by design** and must never be
> inferred from technical events — not from a push, not from the default
> registry filling, not from a tag; any earlier «de-facto publication» reading
> is superseded by this ruling. The switch is one owner-only line
> (`public = true` in `formats/EPOCHS.toml`), and flipping it is the single
> moment obligations, migrations, support windows and the handshake vow
> activate. The wave-0 slots (epoch markers, recipe identity, must-understand,
> yank) are still built early — not because the window is closing silently, but
> because they are cheap now, constrain today's breaking not at all, and are
> what makes the later freeze possible at all.
>
> <spec://org.vibevm.core/vibevm/common/PROP-044#THE-PUBLIC-SWITCH>

## Versions of vibe itself {#vibe-itself}

[p16] The program manages its own versions with `vibe self`: `self install` builds a version from source or installs a verified bundle, `self ls` lists what the machine holds, `self use` switches the active one, and `self rollback` returns to the previous one. The selector `latest` means the tip of the main branch, `stable` the newest tagged release, and a plain `X.Y.Z` that tag.

> [p17] `latest` → tip of branch `main`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#SEL-LATEST>

> [p18] `stable` → highest semantic-version git tag (the newest release).
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#SEL-STABLE>

[p19] Switching versions never overwrites a running binary and never requires a new terminal: the active version is a pointer the shim follows on the next call.

> [p20] **Switching must not reload the console and must not overwrite a running
> file.** (v1's "env is truth" violated the first; see §9.1.) The model has
> four layers:
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#ACTIVATION-LAW>

[p21] The manager looks after the program on the machine, not a project's dependencies, and its launcher folder goes on `PATH` once. `self use` repoints the active version; `--eval` prints a shell line for a one-terminal switch instead. `self update` follows where the running copy came from: a source checkout rebuilds at the tip, an installed binary moves to the newest published release. The same number is fetched again only when its release was rebuilt underneath it; `self reinstall` fetches the running version again without changing which one it is. `self rollback` swaps to the previous version and back again. The active version needs `--force` to be removed, and the copy that is running cannot be removed at all. Every prompt has a flag, so the whole thing works from a script or an agent, and `vibe vars` prints the variables the installation reads, without the publish token.

> [p22] VVM manages *the vibevm tool itself* on *the machine* — a user-global
>   prefix, not a project's `vibedeps/`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#VVM-IS-TOOL>

> [p23] **The shim dir on `PATH`** (stable; set once).
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#PATH-SHIM-DIR>

> [p24] `self use <selector>` — make a version active by repointing the live
>   `current` file — **no console reload** (§2.5). `--eval` prints the shell
>   line for an integrity-checked shell-local override instead of touching the
>   durable environment.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#CMD-USE>

> [p25] `self update` follows the running origin, and moves versions FORWARD (owner
>   ruling 2026-09-14, replacing the v1 rule that a binary execution refreshes its
>   own number and never jumps). A source/worktree execution rebuilds its exact
>   source root at `latest`. A binary execution reads the release channel's
>   newest-release aggregate manifest and goes to the **newest published
>   release**: newer than the running version installs and activates it by the
>   same verified path an explicit `X.Y.Z` takes. The SAME version is not a no-op
>   — a release may be rebuilt under its own number, so the manifest's bundle
>   digest decides: changed bytes install a fresh immutable `#N`, unchanged bytes
>   reuse the instance already held and cost no bundle download at all. A newest
>   release OLDER than the running one (withdrawn on the far side) never walks the
>   machine backwards. `--force` installs a fresh `#N` whatever the digest says.
>   `self install stable` enters this same path, since `stable` IS the newest
>   release (§2.3).
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#CMD-UPDATE>

> [p26] `self reinstall` refreshes the version that is RUNNING, without changing which
>   version that is: a binary execution refetches its own release's manifest and
>   bundle, a source/worktree execution rebuilds its exact source root — either
>   way landing a fresh immutable `#N`. It takes no `--force`, because a fresh
>   instance is the whole verb; `--profile` / `--release` steer the source lane
>   exactly as on `update`. The pair is deliberate (owner ruling 2026-09-14):
>   refetching the current version and moving to a new release are two acts, so
>   they carry two names.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#CMD-REINSTALL>

> [p27] `self rollback` atomically swaps to the immediate `previous` instance;
>   repeating it toggles the two pointers without deleting either generation.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#CMD-ROLLBACK>

> [p28] The **active** version and the **running** instance are protected:
>   removing an active but non-running instance needs `--force`; the actually
>   running instance is never removable, even with that flag.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#RM-PROTECTED>

> [p29] It is fully scriptable: every interactive prompt has a non-interactive flag
>   equivalent, so VVM works from a bare terminal, CI, or an agent transcript.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#FULLY-SCRIPTABLE>

> [p30] `vibe vars` prints the project's env-configurable variables —
>   `VIBEVM_INSTALL_ROOT`, `VIBEVM_HOME` (whose *actual* values are derived from
>   `current_exe`, §2.5), plus `VIBE_INVOKED_BY`, `VIBE_UNATTENDED`, `VIBE_LOG`
>   — in `NAME=VALUE` form. The publish token is deliberately excluded.
>
> <spec://org.vibevm.core/vibevm/common/PROP-019#VARS-CONTENT>

## Edge cases and rules {#edge-cases}

[p31] Two packages with the same coordinate and version but different bytes are two different things, and the second is refused. If a maintainer needs to re-publish, the version number changes.

> [p32] **Consequence.** Fetching the same `(kind, name, version)` from two different URLs (canonical + mirror, original + fork, upstream + vendored copy) must produce the same `content_hash`. Mismatch is a fatal `IntegrityError`. The effect is:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#IDENTITY-CONSEQUENCE>

[p33] A branch used as a [git source](../glossary/index.xml#git-source) is the one exception to pinning by number: its lock entry records the commit that was installed, and an update walks the branch again.

