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

# Evidencectl workflow reference

> Operational boundaries for Evidence Gateway authoring, production build, deployment inspection, fixtures, local development, and editor integration.

`evidencectl` is Evidence Gateway adopter tooling. It creates key material and editable projects, compiles
production candidates, and invokes the `evidence` binary for Evidence Gateway semantic decisions. It does
not approve, deploy, promote, register production clients, or write production secret values.
Its client registration commands manage local development only.

## Contract status

Evidencectl is outside the frozen Evidence Gateway Version 1 runtime contract. Its command line can
change before a compatibility promise covers it. Evidencectl compiles editable authoring input into
a closed bundle. The `evidence` runtime remains the authority for bundle validation and semantic
acceptance, fixture evaluation, secret validation, and startup acceptance.
The canonical adopter commands do not change the numeric Evidence Gateway Version 1
`runtime.yaml` grammar or the existing `evidence-project.yaml` marker.

## Project workflow

| Command | Inputs | Result | Does not do |
| --- | --- | --- | --- |
| `evidencectl check <project>` | Editable project | Reports authoring completeness and field-addressed findings | Claim deployment closure, run fixtures, resolve secrets, or contact a dependency |
| `evidencectl check <project> --target <target>` | Editable project and one explicit target | Adds the target's governance, runtime structure, public keys, source connections, and governed-bundle validation | Require target-host paths or secrets to exist, run fixtures, or contact a dependency |
| `evidencectl check <project> --target <target> --production` | Editable project and one explicit production or evidence-grade target | Refuses incomplete deployment closure under that target's own assurance profile | Select a target, upgrade its profile, or prove live readiness |
| `evidencectl explain <project> [--target <target>]` | Editable project and optional explicit target | Applies the same offline authoring validation, then reports status, findings, revision, and the authored inventory; includes target governance only when selected | Contact sources or expose secret and subject values |
| `evidencectl package <project> --target <target> --output <new-package>` | Editable project and one explicit production target | Creates one closed package with `SHA256SUMS`; runtime remains in the target | Overwrite output, contact source services or OIDC, create production secrets, or start a listener |
| `evidencectl test <editable-project> [--target <deployment-target>]` | An editable project with `questions/`, `sources/`, and referenced synthetic fixtures; an optional target supplies complete deployment governance | Privately compiles the project, then uses runtime `bundle-check` and `bundle-evaluate` | Start HTTP, call a source, or write a production audit entry |
| `evidencectl test <editable-project> --target <deployment-target> --explain` | The same, and asks each evaluation to explain itself | Relays each fixture's stage trace beside its step, or as that fixture's `trace` field under `--format json` | Print a response, fact, derived, or selector value, or explain a served request |
| `evidencectl doctor --runtime-config <absolute-file>` | Runtime file on its target host | Runs the runtime-owned startup dependency preflight without opening the public listener | Send an Evidence request or establish that a fixture passed |
| `evidencectl artifact inspect <target>` | Deployment target whose runtime names the installed package | Inspects artifact custody without contacting dependencies | Establish live dependency readiness |

`doctor --runtime-config` opens the configured audit destination as startup does, so it refuses
while another Evidence instance holds that destination's single-writer lock. To check a candidate
staged beside the instance it will replace, add `--without-audit-lock`: the audit hash key is
checked as startup checks it, and the audit directory and files are checked for ownership, mode,
write access, and a complete final entry. The lock stays with the running writer, so a second
writer is not detected. The JSON `proofBoundary` states this. Every other dependency is checked in
the same way. The refusal for a held lock names this option.

`package` is create-only. It rejects an existing output directory, unauthenticated or non-HTTPS
production HTTP sources, source transports with no stated production conditions, missing governance
metadata or fixtures, unresolved review markers, unknown fields, symlink traversal, and references
outside the allowed project directories. A failed package publishes no candidate.

`check`, `test`, `package`, `source diff`, and `source update`, plus the compatibility spelling
`fixtures run`, refuse a derivation whose `answer` reads a fact its question's source
does not declare, with `evidence.authoring.derivation-fact-undeclared` against the derivation
file. A source declares an inline operation's `source.facts[].name`, or the properties of a
referenced source's closed `factSchema`. A registry field rename that a derivation still reads
under its old name therefore fails before `source update` installs anything. The check reads the
project, not the running registry: a candidate already deployed against a registry whose field is
then renamed still fails every request that reads it while `/ready` reports ready. Only literal
reads on the first `answer` parameter, such as `facts["status"]` and `facts.status`, are checked.
The operands of one `??` fallback are read together, so `facts.new ?? facts.old` passes while
either name is declared. A computed key such as `facts[key]` is not a literal read and is how a
derivation reads a fact the check should not see. It, a read inside a helper function, an
`answer` that rebinds or writes its first parameter, and an open fact schema are left to the
fixtures.

An ordinary `check` can succeed with `status: incomplete` and visible findings. Add
`--deny-findings` when any finding must refuse the command. All findings carry `severity`, `code`,
`artifact`, `path`, `message`, and `suggestedAction`. Human output is the default. Add the global
`--format json` option for the same result as structured JSON. A command that provides no JSON
report accepts only `--format human`, and the CLI reference shows which commands those are;
`--format json` on one of them is the usage error `evidencectl.format.unsupported`.

Under `--format json`, a command writes exactly one JSON object on standard output and nothing on
standard error. The object opens with `ok`, `command`, and `status`, in that order, then carries the
command's own members. Every member name is camelCase; a map keyed by authored identifiers, such
as `selectorProfiles`, keeps those identifiers as its keys. `command` is the command path, such as `check` or
`dev start`, and `status` names what happened, such as `complete`, `incomplete`, `passed`, or
`ready`. `ok` is `true` exactly when the process exits `0`. A refusal uses the same object with
`ok: false`, a `diagnostics` array whose entries each name the next step in `suggestedAction`, and
one of the statuses `refused`, `failed`, `domain-refusal`, `usage-error`, or
`operational-failure`. A command-line error that stops before a command is selected reports
`command: "usage"`. Pending changes, such as a `source add` preview, are a `status`, never an exit
code.

The workflow exit classes are `0` for success, `1` for a domain refusal, denied finding, or failing
fixture, `2` for command-line usage, and `3` for an operational failure, such as a file, process,
or local session the command depends on being unavailable. These classes belong to adopter tooling;
they do not change the Evidence Gateway runtime verifier's frozen exit contract.

`evidencectl test` and `evidencectl fixtures run` also accept `--format junit`. The run is the same;
standard output carries one JUnit XML document with a `check` suite for the bundle check and one
suite per fixture file, holding one test case per case the runtime's trace named, and the human
summary moves to standard error. A run that evaluated no case carries a failing `run` suite, so the
document never reads greener than the exit code. Every other command refuses `--format junit` as a
usage error.

{/* Evidence: crates/registry-evidencectl/src/lib.rs, Cli, Command, OutputFormat, CliFormat,
    run_check_command(), and run_explain_command();
    crates/registry-evidencectl/src/report.rs, the exit constants, success(), refused(), and failure();
    crates/registry-evidencectl/src/junit.rs, render();
    crates/registry-evidencectl/src/check.rs, check() and explain();
    crates/registry-evidencectl/src/runtime.rs, DoctorArgs and run();
    crates/registry-evidencectl/src/authoring.rs, read_inputs() and declared_fact_names();
    crates/registry-evidence-authoring/src/derivation.rs, validate_answer_fact_reads(). */}

## Compatibility spellings

The released `new` and `fixtures run` spellings remain available during the command
transition. The retired `build` spelling refuses the request and names `package` as its replacement.
New projects, examples, and current procedures use `init`, `test`, and `package`.
The `doctor --project <target>` compatibility form retains artifact inspection;
use `artifact inspect <target>` for that operation and reserve `doctor --runtime-config` for
live startup dependency checks. Every command that reads one project names it as a positional
`<project>` argument, defaulting to the current directory where the command allows it. The former
`--project <project>` spelling remains accepted, but hidden, on commands whose project is now
positional. Only `source import`, `source diff`, and `source update`, whose positional argument is
the export, and `target new`, whose positional argument is the target, document `--project`.
`doctor` keeps its visible `--project <target>` option, and the `access` commands and
`audit show` act on the current directory; none of these takes a positional project. Do
not combine a canonical positional project with its former `--project` flag; conflicting old and
new forms are usage errors.
Request preparation uses `--response-format signed-jws|sd-jwt-vc` so the
response choice cannot collide with global report formatting. The released
`request prepare --format` spelling remains accepted only for those two legacy
response values. Supplying both response selectors is a usage error.

## Production input reference

An editable project becomes a production build input only after it has:

- A `fixtures/` regular file referenced by every production question.
- Stable concept identifiers and production `governance` metadata in every question.
- `<target>/governance.yaml` with bundle-owned fields for one environment.
- `<target>/runtime.yaml` with one environment's runtime bindings.
- Public JWK files beneath `<target>/` for every active and published service key referenced there.

`governance.yaml` is strict. It must carry version `1`, an `assuranceProfile` of `production` or
`evidence-grade`, service, issuer, authentication, audit, subject binding, rate limits, signing,
optional response formats, and authority profiles. It cannot supply selector profiles, sources, or
requirements. It accepts logical `secret:file/<name>` references, not values or absolute secret
paths.

The output runtime document is copied byte-for-byte. Its paths and secret posture are accepted only
by the final target-host `evidence check`.

The maintained reference layout keeps the editable project under `shared/evidence-project/` and each
complete deployment target under `environments/<target>/evidence/`. That layout is a repository
convention, not part of the `--target` path grammar. Do not use overlays, environment branches,
symlinks, or runtime substitutions. Git contains public keys and nonsecret provider configuration,
but no private JWKs, HMAC keys, provider tokens, auto-auth credentials, access tokens, live
responses, or real identifiers.

## Local-only commands

`evidencectl init` requires a destination and exactly one authoring source:

```sh
evidencectl init <directory> --openapi <path-or-https-url> --profile local
evidencectl init <directory> --transport sqlite-extract --profile local
```

OpenAPI mode creates an authoring workspace whose source, question, and fixture directories remain
empty. SQLite mode creates a synthetic source, question, query, adapters, schemas, derivation, and
fixture. Both create disposable, unbound Evidence Gateway key material in the ignored owner-only
`secrets/` directory. Neither creates a production target, issuer configuration, or deployable bundle.

`evidencectl dev start [<project>]` starts Evidence Gateway and the pinned local issuer on loopback.
When borrowing a shared issuer, pass `--issuer-project <owner>` and an exact `--resource <URI>`
registered for this Evidence Gateway service. The default resource is
`urn:registrystack:evidence:local:gateway`; a retained session keeps its selected resource and
refuses a different one on restart. The compiled governed bundle binds this audience.
The local issuer container's name starts with `thunderid-<prefix>-`, with the prefix
`evidence-dev` by default. Pass `--name-prefix <prefix>` to `dev start` so parallel jobs on one
host can tell their containers apart: 1 to 32 lowercase letters, digits, and inner hyphens,
starting with a letter, such as `ci-4711`. The session records its prefix as `namePrefix` and keeps
it until `dev clean`: a restart without the flag reuses it, and a restart that names a different
prefix is refused.
For a nondefault resource, the compiler also derives distinct governed provider, issuer, and
service identifiers from that resource, so multiple local Evidence services remain separate in
Discovery.
{/* Evidence: crates/registry-evidencectl/src/dev.rs, DevArgs, select_resource, StartArgs, issuer_label;
    crates/registry-evidencectl/src/authoring.rs, render_local_bundle, local_compilation_keeps_two_exact_evidence_resources_separate */}
It creates a session-scoped P-256 pair for an SD-JWT VC holder and an implicit caller pair only when the project has no explicit access
policy; explicit local clients use their keys under `.evidence/clients/`. Nothing under
`.evidence/dev` or `.evidence/clients` enters a production target.

`evidencectl dev token <client> [<project>]` obtains a fresh service token and writes an owner-only
`Authorization` header file under `.evidence/dev/generated/keys/`. It reports the path and never
prints the token. Task grants come from the configured Casework authority and are not static local
client attributes.

`evidencectl access` manages caller access for one local project:

| Command | State | Result |
| --- | --- | --- |
| `evidencectl access policy add <policy> --question <question>` | Creates `access/policies/<policy>.yaml` | Defines one or more repeated `--question` values for the next Evidence Gateway generation |
| `evidencectl access policy list` | Reads `access/policies/` | Lists the governed local policies and their questions |
| `evidencectl access client add <client> --policy <policy> --generate-local-key` | Creates `access/clients/<client>.yaml` and `.evidence/clients/<client>/private.jwk` | Registers a local client for repeated `--policy` values with non-overlapping question sets |
| `evidencectl access client list` | Reads `access/clients/` | Lists local client status and policy membership |
| `evidencectl access client revoke <client>` | Updates `access/clients/<client>.yaml` | Revokes the local client for the next issuer generation and removes `.evidence/clients/<client>/`, the client's local private key |

For an institutional task exchange, author an optional `taskGrant` on the policy with its
`kind`, exact `sourceIssuer`, active `requesterClients`, and one `bindings` entry for each
question, subject role, and selector alternative. Each binding maps the selector's complete field
set to verified access-token `valueClaims`. The compiler emits authenticated-grant origins and
binds the policy tag to the full grant semantics; it refuses revoked, unassigned, or incomplete
requester bindings. Create the requester with
`evidencectl access client add <client> --policy <policy> --generate-local-key --grant-bootstrap-scope <scope>`.
Use `--grant-bootstrap-resource <URI>` only if its issuer bootstrap resource differs from the
shared issuer owner's default. The borrowed issuer must register that same key and bootstrap
binding for institutional exchange. A direct client omits both bootstrap flags.
For a portal that signs first-party context, create an active policy client with
`--first-party-bootstrap-scope evidence:invoke --first-party-bootstrap-resource <Evidence resource> --first-party-issuer <issuer>`.
The borrowed owner must register the same client key and bootstrap permission, and an exact
`first_party` exchange issuer. Its bootstrap registration carries no static Evidence requester
tags or audience; the signed context supplies those attributes for each request. The client
still needs an active Evidence policy assignment and cannot use a task-grant policy.
{/* Evidence: crates/registry-evidence-authoring/src/model.rs, AccessTaskGrant, AccessTaskBinding;
    crates/registry-evidencectl/src/authoring.rs, render_policy_authority_profile;
    crates/registry-evidencectl/src/access.rs, ClientAddArgs, ActiveClientExchange;
    crates/registry-evidencectl/src/dev.rs, verify_borrowed_registrations */}

Public, reviewable local access configuration lives under `access/`. Owner-only private client keys
live only under `.evidence/clients/`. Generated issuer resources under `.evidence/dev/generated/issuer/`
are disposable.

Stop the local development session before adding or revoking a client. The next start validates the
complete client and policy registry, then provisions it as one issuer generation. A policy change also
requires a new Evidence Gateway generation.

The local access commands do not define production authority or production clients. Production
authority profiles remain in the deployment target's governed `governance.yaml`. Production client
registrations remain in the deployment's governed OAuth issuer. Files under `access/` and
`.evidence/` do not become production candidate inputs.

Use `keygen`, `source suggest`, `request`, `verify`, and `audit` for their documented authoring or
local inspection roles. Do not use a local request, local audit record, or disposable key as a
production candidate input.

## Editor support

`evidencectl tooling` groups the two commands that serve an editor rather than a deployment.

| Command | Inputs | Result | Does not do |
| --- | --- | --- | --- |
| `evidencectl tooling editor [<project>]` | Editable project directory, defaulting to the current directory | Writes the project-local schema mappings VS Code and Zed read, and reports all six managed files | Install an extension, change editor settings outside the project, or replace a file it did not write |
| `evidencectl tooling language-server` | No arguments; speaks the Language Server Protocol over standard input and output | Reports Evidence Gateway authoring diagnostics for every document it indexes in the project, not only the open one | Open a socket, contact a source, read source values, or observe SQLite |

`tooling editor` writes six files into the project:

```text
.evidence-editor/manifest.json
.evidence-editor/schemas/project-marker.schema.json
.evidence-editor/schemas/question.schema.json
.vscode/extensions.json
.vscode/settings.json
.zed/settings.json
```

Commit all six with the rest of the project. They are generated, nonsecret configuration matched to
the schemas the checks apply, and the `.gitignore` that `evidencectl init` writes excludes `secrets/`
and `.evidence/` only. A later run refreshes exactly what an earlier run recorded writing. A managed
file someone has edited by hand stops the command, which names that file and changes nothing.

The mappings cover `evidence-project.yaml` and `questions/*.yaml`, the two document kinds a Rust type
stands behind. Sources, selectors, derivations, answer schemas, and fixtures carry no static schema;
the language server checks those.

A diagnostic in your editor carries the sentence `evidencectl` reports for the same input, because
both read one shared set of authoring checks. Fixing what the editor reports satisfies the command
line for that rule. The editor bounds a message at 1024 characters.

{/* Evidence: crates/registry-evidencectl/src/tooling.rs, ToolingCommand;
    crates/registry-evidencectl/src/tooling_editor.rs, EDITOR_SCHEMA_CATALOG and MANAGED_FILES;
    crates/registry-evidencectl/src/scaffold.rs;
    crates/registry-evidence-authoring/src/validate.rs, validate_question();
    crates/registry-evidencectl/src/authoring.rs, first_finding();
    crates/registry-language-server/src/evidence/diagnostics.rs, bounded_message(). */}

### Base Registry Engine projects

The language server serves Evidence Gateway and Registry Relay projects. A Base Registry Engine
(BReg) project is neither, and it names its own project document `registry.yaml`. The editor tooling in this
page reports nothing about one, and starts no language server over one.

BReg publishes its authoring JSON Schemas as
[`registry-project.schema.json`](https://github.com/registrystack/registry-stack/blob/main/products/breg/generated/authoring/registry-project.schema.json)
and
[`registry-module.schema.json`](https://github.com/registrystack/registry-stack/blob/main/products/breg/generated/authoring/registry-module.schema.json).
No command writes a mapping for them, so copy both into the BReg project and map them yourself in
`.vscode/settings.json`:

```json
{
  "yaml.schemas": {
    "./schemas/registry-project.schema.json": "registry.yaml",
    "./schemas/registry-module.schema.json": "modules/*/module.yaml"
  }
}
```

{/* Evidence: products/breg/generated/authoring/registry-project.schema.json;
    products/breg/generated/authoring/registry-module.schema.json;
    products/breg/acceptance/business/registry.yaml;
    crates/registry-language-server/src/relay_v2/index.rs, declares_root(). */}

## Related reference

The generated `evidencectl` syntax is published only after its exact source version receives a
recorded human review.

- [Configure Evidence Gateway](../../configure/evidence/)
- [Build and deploy an Evidence Gateway project](../../tutorials/build-and-deploy-evidence-project/)