Most VibeXP releases upgrade in place: pull the new image, restart, done. This page lists the exceptions.
Versioning and support
Section titled “Versioning and support”VibeXP publishes one image, ghcr.io/vibexp/vibexp, tagged X.Y.Z per release.
| Tag | Points at |
|---|---|
X.Y.Z |
that exact release, immutable |
latest |
the highest published version, not the most recent build: a backport patch on an older line never moves it |
The bundled docker-compose.yml tracks latest. Pin to X.Y.Z instead if you
want upgrades to be a deliberate step:
image: ghcr.io/vibexp/vibexp:0.10.0Patch releases are supported on the newest minor line only. Now that
0.10.0 has shipped, fixes go to 0.10.x, not 0.9.x. To stay on a supported
version, follow the newest minor.
A patch release (0.10.0 to 0.10.1) contains bug fixes and security fixes
only. It never adds a database migration and never changes the API, so it is
always a straight image bump with no action on your side. Anything that needs a
schema or API change ships as a minor release and appears below if it requires
action.
Everything below needs action when you upgrade, either before the new image will start or immediately after. Entries are newest first: if you are skipping several releases, work upwards from the version you are on and apply every one in between.
Breaking changes
Section titled “Breaking changes”Prompt label filter now matches any label (v0.13.0)
Section titled “Prompt label filter now matches any label (v0.13.0)”v0.13.0 changes what ?labels= means on the prompt list endpoint,
GET /api/v1/{team_id}/prompts, so that it behaves the same as on artifacts,
blueprints and memories. Nothing in the database changes; only the answers to
requests that already worked do.
- Any, not all.
?labels=a,bused to return only prompts carrying bothaandb. It now returns prompts carrying at least one of them, so adding a label to the filter widens the result instead of narrowing it. - New
400responses. A filter naming more than 25 labels, or a label longer than 50 characters, used to be passed to the database as it was. It is now rejected with400. - Empty entries are ignored.
?labels=a,,band?labels=a,used to match no prompt at all, because no prompt carries an empty label. They now filter onaandb, and ona. Each entry is also trimmed, so?labels=a, bnow filters onbrather than onb.
If a script relied on the old all-of behaviour, filter on one label and check
the rest on the client (every prompt in the response carries its labels), or
send the request once per label and intersect the results. See
Labels for how the filter works on every
resource type.
Memory metadata.tags moved into labels (v0.13.0)
Section titled “Memory metadata.tags moved into labels (v0.13.0)”v0.13.0 gives every resource type one taxonomy. Its database migration, 016,
adds a labels text[] NOT NULL DEFAULT '{}' column with a GIN index to
artifacts, blueprints and memories (prompts already had one), and then
moves each memory’s metadata.tags into labels and removes the tags key
from metadata. That is a rewrite of existing rows, not only a new column, so
it is worth knowing what it does before you upgrade.
The rest of the migration:
- Only an array is moved. A
tagsvalue that is not a JSON array (a string, a number, an object) is ordinary metadata that happens to share the name: the migration leaves it inmetadatauntouched. - Nothing looks freshly edited. The trigger that bumps
updated_atis suspended for the backfill, so migrated memories keep their timestamps, and search recency ranking and freshness still reflect real edits. - Whitespace. The backfill trims ASCII whitespace. A tag carrying a
non-ASCII space (a non-breaking space, say) keeps it until the memory’s labels
are next saved: any edit from the web app does that, but an API or MCP update
that omits
labelsdoes not. - Old clients keep working, with one catch. A client that still sends
metadata: {"tags": [...]}on a memory has those tags folded intolabelsby the server (normalised and capped the same way, never rejected), so nothing puts the key back. But on an update,metadata.tagssent withoutlabelsreplaces the memory’s labels with those tags, dropping any label added since. Move such scripts over tolabels. - Rolling back (running 016’s down migration) writes each memory’s
labelsback tometadata.tags, except wheremetadataalready holds a non-arraytagsvalue: that value is kept, and that memory’s labels are lost with the dropped column. The same down migration also drops thelabelscolumn on artifacts and blueprints, whose labels are not saved anywhere, and the memorytitlecolumn that v0.13.0 added alongside it, so every memory title goes too.
After the upgrade, the memory create and edit forms still show a Tags card
next to the new Labels input, and the memory list a Tags column. Both
read metadata.tags, so they are empty for every migrated memory: your tags are
in Labels. Anything typed into the Tags card is folded into labels on save,
after the labels already set, so existing labels are never lost; tags beyond the
10-label cap are dropped without an error.
The same release changes the prompt list filter: see Prompt label filter now matches any label.
Bundled Postgres upgraded from 16 to 17 (v0.10.0)
Section titled “Bundled Postgres upgraded from 16 to 17 (v0.10.0)”The Postgres image shipped in the combined-image docker-compose.yml moved from
pgvector/pgvector:pg16 to pgvector/pgvector:pg17. Postgres data files are
not compatible across major versions, so a Postgres 17 image started on a
data directory created by Postgres 16 refuses to start. If you run the bundled
Postgres with a populated data volume, you must dump-and-restore (or
pg_upgrade) the volume once before pulling the new image. Managed / external
Postgres is unaffected: the pin only governs the bundled container.
Cookie consent removed, GTM now loads on the container ID alone (v0.10.0)
Section titled “Cookie consent removed, GTM now loads on the container ID alone (v0.10.0)”VITE_GTM_ENABLED no longer exists. Google Tag Manager loads whenever
VITE_GTM_ID is set, with no separate on/off flag. If you had a GTM ID set
but the flag off, GTM will now load. Unset VITE_GTM_ID before you upgrade if
you do not want that.
Remove VITE_GTM_ENABLED from your environment. The backend ignores it, so
leaving it in place is harmless but misleading.
The cookie-consent banner is gone too, along with the Consent Mode v2 bootstrap and the login-time auto-grant. A self-hosted deployment should not inherit the maintainer’s compliance model, so consent is now yours to configure inside your own tag container. Consent decisions stored in browsers are evicted on next load, not migrated.
GitHub App configuration moved to per-team settings (v0.9.0)
Section titled “GitHub App configuration moved to per-team settings (v0.9.0)”GitHub App credentials used to be instance-wide: one App in config.yaml,
shared by every team. They are now registered per team and stored encrypted
in the database. You must delete the top-level github: section from your
config.yaml or the backend refuses to start, drop the GITHUB_APP_* /
GITHUB_WEBHOOK_* environment variables, and re-register the App on each team
that uses the integration.
This does not affect auth.github, the GitHub web-login OAuth client.