Publishing an adapter¶
This section is for third-party and partner developers who have built an adapter against
Pq.Adapters.Framework and now need to ship it so that a customer's Protequ installation can
find, install and run it.
Everything the platform needs to know about your adapter travels inside the image itself,
as OCI labels. There is no manifest to submit, no YAML to register, no entry to add to a
central list: you build one Linux container image, label it correctly, push it to
repo.protequ.com, and it appears in the installer's adapter catalog and on the public
adapter page.
your repo repo.protequ.com customer's box
───────── ──────────────── ──────────────
Dockerfile pq-installer
LABEL org.protequ.* ──► pq/<image>:1.0.0 ──► reads /v2/… labels
ENTRYPOINT dotnet … pq/<image>:latest ├─ shows it in the catalog
├─ writes the compose service
└─ writes the nginx route (UI only)
│
└──────────────► protequ.github.io catalog page
Because the labels are the contract, a typo in a label is a deployment bug — see Label reference.
Prerequisites¶
| You need | How you get it |
|---|---|
| A Protequ registry account (username + token) | Issued by Protequ. Grants push access to the pq namespace on repo.protequ.com. |
| Read access to the PQ NuGet feed | Same account. Feed: https://repo.protequ.com/api/packages/PQ/nuget/index.json. |
| .NET 10 SDK | For building the adapter locally. |
| Docker with Buildx | For building and pushing the image. |
| A working adapter | See Getting started and Local dev setup. |
Never commit the token. In CI it belongs in a repository secret; locally it belongs in
docker login/dotnet nuget add source, not in a file you push.
The procedure¶
1. Choose the image name¶
The image name is an identifier, not a display name — it drives the container name, the compose profile and the tag override variable on the customer's box.
- lowercase and prefixed with
pq:pqacme,pqtechfass,pqhikvision - keep the name stable forever; hyphens are allowed, but the installer converts them to underscores
only in the tag override variable, for example
pq-toolsbecomesPQ_TOOLS_TAG - one image per adapter, stable forever (renaming it looks like a different adapter)
Full reference: repo.protequ.com/pq/pqacme. See Registry for
what the installer derives from this name.
2. Build the adapter against the published framework¶
Your project references Pq.Adapters.Framework from the PQ feed — you do not need the Protequ
monorepo. The package carries the source generator, the framework YAML files and the bundled
Pq.Domain / Pq.Messaging assemblies. See Image anatomy.
3. Write the Dockerfile¶
Multi-stage: SDK image builds and publishes, chiseled runtime image runs. The final stage
carries the LABEL block. Full worked example: Image anatomy.
4. Label the image¶
At minimum org.opencontainers.image.title, .description, .vendor,
org.protequ.adapter="true", org.protequ.category and org.protequ.device_vendor.
Everything else is optional and additive. Full table: Label reference.
5. Build and smoke-test locally¶
docker build -t pqacme:dev -f Dockerfile .
docker run --rm -e Mq__Host=host.docker.internal:4222 -e Mq__User=<nats-user> -e Mq__Password=<nats-password> pqacme:dev
The adapter should connect to NATS and register. The NATS credentials are the ones configured for the PQ deployment you are pointing at — ask whoever runs it. If you have no PQ stack to test against, see Local dev setup for how to reach NATS from outside the PQ deployment.
Then confirm the labels actually landed on the image:
6. Tag with a semver version¶
1.0.0 for a release, 1.0.0-rc.1 for a prerelease. The version is the image tag — there is
no other version field. See Tagging rules.
7. Push to repo.protequ.com¶
Either from CI (recommended — worked GitHub Actions example) or by hand (manual push).
8. Verify it is discoverable¶
Pull the labels back out of the registry and confirm the adapter shows up in the installer's catalog. See Verifying the publish.
Release checklist¶
- [ ] Image name is lowercase,
pq-prefixed, and unchanged from the previous release - [ ] Final stage is a chiseled .NET runtime image, running as
$APP_UID(non-root) - [ ]
org.protequ.adapter="true"is present — without it the adapter is invisible - [ ]
org.protequ.categoryis one of the known values (see Label reference) - [ ]
org.opencontainers.image.title/.descriptionread well on a catalog card - [ ] Any extra ports, volumes, env or dependencies are declared as labels, not documented in prose
- [ ] Version tag is valid semver; a prerelease carries a
-and does not movelatest - [ ]
docker inspecton the built image shows every label you expect - [ ] The pushed image resolves in the registry and appears in the installer catalog