diff --git a/docs/developer-guide/adrs/016-airgapped-catalog-chaining.md b/docs/developer-guide/adrs/016-airgapped-catalog-chaining.md
new file mode 100644
index 00000000..468f4aee
--- /dev/null
+++ b/docs/developer-guide/adrs/016-airgapped-catalog-chaining.md
@@ -0,0 +1,343 @@
+---
+status: proposed
+date: 2026-08-19
+---
+
+# Air-Gapped Catalog Chaining via Offline OCM Transport
+
+> **Decision at a glance.** For a *fully* air-gapped destination Solar chains its
+> catalog **over physical media, not a network**. The transport layer from
+> [ADR 013](013-catalog-chaining.md) — ARC, an online OCI diode — is replaced by a
+> **self-contained, signed OCM CTF archive** carried across the boundary and imported
+> into the destination registry. **Everything downstream of that registry is
+> unchanged from ADR 013**: Solar Discovery scans the destination registry and builds
+> the catalog. The primary pattern **ships the full catalog** so Solar runs *inside*
+> the air-gap and operators select in-domain; a lighter *render-then-transport*
+> pattern is also supported.
+
+## Context and Problem Statement
+
+[ADR 013 — Solar Catalog Chaining via ARC](013-catalog-chaining.md) describes chaining
+a source Solar catalog to one or more destination Solar instances across a security
+boundary. It considered only boundaries that are **connected, at least temporarily**,
+and explicitly deferred the disconnected case ("How we handle catalog chaining between
+air-gapped environment or if at all"). This ADR (spike #581) answers that.
+
+[ADR 013's decision](013-catalog-chaining.md#decision-outcome) has two independent halves:
+
+1. **Pulling OCM packages source → destination** — via ARC, an *online* OCI diode that
+ creates Orders which pull artifacts across the boundary.
+2. **Building the destination catalog** — [Option C: Registry Scan by Solar
+ Discovery](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery): Solar
+ Discovery scans the *destination registry* and turns every OCM package into a
+ Component / ComponentVersion.
+
+In a fully air-gapped environment **half 1 is impossible** — there is no network path
+for ARC to pull over. But **half 2 does not care how packages arrived**: the
+destination registry is the interface, and Discovery simply scans it. So the problem
+reduces to one thing: **replace the online transport with an offline one, and reuse
+everything from the destination registry inward.**
+
+[ADR 013's guiding principles](013-catalog-chaining.md#guiding-principles) carry over unchanged and make this clean:
+
+- **OCM is the packaging format**; the OCM component descriptor is the authoritative
+ metadata.
+- **Only OCM packages cross the boundary** — no Solar CRDs. Components and
+ ComponentVersions are derived on the destination side.
+- The transfer layer is a **diode**. ADR 013's diode was a network component (ARC);
+ here it is **physical** — removable media hand-carried across the boundary. Solar is
+ agnostic to which medium is used.
+
+## Decision Drivers
+
+- **No network path** may cross the boundary; the only channel is offline media.
+- **Reuse ADR 013** wherever possible — do not re-decide the destination catalog model.
+- **Untrusted channel**: physical media can be lost, swapped, or tampered with, so the
+ payload must be verifiable on its own — every OCM component version carries a signature
+ that the destination verifies (`ocm verify cv`) against a **trusted public key
+ provisioned out-of-band** (not on the same medium).
+- **Air-gap autonomy**: operators inside the boundary should be able to work without
+ any dependency on the source environment.
+- **Self-contained payload**: everything needed to deploy (descriptors, charts,
+ images) must be present locally; nothing may resolve to an external registry at
+ render or deploy time.
+- **Incremental build-up**: the catalog grows over time as successive media arrive.
+
+## Considered Options
+
+### Transport across the boundary
+
+- **Online OCI diode (ARC), as in ADR 013.** Not applicable: it requires a network
+ path across the boundary, which by definition does not exist in a full air-gap.
+- **Offline OCM CTF on physical media (chosen).** A **by-value** transfer
+ (`ocm transfer ... --copy-resources --recursive`) writes a self-contained **Common
+ Transport Format** archive — component descriptors plus every referenced resource and image
+ *copied in*, not left as external references — to a directory/tar. The archive is carried
+ across on removable media and imported into the destination OCI registry with
+ `ocm transfer`. This preserves every ADR 013 invariant (OCM is the format, only OCM packages
+ cross, no Solar CRDs cross); only the carrier changes.
+
+### What crosses, and where selection happens
+
+- **Ship the catalog (chosen).** The *full* catalog and its dependency
+ closure cross as one CTF. **Solar runs inside the air-gapped target**; Solar Discovery
+ scans the destination registry ([ADR 013 Option C](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery), verbatim) and operators select and
+ roll out **in-domain**. This is the "catalog build-up in the air-gap" the spike is
+ about, and it maximises air-gap autonomy.
+- **Render then transport (alternative).** Selection and rendering happen
+ on the *connected* source; only the rendered rollout crosses; the destination is thin
+ (registry + FluxCD, no Solar catalog). Smaller payload and central control, but no
+ in-domain catalog or selection, and pre-rendered artifacts can go stale before they
+ are applied.
+
+## Decision Outcome
+
+Support air-gapped chaining with **offline OCM CTF transport**, and make the
+**ship-the-catalog** pattern primary. **For the ship-the-catalog pattern**, everything
+from the destination registry inward is ADR 013 unchanged (Solar Discovery builds the
+catalog, [Option C](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery)).
+The render-then-transport alternative deliberately omits the catalog — it runs only a
+registry and FluxCD, so Option C does not apply there.
+
+```mermaid
+sequenceDiagram
+ autonumber
+
+ box rgb(232,244,253) Connected Domain
+ participant Src as Catalog Source
+ end
+
+ participant USB as USB Stick
(OCM CTF — full catalog)
+
+ box rgb(253,237,236) Air-Gapped Domain
+ participant Reg as Registry
(air-gap edge)
+ participant SolAr as SolAr
(in target)
+ actor User as Operator
+ end
+
+ Note over Src,USB: Export the full catalog
+ Src->>USB: export all applications + dependencies
+ Note over USB: Complete offline catalog packaged by a
NEW TOOL into one OCM CTF archive.
+
+ Note over Src,Reg: ✂ AIR-GAP BOUNDARY — USB stick carried across ✂
+ Note over USB: No network path crosses the boundary —
the USB stick is the ONLY transfer channel.
+
+ Note over Reg,User: Verify component versions, then seed the catalog
+ User->>User: ocm verify cv — each component version
+ alt any verification fails
+ Note over User: reject — nothing is imported
+ else all component versions verified
+ User->>Reg: import OCM CTF from USB
+ end
+ Note over Reg: Registry is the INTERFACE
that backs the in-domain catalog.
+ SolAr->>Reg: discover available solutions
+ Reg-->>SolAr: catalog contents
+
+ Note over Reg,User: Select & roll out — inside the air-gap
+ User->>SolAr: pick applications + settings
+ SolAr->>Reg: resolve manifests
+ Reg-->>SolAr: pinned components
+ SolAr->>SolAr: deploy to target
(FluxCD, gitless GitOps)
+ SolAr-->>User: applications running on-site
+```
+
+*Diagram source: [`img/016-airgap-ship-the-catalog.mmd`](img/016-airgap-ship-the-catalog.mmd).*
+
+How it works, and what changes versus ADR 013:
+
+1. **Export (source).** A tool derives the package set from the source Solar catalog —
+ the full catalog plus its dependency closure — and `ocm transfer`s it **by value**
+ (`--copy-resources --recursive`) into a single, self-contained CTF archive.
+ *(This replaces [ADR 013's ARC Orders](013-catalog-chaining.md#option-a-1-solar-catalog-scan-by-arc); see "The export /
+ import tool" below.)*
+2. **Sign (source).** Each component version is signed with `ocm sign cv` — OCM signs the
+ component descriptors, not the archive blob — so the destination can establish trust
+ without a live connection to the source.
+3. **Carry across.** The archive crosses on removable media. No network path exists;
+ the medium is the only channel.
+4. **Verify + import (destination).** Every component version is verified with
+ `ocm verify cv` against the trusted public key (provisioned out-of-band); only then
+ does `ocm transfer` load the archive into the **destination registry** — the interface
+ that backs the in-domain catalog.
+5. **Build the catalog (destination).** *Unchanged from [ADR 013 Option C](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery):* Solar
+ Discovery scans the destination registry and creates Components / ComponentVersions.
+6. **Select and roll out (destination).** Operators select applications and settings in
+ the in-domain Solar; rendering happens locally against the target's current state,
+ and FluxCD reconciles from the destination registry ("gitless GitOps").
+
+**Keeping deployments self-contained.** A by-value transfer copies every resource into the
+CTF, but **OCM does not rewrite the registry references embedded inside a chart's manifests**
+(e.g. a Helm chart's `image:` values). Those are re-pointed at the destination registry at
+**render time** by Solar Discovery / ocm-kit's Helm value templating — the mechanism from
+[ADR 013's OCI URL re-mapping](013-catalog-chaining.md#oci-url-re-mapping) (and ADR 011). In
+the ship-the-catalog pattern this happens in-domain, so a deployed workload resolves nothing
+from the source or an external registry. The render-then-transport alternative renders on the
+*source*, so its references must already target the destination registry before crossing — a
+caveat of that pattern.
+
+**The export / import tool.** Both scenarios name a "new tool". Its job is thin: on the
+source, derive the wanted package set from the Solar catalog and write a signed CTF; on
+the destination, verify and import. It wraps `ocm transfer` / ocm-kit rather than
+inventing a new format. The exact package-set derivation (full catalog vs. a selected
+subset) is the difference between the two scenarios; a detailed tool design is scoped
+out below.
+
+**Bootstrapping Solar into the air-gap.** The ship-the-catalog pattern runs Solar itself inside the
+boundary, which is a chicken-and-egg: Solar's own images and Helm chart must arrive on
+the *first* transport before it can serve a catalog. The initial seed therefore includes
+Solar's components (as OCM packages); subsequent transports carry catalog content and
+updates.
+
+**Incremental build-up and GC.** OCM CTF transfer is additive: later archives bring new
+or updated components, and the destination registry accumulates. This is exactly the
+growth that [ADR 015 — Catalog and Registry Garbage Collection](015-catalog-registry-garbage-collection.md)
+governs; availability reconciliation and the retention janitor apply to an air-gapped
+destination the same as anywhere else.
+
+### Alternative pattern — render then transport
+
+When in-domain selection is not needed, a lighter pattern selects and renders on the
+connected source and ships only the rendered rollout; the destination runs just a
+registry and FluxCD. ADR 013's destination catalog model
+([Option C](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery)) does
+**not** apply here — there is no catalog on the air-gapped side, only reconciliation. The
+exact artifact contract for these pre-rendered rollouts — CTF layout, OCI paths, and how the
+destination `OCIRepository` pins each by immutable digest — is part of the deferred
+export/import tool design (see *Scope*); and because rendering happens on the source, the
+embedded registry references must already point at the destination registry before the CTF is
+sealed.
+
+```mermaid
+sequenceDiagram
+ autonumber
+
+ box rgb(232,244,253) Connected Domain
+ actor User as Operator
+ participant SolAr as SolAr
+ end
+
+ participant USB as USB Stick
(OCM CTF)
+
+ box rgb(253,237,236) Air-Gapped Domain
+ participant Reg as Registry
(air-gap edge)
+ participant Cluster as Target Cluster
(FluxCD)
+ actor Ops as Air-gap Operator
+ end
+
+ Note over User,SolAr: Select & Render
+ User->>SolAr: pick target cluster + applications
+ SolAr->>SolAr: render manifests
(pin OCM components)
+ SolAr-->>User: rollout package ready
+
+ Note over User,USB: Package onto transport medium
+ User->>USB: export as one OCM CTF archive
+ Note over USB: Collected by a NEW TOOL into a single,
self-contained OCM CTF archive.
+
+ Note over SolAr,Reg: ✂ AIR-GAP BOUNDARY — USB stick carried across ✂
+ Note over USB: No network path crosses the boundary —
the USB stick is the ONLY transfer channel.
+
+ Note over Reg,Ops: Verify component versions,
then load & reconcile
+ Ops->>Ops: ocm verify cv — each component version
+ alt any verification fails
+ Note over Ops: reject — nothing is imported
+ else all component versions verified
+ Ops->>Reg: import OCM CTF from USB
+ end
+ Note over Reg: Registry is the INTERFACE
to the air-gapped side.
+ Cluster->>Reg: reconcile (poll OCI artifacts)
+ Reg-->>Cluster: manifests + images
+ Cluster->>Cluster: apply / prune
("gitless GitOps")
+```
+
+*Diagram source: [`img/016-airgap-render-then-transport.mmd`](img/016-airgap-render-then-transport.mmd).*
+
+Trade-offs versus the primary pattern: smaller payload and central control, but the destination
+has no catalog and no in-domain selection, the operator on the connected side must know
+in advance what the target should run, and a rendered rollout can go stale between
+render and apply. It fits fixed, pre-defined deployments; it does not "build up" a
+catalog in the air-gap.
+
+### Effect on ADR 013
+
+[ADR 013](013-catalog-chaining.md) remains the record for the connected case and is not modified. This ADR reuses
+its destination model (Option C) verbatim and only substitutes the transport layer for
+the air-gapped case. ARC stays a separate product, relevant when a (temporary) network
+path exists; it is not required — and not present — in a full air-gap.
+
+### Consequences
+
+Positive:
+
+- Minimal new surface: only the transport changes; the destination catalog model, the
+ rendering pipeline, and gitless GitOps are all reused from ADR 013.
+- Full air-gap autonomy (ship-the-catalog): operators select and deploy with no dependence on
+ the source environment.
+- Self-contained and verifiable: a signed CTF needs no live trust path to the source.
+- Medium-agnostic: the same signed OCM CTF payload works regardless of which removable
+ medium carries it.
+
+Negative and trade-offs:
+
+- **Fat payload (ship-the-catalog):** the full catalog plus dependency closure must be
+ transported, and re-transported for updates (CTF transfer is additive, which limits
+ this to deltas after the first seed).
+- **Bootstrapping:** Solar must be seeded into the air-gap before it can serve a
+ catalog.
+- **Manual, high-latency channel:** transport cadence is human-driven; there is no
+ real-time sync.
+- **No feedback to source:** the source cannot observe destination state; any
+ reconciliation of "what the destination has" is out of band.
+- **Signing is mandatory, not optional:** without a live source, per-component-version
+ OCM signatures — verified against an out-of-band trusted key — are the only trust
+ anchor. Provisioning and rotating that key is a deferred decision (see Scope).
+
+### Confirmation
+
+- A CTF exported on the source and carried across (no network path) imports into the
+ destination registry and Solar Discovery builds the expected catalog — proving the
+ destination model is reused unchanged.
+- Import is rejected when any component version fails `ocm verify cv` (untrusted-media case).
+- In the ship-the-catalog pattern, an operator selects and rolls out an application entirely inside the
+ air-gap, with no source connectivity.
+- A second, later CTF adds/updates components incrementally without re-seeding from
+ scratch.
+- Nothing in a deployed workload resolves to an external registry (self-contained
+ payload).
+
+## Scope
+
+Decided here: that air-gapped chaining is supported, and that it works by offline
+signed OCM CTF transport with the destination model reused from ADR 013, with the
+ship-the-catalog pattern as primary.
+
+Out of scope / follow-up:
+
+- **Detailed export/import tool design** — package-set derivation, CTF layout, signing
+ workflow, incremental-delta computation.
+- **A leaner in-air-gap Solar footprint** ("SolAr light") — deliberately deferred.
+- **Registry/catalog GC in the air-gapped destination** — governed by
+ [ADR 015](015-catalog-registry-garbage-collection.md); not re-decided here.
+- **One-way data-diode boundaries** — a data diode is a controlled *network* path, not
+ a full air-gap; it is a different boundary model with its own threat model and belongs
+ in a separate ADR, not here.
+- **Trusted-key provisioning and rotation for boundary signing** — imports are verified
+ with `ocm verify cv` against a trusted public key that must reach the destination
+ out-of-band; the key-management mechanism (provisioning, rotation, per-source vs.
+ shared) is a separate decision, not settled here. [ADR 014](014-artifact-signing.md)
+ covers rendered-artifact signing at deploy time — a different layer.
+
+## More Information
+
+- Diagrams: [`img/016-airgap-ship-the-catalog.mmd`](img/016-airgap-ship-the-catalog.mmd)
+ (primary), [`img/016-airgap-render-then-transport.mmd`](img/016-airgap-render-then-transport.mmd)
+ (alternative).
+- [ADR 013 — Solar Catalog Chaining via ARC](013-catalog-chaining.md) — the connected
+ case; its [Option C](013-catalog-chaining.md#option-c-registry-scan-by-solar-discovery)
+ destination model is reused here.
+- [ADR 014 — Solar Artifact Signing](014-artifact-signing.md) — a *complementary* layer:
+ cosign signing of *rendered artifacts* verified by FluxCD at deploy time; it does **not**
+ cover OCM package signing at the import boundary (see Scope).
+- [ADR 015 — Catalog and Registry Garbage Collection](015-catalog-registry-garbage-collection.md)
+ — governs the accumulating destination registry.
+- [Spike #581](https://github.com/opendefensecloud/solution-arsenal/issues/581);
+ decision on whether to support the use case tracked in odd-internal#70.
diff --git a/docs/developer-guide/adrs/img/016-airgap-render-then-transport.mmd b/docs/developer-guide/adrs/img/016-airgap-render-then-transport.mmd
new file mode 100644
index 00000000..14813e5d
--- /dev/null
+++ b/docs/developer-guide/adrs/img/016-airgap-render-then-transport.mmd
@@ -0,0 +1,43 @@
+%% Air-Gapped Catalog Chaining — Alternative pattern: Render, Transport, Gitless GitOps
+%% Selection + rendering happen in the CONNECTED domain. The result is packaged
+%% into an OCM Common Transport Format (CTF) archive on a USB stick, carried
+%% across the air-gap boundary, and reconciled into the AIR-GAPPED domain.
+sequenceDiagram
+ autonumber
+
+ box rgb(232,244,253) Connected Domain
+ actor User as Operator
+ participant SolAr as SolAr
+ end
+
+ participant USB as USB Stick
(OCM CTF)
+
+ box rgb(253,237,236) Air-Gapped Domain
+ participant Reg as Registry
(air-gap edge)
+ participant Cluster as Target Cluster
(FluxCD)
+ actor Ops as Air-gap Operator
+ end
+
+ Note over User,SolAr: Select & Render
+ User->>SolAr: pick target cluster + applications
+ SolAr->>SolAr: render manifests
(pin OCM components)
+ SolAr-->>User: rollout package ready
+
+ Note over User,USB: Package onto transport medium
+ User->>USB: export as one OCM CTF archive
+ Note over USB: Collected by a NEW TOOL into a single,
self-contained OCM CTF archive.
+
+ Note over SolAr,Reg: ✂ AIR-GAP BOUNDARY — USB stick carried across ✂
+ Note over USB: No network path crosses the boundary —
the USB stick is the ONLY transfer channel.
+
+ Note over Reg,Ops: Verify component versions,
then load & reconcile
+ Ops->>Ops: ocm verify cv — each component version
+ alt any verification fails
+ Note over Ops: reject — nothing is imported
+ else all component versions verified
+ Ops->>Reg: import OCM CTF from USB
+ end
+ Note over Reg: Registry is the INTERFACE
to the air-gapped side.
+ Cluster->>Reg: reconcile (poll OCI artifacts)
+ Reg-->>Cluster: manifests + images
+ Cluster->>Cluster: apply / prune
("gitless GitOps")
diff --git a/docs/developer-guide/adrs/img/016-airgap-ship-the-catalog.mmd b/docs/developer-guide/adrs/img/016-airgap-ship-the-catalog.mmd
new file mode 100644
index 00000000..2a022bb9
--- /dev/null
+++ b/docs/developer-guide/adrs/img/016-airgap-ship-the-catalog.mmd
@@ -0,0 +1,44 @@
+%% Air-Gapped Catalog Chaining — Primary pattern: Ship the Catalog, Select On-Site
+%% The FULL catalog (all applications + dependencies) is exported into an OCM
+%% Common Transport Format (CTF) archive on a USB stick and carried across the
+%% air-gap boundary. SolAr runs inside the AIR-GAPPED target, where local users
+%% select applications + settings that roll out in-domain.
+sequenceDiagram
+ autonumber
+
+ box rgb(232,244,253) Connected Domain
+ participant Src as Catalog Source
+ end
+
+ participant USB as USB Stick
(OCM CTF — full catalog)
+
+ box rgb(253,237,236) Air-Gapped Domain
+ participant Reg as Registry
(air-gap edge)
+ participant SolAr as SolAr
(in target)
+ actor User as Operator
+ end
+
+ Note over Src,USB: Export the full catalog
+ Src->>USB: export all applications + dependencies
+ Note over USB: Complete offline catalog packaged by a
NEW TOOL into one OCM CTF archive.
+
+ Note over Src,Reg: ✂ AIR-GAP BOUNDARY — USB stick carried across ✂
+ Note over USB: No network path crosses the boundary —
the USB stick is the ONLY transfer channel.
+
+ Note over Reg,User: Verify component versions, then seed the catalog
+ User->>User: ocm verify cv — each component version
+ alt any verification fails
+ Note over User: reject — nothing is imported
+ else all component versions verified
+ User->>Reg: import OCM CTF from USB
+ end
+ Note over Reg: Registry is the INTERFACE
that backs the in-domain catalog.
+ SolAr->>Reg: discover available solutions
+ Reg-->>SolAr: catalog contents
+
+ Note over Reg,User: Select & roll out — inside the air-gap
+ User->>SolAr: pick applications + settings
+ SolAr->>Reg: resolve manifests
+ Reg-->>SolAr: pinned components
+ SolAr->>SolAr: deploy to target
(FluxCD, gitless GitOps)
+ SolAr-->>User: applications running on-site