Documentation preview. These pages target Registryctl v0.15.0, which is not published yet. Public download commands will not work until that release exists. For runnable released instructions, use v0.13.0.
Run your first protected registry API
Registry Relay can publish a protected, read-only API over a spreadsheet without copying the workbook into a second database. In this tutorial, you will start the maintained synthetic sample and prove that an anonymous caller is denied while an authorized caller receives only its own projected record.
The workbook and caller identifiers in this tutorial are synthetic. Do not put personal data or production credentials in this project.
Before you start
Section titled “Before you start”This complete local runtime is supported on Linux amd64. Registryctl also has Linux arm64 and macOS arm64 command-line assets for authoring, validation, and build tasks, but the complete runtime is not supported on those hosts in this release.
Confirm that Docker Engine and Compose v2 are available:
docker info >/dev/nulldocker compose versionThe first command prints nothing when Docker is available. The second prints a Compose v2 version, for example:
Docker Compose version v2.x.xThis proves that the local container provider is reachable. Registryctl will perform its own stricter runtime and project checks before starting Relay.
Install Registryctl
Section titled “Install Registryctl”Download and run the Registryctl 0.15.0 installer:
tag=v0.15.0curl -fsSLO "https://github.com/registrystack/registry-stack/releases/download/${tag}/registryctl-${tag}-install.sh"bash "./registryctl-${tag}-install.sh"registryctl --versionThe installer reports its chosen install directory. The last command prints exactly:
registryctl 0.15.0The installer downloads release files over TLS and verifies their checksums. A checksum detects a damaged or mismatched download, but does not authenticate who published it. Follow the tag-frozen release verification guide when you need signature and provenance verification before installation.
If your shell cannot find registryctl, add the install directory reported by
the installer to PATH.
Create the sample project
Section titled “Create the sample project”Create the maintained spreadsheet starter in a new directory:
registryctl init --from spreadsheet --project-dir my-first-apicd my-first-apiRegistryctl prints:
Initialized Registry Stack project "fictional-public-works-registry". Directory: my-first-api Starter: spreadsheet (Registry Stack 0.15.0) Starter content: matches bundled digest Editor support: VS Code and Zed (my-first-api/.registry-stack-editor/manifest.json)
Next: cd my-first-api registryctl doctor --profile local registryctl startThe starter digest proves that the authored sample files match the copy
bundled with this Registryctl release. The cd command prints nothing.
You do not need to copy product configuration or edit generated Relay YAML. These are the files you will encounter:
| Path | What it controls |
|---|---|
registry-stack.yaml | The API purpose, caller scopes, filters, and returned fields |
entities/projects.yaml | The stable key and field types |
environments/local.yaml | The workbook, worksheet, columns, and local test callers |
data/public_works_projects.xlsx | The synthetic source data |
.registry-stack/build/local/ | Generated product configuration. Review it, but do not edit it. |
.registry-stack/runtime/local/ | Private, disposable local runtime files |
The .registry-stack/ directory is ignored by version control. On Unix,
Registryctl gives runtime secret directories mode 0700 and raw credential
files mode 0600.
Check your computer and project
Section titled “Check your computer and project”Check the project, release files, workbook, listener, and Docker runtime:
registryctl doctor --profile localA successful check starts with:
Registry Stack doctor: ok
Project: <absolute-project-path>Profile: localregistry-relay: ok (0 errors, 0 warnings)<absolute-project-path> is the path to my-first-api on your computer.
Additional provider and release-file lines identify the exact inputs
Registryctl checked.
This proves that the authored project can be compiled, the workbook passes strict validation, the generated result matches the authored inputs, the listener is loopback-only, and the matching release runtime is available. If it fails, follow the reported correction before continuing.
Start the API
Section titled “Start the API”Start the exact compiled project:
registryctl startContainer progress lines depend on your Docker version. After Relay becomes ready, Registryctl prints exactly:
PASS readiness: compiled workbook source is readyRelay API: http://127.0.0.1:4242API docs: http://127.0.0.1:4242/docsThis proves that Relay loaded the compiled workbook source and is ready on the loopback listener. The generated Compose document mounts both the compiled Relay configuration and workbook read-only.
Check the API
Section titled “Check the API”Run the sample’s maintained checks:
registryctl smokeRegistryctl prints exactly:
PASS allowed public health checkPASS allowed match source is readyPASS denied anonymous records requestPASS denied wrong local API keyPASS allowed matching principal returns one recordPASS wrong principal safely returns no matchTogether, these checks prove that the public health route is available, the protected route rejects missing and invalid credentials, the matching caller receives one row, and a valid caller bound to an absent key receives no other row.
Registryctl saves a machine-readable report at
.registry-stack/runtime/local/smoke-results.json. It contains check names,
paths, status classes, and pass states. It does not contain raw keys or
workbook rows.
Make one denied request
Section titled “Make one denied request”Call the records route without a credential:
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \ -H "Data-Purpose: public-works-case-management" \ http://127.0.0.1:4242/v1/datasets/projects/entities/projects/recordsRelay prints exactly:
HTTP 401The API is ready, but this protected route does not accept an anonymous caller. Supplying a purpose does not substitute for caller identity.
Make one allowed request
Section titled “Make one allowed request”Load the private local caller keys into this shell:
set -a. .registry-stack/runtime/local/secrets/local.envset +aThese commands print nothing. Do not print, paste, or commit the environment file.
Use the matching synthetic caller to make the same request:
curl -sS -w '\nHTTP %{http_code}\n' \ -H "Authorization: Bearer $REGISTRYCTL_LOCAL_RELAY_MATCH_KEY_RAW" \ -H "Data-Purpose: public-works-case-management" \ http://127.0.0.1:4242/v1/datasets/projects/entities/projects/recordsRelay returns this structure, followed by the exact status line shown. JSON whitespace and object-key order may differ:
{ "data": [ { "project_id": "pw_001", "district_code": "north-01", "sector": "water", "status": "active" } ], "pagination": { "has_more": false }}HTTP 200The credential authenticates the local caller. The requested purpose and
scopes authorize the records operation. Relay then derives the required
project_id filter from that caller’s principal and returns only the four
fields in the reviewed projection.
A caller cannot satisfy this required filter by adding another
project_id to the URL. The principal-bound filter comes from trusted gateway
identity, not from caller-controlled query parameters. The smoke check’s
no-match result proves the safe alternative: a valid caller whose principal
does not match a workbook key receives an empty collection.
See what you can edit
Section titled “See what you can edit”Open the following files in your text editor:
| Authored input | Decision to inspect |
|---|---|
registry-stack.yaml | Purpose, operation scopes, projection, allowed filters, and principal-bound filters |
entities/projects.yaml | Stable key, strict record schema, and materialization limits |
environments/local.yaml | Workbook binding, exact worksheet headers, and synthetic local principals |
Then ask Registryctl to explain the effective plan:
registryctl check --project-dir . --environment local --explainThe output begins:
Registry Stack project: fictional-public-works-registry (valid)Environment: localBaseline: initial_without_baselineSemantic changes: claim, integration, service_policy, operator_security, disclosureLater sections report one records API service, the effective scopes and disclosure plan, and redaction counts. This proves that Registryctl validated the human-authored project and derived a reviewable effective plan.
Project fields compile as sensitive regardless of whether their physical provider is XLSX, CSV, Parquet, or PostgreSQL. A field is not externally readable merely because it exists in the source or entity schema. It must also appear in the reviewed service projection.
Stop and clean up
Section titled “Stop and clean up”Stop the local runtime:
registryctl stopcd ..Docker may print container shutdown progress. Registryctl prints no additional
success line after Compose exits successfully. cd .. returns you to the
directory that contains my-first-api, ready for the next tutorial.
This stops and removes the local containers and network. It keeps the authored project and workbook. The generated build and runtime directories are disposable and can be regenerated from the authored project.
What you built
Section titled “What you built”You ran a loopback-only Relay API over a synthetic XLSX workbook. You proved that:
- the anonymous and invalid-key paths are denied;
- an authorized principal receives only its own matching record;
- a valid non-matching principal cannot see another record; and
- the API returns only fields selected by authored disclosure policy.
The workbook, entity schema, environment binding, and service policy remain human-owned. Registryctl generates and validates the product configuration that Relay consumes.
Continue
Section titled “Continue”Verify a live registry-backed claim to add
Registry Notary to this my-first-api project and evaluate a bounded claim
through the running Relay path.
When you are ready to replace the sample, use your own spreadsheet to derive the entity, workbook mapping, disclosure policy, local principal, purpose header, and request URL from a reviewed workbook.
Before a broader adoption, decide when Registry Stack fits and review the supported product and trust boundaries.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Resolution |
|---|---|---|
registryctl is not found | The install directory is not on PATH. | Add the directory printed by the installer, usually ~/.local/bin, to PATH. |
| The installer reports an unsupported platform | No Registryctl asset is published for that OS and CPU. | Use a published CLI platform for authoring, or Linux amd64 for this complete local runtime. |
doctor cannot find Docker or Compose v2 | Docker Engine is absent or stopped. | Start Docker and confirm docker info and docker compose version, then retry. |
doctor rejects the image lock | Registryctl and the image lock are absent, changed, or from different releases. | Rerun the same versioned installer. Do not substitute a mutable image tag or another release’s lock. |
doctor reports a workbook failure | The declared file, sheet, header, strict columns, types, formulas, or primary key failed validation. | Correct the human-owned workbook, entity, or environment file. Do not edit generated Relay input. |
| A generated artifact integrity check fails | A file under .registry-stack/build/ or .registry-stack/runtime/ was edited or replaced. | Remove the disposable generated closure and rerun registryctl doctor. Reapply intended changes only in human-owned files. |
A request returns 401 | The credential is missing or invalid. | Load the generated local environment without printing it and use the matching local key. |
A request returns 403 | The caller lacks the reviewed scope or purpose. | Review the service and environment bindings. Do not widen scopes merely to bypass the denial. |
| The documented recovery does not solve the problem | The local tutorial does not cover every host or workbook condition. | Open a public Registry Stack issue with the command, stable code, operating system, and Registryctl version. Do not include keys, workbook rows, or private paths. |