Pack Versioning
How pack versions flow from your repository through the catalog to what actually runs — semver rules, the release checklist, version pins, update policies, breaking-change detection, and SDK compatibility.
This page is the end-to-end picture of pack versioning: what a version is, every place it must be declared when you release one, and what the platform does with it — from catalog sync to the moment a workflow executes your integration's code.
The version model
Three layers carry a version, and they serve different purposes:
| Layer | Declared in | Purpose |
|---|---|---|
| Pack version | pack.json → package.version, and the source's catalog index (scrydon.yaml → version) | Identifies a catalog row. The catalog keeps one row per (packId, version) — releasing 1.2.0 adds a row; the 1.1.0 row stays. |
| Content-entry version | pack.json → contents[].version and each subdir manifest (e.g. integration-acme/manifest.json → version) | Per-kind version inside the pack. For integrations it must match the version compiled into the artifact. |
| Artifact version | Inside the built bundle (defineVendor({ version }) for integrations) | What the platform registers and what update comparisons use. The install verifies it matches the content entry — a mismatch rejects the install. |
All versions are semver (MAJOR.MINOR.PATCH, pre-release suffixes like 2.0.0-beta.1 sort below the release). The platform compares versions numerically — 1.10.0 is newer than 1.9.0.
Old versions never disappear on their own. Catalog rows for previous versions stay live (they power rollback and the "Other live catalog versions" list). Everything that decides what is current — the marketplace, the Packs page, the runtime — selects the highest-semver live version, honoring any version pin (below). You never need to delete old rows for a new release to take effect.
Releasing a new version — the checklist
A release only propagates when every layer moves together. Forgetting one is the most common publishing mistake — in particular the catalog index: the sync reconciler compares index versions, so a bumped pack.json behind an unchanged scrydon.yaml entry is silently skipped on every sync.
For integrations: defineVendor({ version: "1.2.0" }) (or your build's equivalent), then rebuild the artifact — bunx @scrydon/sdk-authoring integrations build produces dist/{vendorId}-1.2.0.bundle.tar.gz.
The subdir manifest (integration-*/manifest.json → version) and the matching contents[] entry in pack.json must declare the same version as the artifact. The install verifies artifact identity against the catalog entry and rejects mismatches.
pack.json → package.version. Convention: the pack version moves at least as fast as its fastest-moving content entry.
For Git/OCI pack sources: the scrydon.yaml entry for your pack (version:) must be bumped to the new version. This is the field the reconciler keys on — without it, nothing else you changed is ever picked up.
If your repo commits built output (the recommended layout), rebuild dist/ and run your verify gate so dist/ matches src/. Push/publish; the platform syncs the source on its interval (default every 5 minutes) or immediately via Refresh on the source in Settings → Platform → Packs.
Pick the right bump
| Bump | Use when | Platform behavior |
|---|---|---|
Patch (1.1.1 → 1.1.2) | Bug fixes, no surface changes | Eligible for auto_patch and auto_minor policies |
Minor (1.1.x → 1.2.0) | New tools, new optional inputs, new capabilities | Eligible for auto_minor |
Major (1.x → 2.0.0) | Anything breaking: removed/renamed tools, new required inputs, changed input/output types, auth-mode changes | Always manual; the update review shows a breaking warning |
The platform verifies your choice rather than trusting it — see breaking-change detection.
What happens after a release lands
A new version arriving in the catalog is deliberately inert:
- The sync adds a catalog row for the new version (and, for integration content, stores the artifact). Nothing about what runs has changed yet.
- Every installed integration is pinned to the version it was installed at. The pin — not the newest row — decides which version the marketplace lists, which manifest tools/blocks resolve from, and which code executes in the sandbox.
- The new version surfaces as Update available on the Packs page and as an Update badge on the integration's marketplace card.
- The pin moves in exactly two ways:
- Manually — an admin clicks Update pack after the impact review. In-flight workflow runs finish on the version they started with; new runs use the new version.
- Automatically — connections that opted in via an update policy:
| Policy | Auto-applies |
|---|---|
manual (default) | Nothing — updates wait for the Packs page |
auto_patch | Patch bumps with no detected breaking changes |
auto_minor | Patch + minor bumps with no detected breaking changes |
Major bumps and any update with detected breaking changes always wait for manual review (the connection shows update blocked: breaking_diff until an admin reviews it).
Breaking-change detection and semver honesty
When an update is available, the platform diffs the installed and target manifests and classifies the changes:
| Change | Classification |
|---|---|
| Tool, product, or block removed or renamed | Breaking |
| New required input field; existing field removed or type changed | Breaking |
| Output field removed or type changed | Breaking |
| Auth mode changed (e.g. apiKey → OAuth) | Breaking |
| New tool/product, new optional input, description changes | Compatible |
The findings appear in the update review on the Packs page, next to the list of affected workflows. Two warning levels:
- Potentially breaking (amber) — a major bump, or breaking findings correctly shipped as a major.
- Breaking changes in a non-major update (red) — the diff found breaking changes but you shipped a minor or patch. Auto-update policies refuse it, and admins see the stronger warning. Don't do this — re-release as a major.
SDK contract compatibility
Integration artifacts are compiled against a specific generation of the platform↔bundle runtime contract (the shape of ctx.auth, the dispatch protocol). The SDK stamps this contract version into your manifest automatically at build time — you never declare it by hand.
- The platform supports the current and the immediately previous generation; previous-generation bundles run through an automatic compatibility translation.
- A bundle built against an unsupported generation is refused at install (
integration_contract_incompatible) and at run time (BUNDLE_CONTRACT_INCOMPATIBLE) with a message naming the versions involved. Both mean the same thing: rebuild and republish with a current@scrydon/sdk-authoringrelease (a patch release of your pack is enough).
Practical rule: rebuild your packs with a current SDK whenever you cut a release, and you will never be more than one generation behind.
Rolling back
Because old catalog rows and old installed versions are retained, an admin can roll an integration back to any previous version from the version management surface — the pin moves backwards and in-flight runs drain first, the same mechanics as an upgrade. Rollback never requires re-publishing anything from your side.
Exceptions by content kind
- Process flows always track the latest live catalog version — they have no pinned installed version and no update action.
- Ontologies, KB domains, workflows, data sources are versioned per install; the Packs page shows their per-kind install state.
Related pages
- Pack version management — the admin-facing UI walkthrough (install state, update bar, impact review).
- Pack sources —
scrydon.yaml, Git/OCI layout, sync behavior, signature policies. - Packaging a custom integration in a pack — subdir layout and the install flow.