Preview release.These docs are a work in progress. Pages are still being written, links may break, and structure may shift without notice. Treat everything here as a draft and report issues onGitHub.
Connect Notary to a Registry Data API source
Registry Notary runs as its own project against any Registry Data API-shaped source: a source exposing the Registry Data API contract, the protected read API shape Registry Relay serves. This tutorial generates a standalone Notary project, points it at that source, and evaluates a starter claim against it.
The reproducible path in this tutorial uses the local Relay project from Run a protected registry API locally as a stand-in source.
If your source is not Registry Data API-shaped, put a source-adapter sidecar in front of it: see Adapt a custom HTTP source for the engine that fits your source.
This tutorial uses synthetic data and local demo credentials. Do not use the generated local keys in production.
Start with a running source
Section titled “Start with a running source”For a local reproducible source, complete the first tutorial and leave the Relay project running:
registryctl init relay my-first-api --sample benefitscd my-first-apiregistryctl startregistryctl smokeset -a. secrets/local.envset +aThe set -a block exports ROW_READER_RAW, which the standalone Notary project uses once when it
is generated.
Create the Notary project
Section titled “Create the Notary project”From the parent directory of my-first-api, create the standalone Notary project:
cd ..registryctl init notary my-standalone-notary \ --source-url http://registry-relay:8080 \ --source-network my-first-api_default \ --source-token-from-env ROW_READER_RAWcd my-standalone-notary--source-token-from-env ROW_READER_RAW reads the token value from your current shell and writes it
into the new project’s secrets/local.env.
my-first-api_default is the Compose network name Docker derives from the Relay project directory.
If you named that directory differently, use that name with the _default suffix.
Start Notary
Section titled “Start Notary”Start the standalone project:
registryctl startregistryctl starts Notary, waits for readiness, and prints the local API URL:
Notary API: http://127.0.0.1:4255API docs: http://127.0.0.1:4255/docsRun the smoke check:
registryctl notary smokeThe smoke check lists claims, evaluates the generated starter claim, and writes a detailed report:
output/notary-smoke-results.jsonEvaluate the starter claim
Section titled “Evaluate the starter claim”Load this project’s local keys:
set -a. secrets/local.envset +aEvaluate the starter claim:
curl -sS -X POST \ -H "x-api-key: $REGISTRY_NOTARY_TUTORIAL_EVALUATOR_RAW" \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.registry-notary.claim-result+json" \ -d '{ "target": { "type": "person", "id": "per-2001" }, "claims": ["benefits-person-exists"], "disclosure": "predicate", "purpose": "https://example.local/purpose/tutorial" }' \ http://127.0.0.1:4255/v1/evaluationsNotary returns a claim result without returning the source row.
Use another Registry Data API source
Section titled “Use another Registry Data API source”Change the source options at project creation time.
The three <...> values must match the Registry Data API lookup route your source exposes:
registryctl init notary my-notary \ --source-url https://api.example.com \ --source-token-env EVIDENCE_SOURCE_API_TOKEN \ --source-dataset <your-dataset-id> \ --source-entity <your-entity> \ --source-lookup-field <your-lookup-field>Notary will read:
GET /v1/datasets/{dataset}/entities/{entity}/records?{lookup_field}={lookup_value}&fields=...&limit=2Authorization: Bearer <source-token>Data-Purpose: <purpose>Successful responses must use:
{ "data": [{ "field": "value" }] }--source-token-env names the environment variable the Notary container reads at runtime.
After project creation, edit secrets/local.env and set EVIDENCE_SOURCE_API_TOKEN to the source
token.
If the source API is another Compose service, pass --source-network <compose-network> so Notary
can join that network.
Adapt a custom HTTP source
Section titled “Adapt a custom HTTP source”Use a source-adapter sidecar when your source API has its own routes, auth, response envelopes, or matching behavior.
The adapter runs privately next to Notary and exposes the Registry Data API-shaped route that Notary expects.
Start with the smallest engine that fits:
| Engine | Use when |
|---|---|
http_json | One governed HTTP JSON request can return the fields Notary needs. |
http_flow | You need 2 to 5 dependent GET requests, such as search first and fetch detail second. |
fhir (FHIR R4 resource projection engine) | You are projecting bounded FHIR R4 resources into Notary-ready facts. |
script_rhai | You need POST, fallback behavior, or small custom branching that the built-in declarative engines cannot express. |
Keep the source-specific logic in the adapter. Keep claim semantics, disclosure, caller policy, and credential issuance in Notary.
Clean up
Section titled “Clean up”Stop the standalone Notary project from its directory:
registryctl stopStopping removes the containers and network only; the generated config, keys, and smoke results stay on disk in the project directory.
If you also started the sample Relay source, stop it from the my-first-api directory.
What you built
Section titled “What you built”You generated a standalone Registry Notary project, pointed it at an existing Registry Data API-shaped source over a shared Compose network, and evaluated a starter claim through Notary’s claim evaluation API. Notary returned a claim result, not the underlying source row: the source stayed private, and only the claim’s disclosed predicate crossed the API boundary.
- Evaluate a claim with Registry Notary: learn the core local path where Relay and Notary run in one generated project.
- OpenCRVS claims: see the OpenCRVS DCI (Digital Convergence Initiative) source-adapter path.
- Deploy Relay and Notary standalone with your own data: move from a local tutorial to an operator-shaped deployment.
- Integration patterns: decide where Registry Notary belongs beside DHIS2, FHIR, workflow engines, exchange layers, and service platforms.
- Source and claim modeling: configure source connections, source adapters, and claim boundaries.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Resolution |
|---|---|---|
registryctl init notary cannot read ROW_READER_RAW | The Relay keys were not exported in this shell. | Run the set -a block from the Relay project directory, then retry. |
registryctl start fails with network ... not found | The source Compose network name is wrong or the source project is not running. | Start the source project and pass the correct <project>_default network name. |
| Claim evaluation returns a source auth error | Notary cannot authenticate to the source. | Confirm the source token in secrets/local.env and restart Notary. |
Claim evaluation returns 409 Evidence not available | The target id is not available from the source, or the dataset, entity, or lookup field does not match the source contract. | Use a known target id or inspect the Registry Data API source contract. |
registryctl start times out and the container log shows missing field \commitment“ | registryctl v0.8.4 pins a service image older than its own generated config format (GH#278). | Pin compose.yaml to the published v0.8.4 Notary digest ghcr.io/registrystack/registry-notary@sha256:0cf05184885d7ed17dd9889e20f3797eb2a9ad07517f4ac7c05c03b774a00b8f and, when the project includes Relay, ghcr.io/registrystack/registry-relay@sha256:93e194500a3500ba3f6331d5a0a9a3069127c48a709beccb083a5fcbdbc3ec61. Then run docker compose pull; reapply the pins after a generation command rewrites compose.yaml. |
With registryctl v0.9.0 or later, registryctl init notary reports that its image lock is missing or invalid | The binary is not paired with the strict image lock from the same release, or the lock failed its release and digest checks. Registryctl v0.8.4 does not use this lock. | Rerun the installer from the same pinned target tag so it checksum-verifies and installs both files. If the lock is intentionally stored elsewhere, set REGISTRYCTL_IMAGE_LOCK to that exact verified file. Do not replace the digest pin with a mutable tag. |