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

# Author an HTTP Registry Stack project

> Copy the HTTP starter, run its offline fixtures, review the generated plan, and build unsigned Relay and Notary Config Bundle inputs.

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

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.

<QuickstartMeta
  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 commands', 'A 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.

{/* Evidence: crates/registryctl/src/main.rs, crates/registryctl/src/project_authoring/,
    and crates/registryctl/assets/project-starters/bounded-http/. */}

## Canonical HTTP starter sequence

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

<ProjectStarterSequence starter="http" />

## Copy the HTTP starter

Create a local project workspace:

```sh
registryctl init --from http --project-dir registry-project
```

The JSON report contains:

```text
"status": "initialized",
"explanation": {
  "id": "http",
  "release": "0.10.0",
  "state": "matches"
}
```

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:

```text
registry-project/
  registry-stack.yaml
  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.

## Trace one fixture offline

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

```sh
registryctl test \
  --project-dir registry-project \
  --integration person-record \
  --fixture active-person \
  --trace
```

The JSON report identifies the selected fixture, typed input, source call, minimized output, claim
results, and derived security cases. Its primary fixture contains:

```json
{
  "integration": "person-record",
  "fixture": "active-person",
  "inputs": ["person_id"],
  "calls": ["request"],
  "outputs": ["active"],
  "claims": ["person-active", "person-record-exists"],
  "outcome": "match",
  "passed": true
}
```

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.

## Watch the selected fixture

Keep the same fixture running while you edit the project:

```sh
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.

## Adapt the authored contract

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

| File | Field | Replace | With |
| --- | --- | --- | --- |
| `registry-stack.yaml` | `registry.id` | `fictional-citizen-registry` | `fictional-civic-support-registry` |
| `integrations/person-record/integration.yaml` | `source.product` | `replace-with-source-product` | `fictional-civic-support-api` |
| `integrations/person-record/integration.yaml` | `source.versions.unverified` | `[replace-with-source-version]` | `[tutorial-contract-v2]` |
| `environments/local.yaml` | `source.origin` | `https://citizen-registry.invalid` | `https://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.

## Add another integration

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
   claims that select or derive from that consultation's declared outputs.
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:

```sh
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.

{/* Evidence: crates/registryctl/tests/project_authoring.rs,
    http_starter_adapts_to_a_structurally_different_source_api and
    source_product_is_metadata_not_runtime_dispatch. */}

## Run the complete fixture journey

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

```sh
registryctl test --project-dir registry-project
```

The report must again contain:

```text
"status": "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.

## Review the generated plan

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

```sh
registryctl check \
  --project-dir registry-project \
  --environment local \
  --explain
```

The human-readable review report starts with:

```text
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.

## Build unsigned product inputs

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

```sh
registryctl build \
  --project-dir registry-project \
  --environment local
```

The JSON report contains:

```text
"status": "built"
```

The output root contains:

```text
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.

## Clean up generated output

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.

## What you built

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.

## Next

- [Configure API-key source authentication](../configure-project-api-key-authentication/) when
  the upstream requires a fixed header or query credential.
- [Configure a FHIR R4 integration](../configure-project-fhir-r4/) when the reviewed journey uses
  a fixed Patient anchor and declared relation.
- [Configure an exact snapshot materialization](../configure-project-snapshot-materialization/)
  when consultation reads an immutable local snapshot.
- [Configure a script source adapter](../configure-project-script-adapter/) only when the reviewed
  source recipe needs more than one bounded HTTP request.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| `project destination must be absent or an empty real directory` | `init` found content, a non-directory, or a symlink. | Choose an absent or empty real directory. |
| `input.pattern_mismatch` | A 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 trace | The 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 together` | Only one approved-baseline argument was present. | Supply the verified bundle and matching trust anchor together. |
| Generated configuration fails validation | Authored fields cannot produce a valid Relay or Notary startup contract. | Correct the reported authored file and field, then rerun `test` and `check`. |