Registry stack documentation: machine-readable Markdown.
Index of all pages: https://docs.registrystack.org/llms.txt
Full corpus: https://docs.registrystack.org/llms-full.txt

# registryctl CLI reference

> Commands, subcommands, and flags for registryctl, the tool that runs Registry Stack services locally.

import ProjectStarterSequence from '../../../components/ProjectStarterSequence.astro';
import ProjectWorkspaceJourneys from '../../../components/ProjectWorkspaceJourneys.astro';

`registryctl` is the local adopter command-line tool for Registry Stack. It creates a local project, starts and stops the generated services, and runs validation and smoke checks against them.

This page lists commands in the current `registryctl` source.
Run `registryctl <command> --help` for the built-in usage text.
Most human-facing commands also perform a once-per-day update check; see
[Update check](#update-check).

## Registry Stack project authoring

Project authoring commands work on a Registry Stack project containing `registry-stack.yaml`,
integration definitions and fixtures, and explicit environment bindings.
One project defines one registry trust domain. Its deployment topology can be Relay only, Notary
only, or Relay and Notary together; independent registries use separate projects. Notary-only
source-free claims are evaluation-only. Credential issuance requires the combined topology and
exact Relay-backed evaluation provenance.
The [Registry Stack project authoring guide](../../tutorials/author-registry-project/) covers the
complete workflow and generated trust boundary.

| Subcommand or flag | Purpose |
| --- | --- |
| `init --from <starter>` | Copy `http`, `dhis2-tracker`, `opencrvs-dci`, `fhir-r4`, or `snapshot` into a local workspace. |
| `init --project-dir <dir>` | Destination for `init --from`. Defaults to the current directory. |
| `init --format json` | Emit the versioned machine-readable initialization report instead of the default human-readable result. |
| `test --project-dir <dir>` | Compile and run every integration fixture through the Relay decoder and configured claim evaluator offline. Defaults to the current directory. |
| `test --integration <id> --fixture <name>` | Select one integration fixture. `--fixture` requires `--integration`. |
| `test --trace` | Include the safe synthetic interaction trace in the human or JSON report. |
| `test --format json` | Emit the versioned machine-readable test report instead of the default human-readable result. |
| `test --watch` | Rerun the selected offline scope when an authored project file changes and print a concise pass/fail summary. Cannot be combined with `--trace` or `--live`. |
| `test --environment <name>` | Include one explicit environment binding in offline validation. |
| `test --environment <name> --live` | After offline fixtures pass, send one governed evaluation through a deployed Notary. The environment must be explicitly non-production. |
| `check --project-dir <dir> --environment <name>` | Validate fixtures and the generated configuration for the project's Relay-only, Notary-only, or combined topology without writing build output. |
| `check --explain` | Include the redacted acquisition, authorization, output, claim, and disclosure plan. |
| `check --format json` | Emit the machine-readable success report or typed invalid-project diagnostics instead of the default human-readable report. |
| `check --against <bundle> --anchor <anchor>` | Verify a signed product baseline and compare against its signed human review plus internal approval state. Both flags are required together. |
| `authoring xw --format reference` | Print the generated `xw.v1` function reference for Script authors. |
| `authoring xw --format editor` | Print generated editor metadata for the `xw.v1` function surface. |
| `authoring schema --kind <kind>` | Print a strict project, environment, integration, fixture, or entity JSON Schema. |
| `authoring editor --project-dir <dir>` | Create or verify version-matched VS Code and Zed schema configuration. Defaults to the current directory. |
| `authoring editor --format json` | Emit the versioned machine-readable editor setup report. |
| `authoring language-server` | Run Registry Stack navigation and reference diagnostics over the Language Server Protocol on standard input and output. |
| `build --project-dir <dir> --environment <name>` | Emit deterministic unsigned Config Bundle input directories for the products in the selected topology. |
| `build --against <bundle> --anchor <anchor>` | Build against an explicitly verified signed baseline. Both flags are required together. |
| `build --format json` | Emit the versioned machine-readable build report instead of the default human-readable result. |

Interactive report commands print concise human-readable results by default. Add `--format json`
when another program needs a report containing only versioned JSON on standard output. This policy
covers `init`, `add notary`, non-watch `test`, `check`, `authoring editor`, `build`, `doctor`,
`bundle`, and `anchor`. Watch mode prints one concise pass/fail summary per run and rejects JSON
formatting. Artifact and protocol streams retain their native formats, including `authoring xw`,
`authoring schema`, `authoring language-server`, and `logs`.

| JSON command result | Schema version |
| --- | --- |
| `init` | `registryctl.init.v1` |
| `add notary` | `registryctl.add_notary.v1` |
| Successful `test`, `check`, or `build` | `registryctl.project_command.v1` |
| Invalid-project `check` | `registryctl.project_diagnostics.v1` |
| `authoring editor` | `registryctl.project_editor.v1` |
| `doctor` | `registryctl.validation.report.v1` |
| `smoke` | `registryctl.smoke.v1` |
| `bundle` or `anchor` | The operation-specific `schema_version` in the report |

An initialized starter records its starter ID, Registry Stack release, and
authored-content digest in `registry-stack.yaml`. `init` verifies that digest,
and `check --explain` reports `matches` or `diverged` together with the current
platform-defaults release, script runtime, and `xw.v1` ABI. Divergence is
informational: it identifies intentional project changes without blocking a
valid adapted workspace.
Without `--against`, `check` and `build` label the baseline
`initial_without_baseline`.
Their `semantic_changes` entries identify changed `claim`, `integration`, `service_policy`,
`operator_security`, and `disclosure` dimensions. The authorized bundle signer reviews that report;
Registry Stack does not create a separate reviewer workflow.
The `registryctl.project_command.v1` build report identifies the complete generated build root in
its `output` field. Automation must use that field instead of constructing a path from registryctl's
private generated directory layout.

For invalid authoring, `check` exits nonzero and reports a nonempty typed diagnostic list.
The default human output and `--format json` use the same diagnostics, stable codes, normalized
project-relative authored files, safe causes, and remediation. YAML syntax and unknown-field
diagnostics include a 1-based location and schema command when available. Script diagnostics can
include a static released-signature suggestion.

The diagnostic list is sorted and deduplicated deterministically, then capped at 64 entries with a
`registryctl.authoring.diagnostics.truncated` entry. Safe missing entity and integration references
aggregate. Unsafe paths, symlinks, oversized files, and files that cannot be safely inspected stop
later inspection. This boundary check covers all environment YAML files included in the project
digest, including environments that are not selected. Diagnostics omit authored scalar values,
origins, secret references, fixture inputs and observations, Script arguments, and parser internals.
If any diagnostic exists, `check` does not compile, validate generated product configuration,
execute fixtures, or write build output.

{/* Evidence: crates/registryctl/src/project_authoring/diagnostics.rs and
    crates/registryctl/tests/project_authoring.rs. */}

### Canonical starter sequences

Each bundled starter follows the same offline-first authoring sequence. The integration and fixture
selectors in this generated matrix come from the committed starter workspace, not from a separate
documentation copy.

<ProjectStarterSequence />

### Maintained and conformance workspaces

The following workspaces are checked-in authoring evidence, not additional public starters.
Their command lists contain only the workflow steps supported by each workspace.
The OpenSPP workspace uses a synthetic wire shape.
Its offline tests, configuration checks, and build do not establish compatibility with a live
OpenSPP release.

<ProjectWorkspaceJourneys />

### VS Code and Zed editor setup

`init --from` creates schema-driven editing support with every starter. For a project created by an
earlier `registryctl`, create or verify the same files with:

```sh
registryctl authoring editor --project-dir <project>
```

The command copies the five JSON Schema Draft 2020-12 documents embedded in the running
`registryctl`. It records the binary version and schema SHA-256 values in
`.registry-stack-editor/manifest.json`, so the project does not depend on a source checkout, a
mutable branch, or network schema retrieval.
For automation, `authoring editor --format json` returns the project root in `project_directory`
and every managed file in `files`. Use those `registryctl.project_editor.v1` fields instead of
inferring additional editor paths.

| Authored file | Project-local schema |
| --- | --- |
| `registry-stack.yaml` | `.registry-stack-editor/schemas/project.schema.json` |
| `environments/*.yaml` | `.registry-stack-editor/schemas/environment.schema.json` |
| `integrations/*/integration.yaml` | `.registry-stack-editor/schemas/integration.schema.json` |
| `integrations/*/fixtures/*.yaml` | `.registry-stack-editor/schemas/fixture.schema.json` |
| `entities/*.yaml` | `.registry-stack-editor/schemas/entity.schema.json` |

The generated `.vscode/settings.json` and `.zed/settings.json` reserve the five path suffixes in the
table. Open the Registry Stack project directory as the editor root. In VS Code, install or accept
the workspace recommendation for Red Hat YAML. Zed includes YAML language-server support.

The generated schema setup is the stable beta editor path.
It provides YAML validation, completion, hover, and formatting without a source checkout.

VS Code and Zed semantic navigation are optional beta integrations installed from the Registry
Stack source tree. They are not marketplace extensions and are not available as release assets.
Project configuration and editor installation are separate. Configure projects with `init` or
`authoring editor`, and install an editor integration once from a matching source checkout:

```sh
./editors/install.sh vscode
./editors/install.sh zed
```

The installer verifies the matching `registryctl` and embedded language server without reading or
changing a project. Pass `--open <existing-directory>` only to open a directory after installation;
it does not configure that directory. Use these integrations when you want cross-file definitions,
references, workspace and document symbols, and missing, duplicate, or ambiguous reference
diagnostics.
Both integrations launch the same semantic server, either as `registry-language-server` or through
`registryctl authoring language-server`, alongside the YAML language server.
The YAML language server continues to own syntax, schemas, completion, hover, and formatting.
Follow `editors/vscode/README.md` or `editors/zed/README.md` in the same source checkout.

The shared YAML language server interprets configured paths as suffix matches at any depth. A file
such as `notes.yaml` keeps its normal schema detection and formatting, but a nested copy such as
`examples/environments/local.yaml` receives the Registry Stack environment schema. Do not reuse
the five reserved layouts for unrelated YAML inside the opened project. The Registry Stack
extensions restrict semantic indexing to the project root and documented authored-file layouts;
portable schema settings continue to use suffix matching.

Completion, hover descriptions, the document outline, and inline validation then use the matching
Registry Stack schemas. To smoke-test the association, add an unknown top-level key to an
integration or change its `version` from the integer `1` to a string. The editor must diagnose the
temporary edit. Remove it before running `registryctl test`.

Editor setup is idempotent when every target is unchanged. On a `registryctl` upgrade, it refreshes
a prior generated schema bundle only after the manifest shape and every available schema hash have
been verified. Custom editor settings, malformed manifests, and schema files that disagree with
their manifest are preserved as conflicts. The command stages all changes and rolls them back if
publication fails. Preserve custom settings and install the mappings manually, or restore the
expected generated files before rerunning the command. Automatic JSON-with-comments merging is not
part of the 1.0 setup.

For a project that deploys Notary, `environments/*.yaml` can set the existing
dedicated-worker memory ceiling explicitly:

```yaml
notary_cel:
  worker_memory_bytes: 1073741824
```

The field accepts 32 MiB through 1 GiB and participates in the
`operator_security` review dimension. Omit it to retain Notary's 128 MiB
default. The value is a per-worker data/address-space ceiling, not reserved
memory; the 1 GiB maximum exists for emulated local runtimes.

Offline fixture execution uses an implementation-owned, fixture-only binding. It runs the
same Relay source-plan compiler, closed response decoder, typed normalization, static
authentication and service-policy gates, and claim evaluator used by the products. Fixture YAML
supplies only synthetic logical inputs and bounded source observations. It cannot select destinations,
credentials, worker commands, authority context, or decoder bypasses. A product-named starter does
not select a runtime executor or enable a protocol helper based on source product or version.

`snapshot` is supported through an authored integration, entity definition, and private
environment files.
A records service and one or more snapshot integrations can reference the same logical entity.
`build` then emits one ingest plan and materialization identity, while the governed records routes
and exact consultations retain their separate authorization contracts.
See the exact snapshot guide for the logical output contract and private physical mapping.

{/* Evidence: crates/registryctl/tests/project_authoring.rs,
    records_and_snapshot_share_one_generated_materialization. */}

The governed live test reads `REGISTRY_STACK_LIVE_NOTARY_ORIGIN`,
`REGISTRY_STACK_LIVE_NOTARY_API_KEY`, `REGISTRY_STACK_LIVE_REQUEST_FILE`, and
`REGISTRY_STACK_LIVE_EXPECTED_FILE` from the invoking process environment. The origin must be
HTTPS, except that HTTP loopback is accepted for local testing. The gate first requires every
Relay-backed consultation contract to report ready, then sends the request only to
`POST /v1/evaluations`. Returned claim fields must match the expected file and include
source-backed provenance. Do not put registry or source credentials in the request or Registry
Stack project.

Registry-backed batch is a Notary API contract, not a separate registryctl command.
`POST /v1/batch-evaluations` requires an `Idempotency-Key` when any requested claim is
registry-backed.
Notary validates the complete batch before the first Relay call, executes bounded independent
single-subject consultations, preserves item order, and replays an identical caller-scoped outer
request without repeating its completed children.
The `test --live` command currently exercises one `POST /v1/evaluations` request, so a successful
live authoring check is not batch evidence.

{/* Evidence: crates/registry-notary-server/src/runtime/tests/evaluation.rs and
    crates/registry-notary-server/src/openapi.rs. */}

## Config bundle commands

The `build` output for a Registry Stack project contains an unsigned Config Bundle input directory
for each product in the selected topology. Relay-only and Notary-only projects produce one product
input; a combined project produces separate Relay and Notary inputs. This output is not a signed
project root or a deployable bundle. Package and sign each product directory with `bundle sign`,
then verify the resulting product bundle against its product trust anchor with `bundle verify`.
Activation remains a product-specific deployment step.
A product input carries the same human review as `reviewable/review.json` plus an internal approval
state. Product signing covers both files. The internal state binds the report, semantic comparison
state, and generated product closures without exposing those lower-level digests in the human
report. In a combined build, Relay and Notary receive identical approval state, but separate product
signatures do not make their activation atomic.
A signed project-level deployment bundle with a root manifest that binds compatible product
submanifests is future work and is not emitted by the current CLI.

| Subcommand or flag | Purpose |
| --- | --- |
| `bundle sign --input <dir>` | Package the generated product input directory. |
| `bundle sign --key <jwk-or-op-reference>` | Sign with a private JWK file or `op://` reference. |
| `bundle sign --product <id> --environment <name> --stream-id <id>` | Bind the bundle to one product, environment, and configuration stream. |
| `bundle sign --instance-id <id>` | Optionally bind the bundle to one product instance. |
| `bundle sign --sequence <n> --bundle-id <id> --out <dir>` | Set the monotonic sequence and bundle identity, then create the output directory. |
| `bundle verify --bundle-dir <dir> --anchor-path <file>` | Verify the signed closure, signature, trust anchor, and configured identity bindings. |
| `bundle --format json <subcommand>` | Emit the operation-specific machine-readable report. The global flag is also accepted after the subcommand. |
| `anchor --format json <subcommand>` | Emit the versioned machine-readable trust-anchor report. The global flag is also accepted after the subcommand. |
| `check --against <bundle> --anchor <file>` | Verify a signed baseline before calculating semantic changes. Both flags are required. |
| `build --against <bundle> --anchor <file>` | Verify a signed baseline before producing updated unsigned inputs. Both flags are required. |

`bundle inspect --bundle-dir <dir>` reports manifest and signature metadata without replacing
verification. Trust-anchor creation and key changes use the existing `anchor` subcommands shown by
`registryctl anchor --help`. Bundle and trust-anchor operations print human-readable results by
default and accept `--format json` for automation.

{/* Evidence: crates/registryctl/src/main.rs, BundleCommand and AnchorCommand. */}

## Project setup

The canonical `init relay` command creates a local Relay-backed spreadsheet API tutorial project.
In registryctl `v0.13.0`, this generation command requires the strict
`registryctl-vX.Y.Z-image-lock.json` from the same release beside the running
binary. Set `REGISTRYCTL_IMAGE_LOCK` only when an operator has verified the same
file at a separate explicit path. Registryctl does not search the current
working directory or query a registry for image tags. Lifecycle commands use
the immutable image references already stored in an existing project and do
not need the lock. Registryctl `v0.8.4` predates the image-lock contract.

| Subcommand or flag | Purpose |
| --- | --- |
| `init relay <dir>` | Create a local Relay-backed spreadsheet API project in `<dir>`. |
| `init relay --sample <sample>` | Sample project to generate. Defaults to `benefits`. |
| `init relay --format json` | Emit the same `registryctl.init.v1` machine-readable report used by `init --from`. |

The human-readable result identifies the generated Bruno collection and gives the validation and
start commands. The JSON result contains no progress text, so another program can parse standard
output directly. Automation must read the project root from `output` and supported generated entry
points from `artifacts` in the `registryctl.init.v1` report. The remaining generated layout is a
private implementation detail.

{/* Evidence: crates/registryctl/src/main.rs and crates/registryctl/tests/init_output.rs. */}

Use the project-authoring `init --from`, `test`, `check`, and `build` commands for Relay-only,
Notary-only, and combined deployments. Registry Notary does not have a direct-source project
generator. Registry-backed Notary claims consume compiler-pinned Relay consultations, while a
Notary-only project contains source-free or self-attested evaluation-only claims.

### Local Notary add-on

Registryctl `v0.13.0` includes `registryctl add notary`. From a generated `benefits` spreadsheet
project, it creates an editable authored project under `notary/project/`, adds a private
consultation Relay and local Notary services, and generates local-only evaluator and workload
credentials. It refuses an existing Notary directory or a second invocation instead of
overwriting authored work.

The default result identifies the authored claim, the Notary URL available after start, and the
next command. Add `--format json` for the `registryctl.add_notary.v1` report.

`registryctl start` and `registryctl restart` validate and rebuild this add-on from the authored
project before starting it. Registryctl validates the fixed local runtime overrides with the
production product models and publishes one complete generated bundle, so services do not observe
a partially updated contract. The command is a tutorial convenience for the generated benefits
workbook, not a custom-registry import command.
The tutorial path evaluates a registry-backed claim only. It does not issue a
credential or prove wallet, credential-presentation, or OID4VCI interoperability.

## Lifecycle

Lifecycle commands run against the project in the current working directory.

| Subcommand | Purpose |
| --- | --- |
| `start` | Start the local project with Docker Compose and wait for readiness. |
| `stop` | Stop the local project. |
| `restart` | Stop the local project, rebuild an added Notary project when present, then start and wait for readiness. |
| `status` | Print local runtime status, including health and readiness probes. |

## Inspect

Inspect commands report on a running or generated project.

| Subcommand or flag | Purpose |
| --- | --- |
| `open` | Open or print the local API docs URL. |
| `logs` | Stream Compose logs for the local project. |
| `doctor` | Run product doctor validation and print a human-readable diagnostic report. |
| `doctor --profile <profile>` | Deployment profile override passed through to product doctor commands. |
| `doctor --format json` | Emit the versioned machine-readable diagnostic report. |

## Testing

Smoke commands run built-in local checks and write a versioned JSON result file. The
`registryctl.smoke.v1` report is saved as `smoke-results.json` under the authored
`local.output_dir`. Smoke-check ordering and human-readable names are not compatibility contracts.

| Subcommand | Purpose |
| --- | --- |
| `smoke` | Run built-in local smoke checks against the Relay surface. |

## Bruno

`bruno` works with the optional generated Bruno API collection.

| Subcommand or flag | Purpose |
| --- | --- |
| `bruno generate` | Generate or refresh the optional Bruno API collection. |
| `bruno generate --force` | Overwrite existing Bruno files even if registryctl did not generate them. |
| `bruno open` | Open the generated Bruno collection when Bruno is installed. |
| `bruno run` | Run the generated Bruno collection when the Bruno command-line tool is installed. |

## Update check

`registryctl` checks GitHub releases at most once per day for normal human-facing commands and prints an upgrade notice to standard error when a newer release is available. It skips the automatic check in continuous integration and while running `doctor` and the explicit update-check commands, so doctor diagnostics are not accompanied by an update notice.

| Subcommand | Purpose |
| --- | --- |
| `update-check` | Check whether a newer registryctl release is available and print the result. |

Related environment variables are listed in the [environment variable reference](../environment-variables/): `REGISTRYCTL_NO_UPDATE_CHECK`, `REGISTRYCTL_UPDATE_CHECK`, and `REGISTRYCTL_VERSION`.

## Source

The released command tree comes from the registryctl source at `v0.13.0`.
For its canonical definitions, read the
[registryctl command tree in `src/main.rs`](https://github.com/registrystack/registry-stack/blob/v0.13.0/crates/registryctl/src/main.rs).