Adapter reference
Generated file — do not edit by hand. Regenerate from the repo root with
CGO_ENABLED=0 go run scripts/gen-adapters-md.go.
Adapters connect SHC to other self-hosting platforms. Each adapter understands one platform’s app grammar and on-box layout, and powers two verbs:
shc adapter loadtranspiles a live install of the platform into an adapted app — an SHC app package that runs on SHC — and pulls the app’s data with it.shc adapter migrate --fromextracts a platform app’s data package-free and replays it into the matching native SHC catalog app through a migration recipe — a transform into the native app, not a shim around the foreign one.
See the glossary: Adapter,
Adapted app,
shc adapter load,
shc adapter migrate.
Source of truth is the capability registry
(modules/adapter/capabilities.go);
shc adapter ls renders the same registry live from your binary.
Column key — Load / Migrate: the two verbs above. Env
capture: how live env/secret values are captured from the box
(none, file: <path>, or live-inspect: <mechanism>). Secret
minting: how foreign values classify as secrets and mint
(typed-schema | fixed | heuristic | none). Vars: whether the
foreign config grammar lowers into the typed vars DSL. Plugs:
whether platform addons map onto SHC capability socket+plug pairs.
Quiesce: the pause mechanism wrapped around a data pull so the
capture is a consistent point-in-time copy. Load proven /
Migrate proven are the validation honesty markers, tracked
SEPARATELY per verb (a live-proven load says nothing about migrate):
live = driven end-to-end against a real platform box; fixture =
fixture / fake-box + conformance validated only; unproven = no
meaningful validation yet; n/a — not supported = the verb is absent
by design (not a debt).
Total: 15 platforms — 13 load + migrate, 2 migrate-only.
Compose-based adapters
Section titled “Compose-based adapters”These platforms define apps as Docker Compose — plain, or with a manifest riding alongside — and transpile through the shared compose core.
| Adapter | Load | Load proven | Migrate | Migrate proven | Env capture | Secret minting | Vars | Plugs | Quiesce |
|---|---|---|---|---|---|---|---|---|---|
| casaos | yes | live | yes | live | compose-derived: installed compose env (values carried on Package.Secrets) | heuristic | yes | no | casaos-cli app-management stop (async) + compose-project drain poll |
| coolify | yes | live | yes | fixture | file: /data/coolify/services/<uuid>/.env | typed-schema | yes | no | docker compose -p <uuid> stop (no drain poll) |
| dockge | yes | live | yes | live | file: /opt/stacks/<id>/.env | heuristic | yes | no | cd /opt/stacks/<id> && docker compose stop (synchronous) |
| dokploy | yes | live | yes | live | file: /etc/dokploy/compose/<appName>/code/.env | heuristic | yes | no | docker compose -p <appName> stop + drain poll (composeType=stack has no non-destructive stop — live pull) |
| runtipi | yes | live | yes | live | file: runtipi/app-data/<store>/<id>/app.env | typed-schema | yes | no | runtipi-cli app stop (sudo) + compose-project drain poll |
| synology | yes | fixture | yes | fixture | compose-derived: project <share>/.env (values carried on Package.Secrets; docker-inspect backstop) | heuristic | yes | no | docker compose -p <project> stop (sudo, abs path) + compose-project drain poll |
| truenas | yes | fixture | yes | fixture | compose-derived: rendered compose inline env (values carried on Package.Secrets; docker-inspect backstop) | heuristic | yes | no | docker compose -p ix-<app> stop + drain poll (app.stop is destructive async) |
| umbrel | yes | live | yes | live | live-inspect: docker inspect <compose-project> env | fixed | yes | yes | docker stop by compose-project label + drain poll |
Own-transpiler adapters
Section titled “Own-transpiler adapters”These platforms have their own app grammar (JSON, XML, or template manifests — no compose upstream); each adapter ships a dedicated transpiler.
| Adapter | Load | Load proven | Migrate | Migrate proven | Env capture | Secret minting | Vars | Plugs | Quiesce |
|---|---|---|---|---|---|---|---|---|---|
| caprover | yes | live | yes | live | none | typed-schema | yes | no | docker service scale srv-captain--<app>=0 (replica stash) + drain poll (manager-only) |
| cloudron | yes | live | yes | live | none | fixed | yes | yes | no-op (native backup tarball is a point-in-time snapshot) |
| easypanel | yes | fixture | yes | fixture | compose-derived: state-store env block + db password fields (values carried on Package.Secrets) | heuristic | yes | no | docker service scale <project>_<svc>=0 (async) + drain poll + replica restore |
| portainer | yes | live | yes | live | live-inspect: docker inspect <container> env | heuristic | yes | no | docker stop <container> (no sudo shim, no drain poll) |
| unraid | yes | fixture | yes | fixture | compose-derived: my-<Name>.xml Config values (values carried on Package.Secrets) | typed-schema | yes | no | docker stop -t 10 <Name> + drain poll (root ssh) |
Migrate-only sources
Section titled “Migrate-only sources”Nothing loads from these platforms — their apps cannot run on SHC as adapted apps.
shc adapter migrate extracts the app’s data package-free and replays it into the
matching native SHC app through a migration recipe.
| Adapter | Load | Load proven | Migrate | Migrate proven | Env capture | Secret minting | Vars | Plugs | Quiesce |
|---|---|---|---|---|---|---|---|---|---|
| kube | no | n/a — not supported | yes | live | none | none | no | no | kubectl scale deploy/sts to 0 (replica stash) + pod-drain poll + helper-pod PVC stage |
| yunohost | no | n/a — not supported | yes | fixture | none | none | no | no | no-op (yunohost backup create = operator-run point-in-time snapshot) |
Per-adapter crown limits
Section titled “Per-adapter crown limits”One line per adapter: where the importer reads the platform’s install tree from (“live-synthesized catalog” means the platform keeps no static manifest tree, so the catalog is reconstructed over SSH from the live engine), and the adapter’s headline limit.
- caprover — live-synthesized catalog (root
/captain/data). limited load: only image-based apps (~84% of the catalog) load; built-from-source apps (img-captain-*images) are load-rejected but stay fully migrate-capable. - casaos — box tree
/var/lib/casaos/apps. no resolved env file exists on the box, so an imported datastore keeps the source box’s plaintext credentials while the adapted package re-mints fresh values at deploy — and the load report cannot flag the mismatch. - cloudron — box tree
/var/backups/snapshot. shared postgres/mysql/mongo/redis addon dumps inside the backup tarball are not imported — an app without a self-dump contract imports configured-but-empty; the tarball import path has no end-to-end proof. - coolify — box tree
/data/coolify/services. one-click services subset only; migrate recipes ship (gitea, invoice-ninja/mariadb) but no live-box migrate has been driven green end to end. - dockge — live-synthesized catalog (root
/opt/stacks). stacks hold app data as relative binds beside the compose, so the catalog fetch is per-stack config-only; expect a high gate-reject rate — dockge stacks are arbitrary user compose. - dokploy — box tree
/etc/dokploy/compose.composeType=stackapps have no non-destructive stop upstream (dokploy’s own stop isdocker stack rm), so their quiesce is a no-op and the pull is effectively live. - easypanel — box tree
/etc/easypanel. the platform’s headline source-build deploys (github/git/dockerfile/nixpacks/buildpacks) carry no pullable image and load-reject; the state store is closed-source, so live env capture is still owed. - kube — live-synthesized catalog. no live cluster has run this path — PVC/RWO/CSI fidelity must be proven on a real cluster; the Kubernetes-to-compose load lowering is a later increment.
- portainer — live-synthesized catalog (root
/var/lib/docker/volumes). quiesce is a plaindocker stopwith no sudo shim and no drain poll — a passwordless-sudo-but-no-docker-group login silently degrades every pull to a live capture; live env values are never seeded into secrets. - runtipi — box tree
runtipi/apps. thebackup.yamlephemeral-volume exclusion is a substring heuristic — a data volume named…cache…is wrongly excluded. - synology — live-synthesized catalog (root
/var/packages/ContainerManager/etc/projects). a project’s live values ride its<share>/.env, whose box path is not recoverable from the importer’s handle — no live-secret seeding is wired;.spk-packaged apps are out of scope. - truenas — box tree
/mnt/.ix-apps/app_configs.host_pathstorage points at arbitrary, multi-TB SMB-shared user datasets and is treated as an external reference — never captured; onlyix_volumeand docker named volumes travel. - umbrel — box tree
umbrel/app-data. never live-imported; only the curatedexports.shprofiles (bitcoin, electrs) lower manifest dependencies onto plugs — every other dependencies/exports.sh app gates. - unraid — box tree
/boot/config/plugins/dockerMan/templates-user.ExtraParamsis a raw docker-run flag string — the adapter tokenizes it and folds each dangerous flag onto the synthesized compose so the shared gate rejects it; manifests (USB flash) and data (array) live on disjoint filesystems. - yunohost — box tree
/home/yunohost.backup/archives. migrate-only by design — apps are Debian packages over a shared server-side database, so nothing can load; migration recipes are the scarce resource.