Skip to content
Registry StackDocsv0.13.0

Author an HTTP Registry Stack project

View as Markdown

Create a Registry Stack project with a bounded HTTP integration without editing product source code. You will copy the built-in starter, prove its synthetic journey offline, inspect the bounded acquisition and disclosure plan, and build separate unsigned inputs for Registry Relay and Registry Notary.

One project defines one registry trust domain. A deployment can use Relay only for governed materialization and records APIs, Notary only for source-free or self-attested evidence, or both products for registry-backed consultations and claims derived from Relay outputs. Independent registries require separate projects.

Outcome
A tested project workspace with reviewable bounded HTTP configuration and unsigned Relay and Notary Config Bundle inputs.
Time
About 10 minutes after registryctl is installed
Level
Local authoring with synthetic fixtures
Prerequisites
A registryctl build with project authoring commandsA shell and a text editor

This tutorial uses a fictional registry and synthetic records. Do not add source credentials, production endpoints, or real subject records.

Use this compact sequence as the workflow checklist. The sections that follow explain each command and the trust boundary it verifies.

Run these commands in order. Initialization creates the editor files, and the next idempotent command verifies them against the running registryctl. The focused test prints a safe synthetic trace. The following command starts the same fixture as a watch smoke; pressCtrl+C after its initial passing report. The final three commands test every fixture, explain the redacted plan, and build the unsigned product inputs.

http: Custom HTTP

One fixed bounded HTTP request with a closed response projection.

registryctl init --from http --project-dir registry-project
registryctl authoring editor --project-dir registry-project
registryctl test --project-dir registry-project --integration person-record --fixture active-person --trace
registryctl test --project-dir registry-project --integration person-record --fixture active-person --watch
registryctl test --project-dir registry-project
registryctl check --project-dir registry-project --environment local --explain
registryctl build --project-dir registry-project --environment local

Generated from the five starter workspaces compiled into registryctl.

Create a local project workspace:

Terminal window
registryctl init --from http --project-dir registry-project

The human-readable result confirms the project, starter provenance, and next command:

Initialized Registry Stack project "fictional-citizen-registry".
Directory: registry-project
Starter: http (Registry Stack 0.13.0)
Starter content: matches bundled digest
Editor support: VS Code and Zed (registry-project/.registry-stack-editor/manifest.json)
Next:
cd registry-project
registryctl test --project-dir .

Add --format json when another program needs the versioned initialization report.

The copied registry-stack.yaml keeps the complete starter provenance, including its authored-content digest. Later, check --explain reports whether the workspace still matches that starter or has intentionally diverged.

The command creates this authored layout:

registry-project/
registry-stack.yaml
.registry-stack-editor/
manifest.json
schemas/
.vscode/
extensions.json
settings.json
.zed/
settings.json
integrations/
person-record/
integration.yaml
fixtures/
environments/
local.yaml

The starter is copied into your workspace. Registry Stack does not resolve a remote package or download integration code at runtime.

Initialization copies the five schemas embedded in registryctl and configures both VS Code and Zed. The second command in the canonical sequence, registryctl authoring editor --project-dir registry-project, verifies the same deterministic setup and is also available for existing projects.

Open registry-project itself as the editor root. In VS Code, accept the Red Hat YAML workspace recommendation. Zed starts its native YAML language server. Open integrations/person-record/integration.yaml and check key completion, field descriptions on hover, and the document outline.

For a short validation demo, add an unexpected: true top-level field. Both editors must mark the unknown field as invalid. Remove the field before continuing. A separate YAML file outside the five reserved Registry Stack path suffixes, such as notes.yaml, keeps its normal editor behavior.

Run one matching fixture and include its safe synthetic trace before changing the source contract:

Terminal window
registryctl test \
--project-dir registry-project \
--integration person-record \
--fixture active-person \
--trace

The human-readable report identifies the selected fixture, typed input, source call, minimized output, claim results, and derived security cases. The report starts with:

PASS: 7/7 fixtures passed
PASS person-record.active-person
inputs: person_id
calls: call=1 operation=request method=GET path=/people/* query=[fields] headers=[] body=none
outputs: active
claims: person-active, person-record-exists
outcome: match

The same report includes derived malformed-decoding, byte-ceiling, timeout, authorization-before-source, and output-minimization cases. The command does not contact Registry Relay, Registry Notary, or a source registry. Add --format json when another program needs the versioned fixture report.

Keep the same fixture running while you edit the project:

Terminal window
registryctl test \
--project-dir registry-project \
--integration person-record \
--fixture active-person \
--watch

The command prints PASS: 1/1 fixtures passed, waits for an authored file to change, then reruns the selected fixture. Use the preceding non-watch command for the full trace. Press Ctrl+C after you confirm the initial pass. The watcher ignores generated .registry-stack output and never enables live source access.

For this synthetic journey, make these exact substitutions with your editor:

FileFieldReplaceWith
registry-stack.yamlregistry.idfictional-citizen-registryfictional-civic-support-registry
integrations/person-record/integration.yamlsource.productreplace-with-source-productfictional-civic-support-api
integrations/person-record/integration.yamlsource.versions.unverified[replace-with-source-version][tutorial-contract-v2]
environments/local.yamlsource.originhttps://citizen-registry.invalidhttps://civic-support.invalid

These values remain fictional and .invalid destinations cannot identify a live service. They do not alter the request shape proved by the starter fixtures. When you later change a method, path, query, header, or body, update each affected fixture’s expected interaction so the test proves the new canonical request.

For an actual integration, review all four authored surfaces and replace the fictional contract with approved project values:

  1. In registry-stack.yaml, name the registry, service, purpose, caller scopes, consultation input mapping, outputs, claims, disclosure modes, and credential claim allow-list.
  2. In integrations/person-record/integration.yaml, define selector and parameter input schemas, one fixed HTTP request, output pointers and schemas, cardinality, and any limit override proven necessary by fixtures.
  3. In integrations/person-record/fixtures/, replace the synthetic interactions and expected outputs and claims. Each fixture proves the canonical request as well as the response.
  4. In environments/local.yaml, bind the non-production source destination, secret references, caller fingerprints, Relay trust, and deployment services.

The integration fixes the method, path, input placement, minimized output fields, and bounds before deployment. The environment binds the one logical source origin and credentials. Consultation inputs can populate only declared request values. They cannot select an origin, method, credential, capability, projection, or response mapper.

For target-derived consultation inputs, use one of these closed mappings:

  • request.target.id for the target’s primary request identifier
  • request.target.identifiers.<stable-id> for a named institutional identifier
  • request.target.attributes.<stable-name> for an ordinary target attribute

A target attribute name must match [a-z][a-z0-9_]{0,63}. Use an identifier mapping for values that identify a record within an issuing scheme. Use an attribute mapping for other request-bound values, and make the mapped value satisfy the integration input’s declared type and bounds. An attribute is caller-supplied context. Mapping an attribute does not authenticate the value or turn the value into an identifier. Registryctl rejects any other target path before generating Relay or Notary configuration.

Keep three policy categories separate while you author the project. The integration and environment define Relay source access and adaptation policy. The evidence service defines Notary evidence authorization and disclosure policy. The evidence consumer and decision owner keep their use, decision, workflow, and action policy outside the project.

Test every proposed claim before adding it:

  1. Does the claim state one atomic evidence fact or value, rather than a consumer decision?
  2. Does the claim define what true, false, null, no_match, ambiguous, and source failure mean without turning missing evidence into a negative fact?
  3. Can another authorized service or procedure reuse the evidence without importing the first consumer’s eligibility, qualification, ranking, workflow, or action rules?

If any answer is no, narrow or rename the claim and keep the consuming decision downstream. For example, prefer programme-enrollment-active or measles-dose-recorded to outreach-required or benefits-eligible. A Common Expression Language (CEL) rule may derive a precise evidence predicate from typed outputs, but it is not a general-purpose eligibility engine. Across other sectors, prefer evidence such as qualification-awarded, business-registration-active, coverage-active, inspection-completed, or professional-credential-valid to outcomes such as admission-approved, licence-granted, claim-payable, inspection-priority, or access-permitted.

A claim may attest a decision that an authoritative source already made. In that exception, the claim id and its review evidence must identify it as a source-owned decision, and the integration must preserve the source’s exact meaning. Notary does not recompute the decision.

An existing project can add another protocol view over the same logical source without starting a second project or copying generated product configuration. Use a stable integration id such as benefit-record, then add these authored files and references:

  1. Create integrations/benefit-record/integration.yaml and integrations/benefit-record/fixtures/. Add adapter.rhai and any reviewed local modules only when the integration uses capability.script.
  2. Add integrations.benefit-record.file: integrations/benefit-record/integration.yaml to registry-stack.yaml.
  3. Under the consuming evidence service, add a consultation with integration: benefit-record and bind every integration input to one typed request path. Add atomic evidence claims that select or derive from that consultation’s declared outputs. Keep consumer decisions outside the evidence service.
  4. Add integrations.benefit-record.source to environments/local.yaml with its non-production origin, credential reference, and generation. Do not put credential values in the project files.

Run the new fixture first, then the complete offline and generated-config gates:

Terminal window
registryctl test --project-dir . --integration benefit-record --fixture <fixture-name> --trace
registryctl test --project-dir .
registryctl check --project-dir . --environment local --explain
registryctl build --project-dir . --environment local

The project model allows multiple integrations only when they are reviewed views over the same logical source trust domain. Start a separate project for an independent registry authority.

Use source.product as review metadata for the source system. It does not select a product executor or runtime capability. Mark a source version unverified until the required integration evidence exists.

Test every edited fixture, including match, no-match, ambiguity, source-shape, and derived security cases:

Terminal window
registryctl test --project-dir registry-project

The report starts with PASS and states how many fixtures passed:

PASS: <passed>/<total> fixtures passed

Failures identify the authored file and fixture. A fixture can supply bounded source observations, but it cannot supply a destination, credential, worker command, authentication bypass, or decoder mode.

Compile the authored project through the Relay and Notary validators without writing build output:

Terminal window
registryctl check \
--project-dir registry-project \
--environment local \
--explain

The human-readable review report starts with:

Registry Stack project: fictional-citizen-registry (valid)
Environment: local
Baseline: initial_without_baseline

Review the fixed request authority, input mappings, caller scopes, purpose, outputs, claims, disclosure modes, and credential membership. Use --format json only when another tool needs the machine-readable report. An initial project without an approved baseline requires the claim, integration, service_policy, operator_security, and disclosure review classes. A valid report is not legal approval, source interoperability evidence, or deployment authority.

Generate deterministic unsigned product inputs for the existing Config Bundle v1 workflow:

Terminal window
registryctl build \
--project-dir registry-project \
--environment local

The human-readable report starts with the built project and output directory:

Built Registry Stack project "fictional-citizen-registry".
Environment: local
Output: registry-project/.registry-stack/build/local

Add --format json when another program needs the versioned build report.

The output root contains:

registry-project/.registry-stack/build/local/
reviewable/
integration-packs/
consultation-contracts/
review.json
private/
relay/
config/relay.yaml
approval/review.json
notary/
config/notary.yaml
approval/review.json

The product input directories remain separate and contain secret references, not secret values. They are inputs to each product’s Config Bundle workflow, not a signed project root or a deployable bundle. build does not create a bundle manifest, sign a bundle, or read a secret value. Package, sign, verify, and activate each product directory through that product’s Config Bundle workflow. One signed project-level deployment bundle whose root binds compatible product submanifests is future work; the current CLI does not emit that artifact. Treat every generated directory as institutionally sensitive and keep it out of source control.

Keep registry-project/ as the authored project workspace. If you do not need the generated inputs, remove only registry-project/.registry-stack/build/local/. You can reproduce that directory with the same build command.

You copied a local HTTP starter, proved its positive and denial fixtures without source access, adapted the reviewed source contract, inspected the complete redacted plan, and generated separate unsigned Relay and Notary inputs. The generated profile keeps source acquisition in Relay and claim disclosure in Notary.

SymptomCauseFix
project destination must be absent or an empty real directoryinit found content, a non-directory, or a symlink.Choose an absent or empty real directory.
input.pattern_mismatchA fixture input does not satisfy the declared type or pattern.Correct the synthetic fixture or the reviewed input contract.
A fixture request proof differs from the traceThe expected interaction does not match the canonical request produced by the integration.Correct the integration or update the wholly synthetic interaction proof.
--against and --anchor must be supplied togetherOnly one approved-baseline argument was present.Supply the verified bundle and matching trust anchor together.
Generated configuration fails validationAuthored fields cannot produce a valid Relay or Notary startup contract.Correct the reported authored file and field, then rerun test and check.