# Pinning a kit version (using Ui@2)

> A kit like `Ui` is versioned independently of the platform, so you pin the major you build against with `using Ui@2;`. The number is a stability floor that never auto-crosses the next major. Platform capabilities (`Storage.Blob`, `Content.Markdown`, …) are version-neutral — they ride the platform version — so pinning one is a compile error.

<!-- id: ui-kit-versioning · area: ui · stability: stable · html: https://osysharp.com/reference/ui/kit-versioning/ -->

## Summary        {#summary}
A **kit** (like [the UI kit](https://osysharp.com/reference/ui/kit/)) is a library of components, vocabularies, and a theme that is versioned
**independently of the platform**. You pin the major version your app builds against by adding an `@major`
suffix to its `using`:

```osy syntax
using Ui@2;
```

`@2` is a **stability floor**: your app resolves to some `2.x`, and never silently jumps to a breaking `3.x`.
The version applies only to **kits** — the forkable, independently-shipped libraries. Ordinary **platform
capabilities** (`Storage.Blob`, `Memory`, `Content.Markdown`, `Observability`, …) are
version-neutral, so pinning one is rejected.

## Signature      {#signature}
```osy syntax
using Ui@2;        // any 2.x       — a major floor
using Ui@2.3;      // any 2.x ≥ 2.3 — a minor floor
using Ui@2.4.1;    // exactly 2.4.1 — an exact pin
```

The suffix is `@major[.minor[.patch]]`. A bare `@` with no number is an error.

## Description    {#description}
Kits and platform capabilities differ in one decisive way — **can you resolve an old or new version
independently?**

- A **kit** is composition (components, variant recipes, vocabulary members, a theme) shipped on its own
  cadence. An older or newer major exists as its own set of source, so pinning a version is meaningful.
- A **platform capability** is provided by the platform you run. There is no separate "version 2" of
  `Storage.Blob` to resolve to — it is whatever the running platform provides. The **platform version is its
  version**, so pinning would be a fiction.

Because of that, a version pin is legal **only on a kit**. Pinning a platform capability is a compile error
that names the fix:

```osy syntax
using Storage.Blob@2;
// error VERSION_ON_PLATFORM_CAPABILITY: 'using Storage.Blob@2;' pins a version on a platform capability,
// which is version-neutral (it rides the platform version). Drop the '@2' — a version pin is only meaningful
// on a kit (e.g. `using Ui@2;`).
```

If your app needs a newer platform (for a capability feature that only a newer platform provides), that is an
**app-level** requirement, not a per-capability pin. Requiring a minimum platform is expressed at the app level,
not by writing `@version` on a capability.

## Which exact version did I get? — `osyrin.lock`   {#lockfile}
Your `using Ui@2;` declares **intent** (a stability floor). The exact resolved version is recorded in
**`osyrin.lock`** so a build is reproducible across machines and matches what the server compiles — the same split
as `package.json` vs `package-lock.json`.

Run `osyrin lock` to resolve your pins and write the file:

```console
$ osyrin lock
✓ Wrote osyrin.lock (2 pins)
  Ui              2.0.0 (bundled)
  Storage.Blob    platform capability
```

Each kit entry records the resolved `version`, a `hash` of the resolved source (the integrity check — an edited or
stale local kit copy is caught when you `osy compile`), the `minPlatform` the kit needs, the `source` it came
from, and the `constraint` you declared. A platform capability is recorded without a version (it rides the
platform). The happy path is **offline**: a default pin resolves to the kit **bundled** with your platform — no
network. Pinning a version the bundled kit can't satisfy is a clear error, not a silent mismatch:

```console
$ osyrin lock          # with `using Ui@3;` but only 2.x bundled
ERROR  KIT_VERSION_UNAVAILABLE  'using Ui@3;' requests a version the bundled kit (2.0.0) does not satisfy…
```

## Updating & reconciling forks   {#updating}
Stay on your major but pick up the newest compatible kit with **`osyrin update`** — it re-resolves within the
declared major (never crossing to the next) and rewrites `osyrin.lock`:

```console
$ osyrin update ui
  Ui  2.0.0 → 2.1.0
✓ Updated 1 kit in osyrin.lock
```

After an update, **`osy diff`** shows how your forks in `ui/lib/` differ from the kit's new source, so you can
reconcile them (shadcn-style):

```console
$ osy diff ui/button
≠ Button (your fork vs kit default)
  + // my customization
```

A fork that matches the kit exactly is flagged as safe to drop.

Each vendored file records the kit version it was taken from, so `diff` can tell you the other thing a text
comparison cannot — that the **kit itself** has moved on since you forked:

```console
$ osy diff ui/button
! Button — forked from Osysharp.Ui 2.0.0, the kit is now 2.1.0. What follows includes the kit's own changes since.
```

That line is the real cost of a fork. The code is yours either way; what you give up is receiving improvements to
it, and this is how you find out what you are missing.

## Examples       {#examples}
Pin the UI kit's major and use a platform capability version-neutrally in the same manifest:

```osy title="pinning a kit, and a version-neutral capability" test app=ui-kit-versioning
app Shop {
  model "model/**/*.osy";
  use Osysharp.Ui@2;         // kit — pinned to major 2
  use Osysharp.Storage;      // platform capability — version-neutral, no @
}
```

⚠ A version pin belongs on the manifest's **`use`**, never on a source file's `using`. `using` is a C# import and
carries no version — `using Osysharp.Ui@2;` is refused with a message saying exactly this.

## See also       {#see-also}
- [Osysharp.Ui (the UI kit)](https://osysharp.com/reference/ui/kit/) — what the UI kit contributes and how to fork a control.
- [theme tokens](https://osysharp.com/reference/ui/theming/) — the design tokens a kit's controls share with your theme.
- [component](https://osysharp.com/reference/ui/component/) — declaring your own components (kit controls are just components).
