<!-- HushSpec 1.0.0; reference; stable
releaseCommit: e771ec647b7f26a0a09ff852886eb8a91093bc58
docsCommit: 5a252dbf7eb46b507ac9493dff8a695abf5b5e9a
sourcePath: docs/src/reference/json-schema.md
canonical: https://www.hushspec.org/docs/json-schema/
Relative links in this unmodified source body are relative to sourcePath.
-->

# JSON Schema

HushSpec provides JSON Schema files for document validation. These schemas are the machine-readable counterpart to the prose specification and can be used with any JSON Schema validator.

## Available Schemas

The schemas are in the [`schemas/`](https://github.com/backbay-labs/hush/tree/main/schemas) directory:

| File | Description |
|------|-------------|
| `hushspec-core.v1.schema.json` | Core HushSpec document schema: rules, extensions, metadata, `when` conditions |
| `hushspec-posture.v1.schema.json` | Posture extension schema |
| `hushspec-origins.v1.schema.json` | Origins extension schema |
| `hushspec-detection.v1.schema.json` | Detection extension schema |
| `hushspec-evaluator-test.v1.schema.json` | Evaluation test fixture format used by `h2h test`, the testkit, and every SDK's shared-fixture runner. Format `0.2.0` adds per-case `controls` and `tags` and the `expect.rule_trace` / `expect.receipt` assertions; `0.1.0` fixtures stay valid |
| `hushspec-hash-vector.v1.schema.json` | Canonical-form test vector format ([`fixtures/core/hash/`](https://github.com/backbay-labs/hush/tree/main/fixtures/core/hash)); see the [canonical form spec](../canonical-spec.md) |
| `hushspec-receipt.v1.schema.json` | Decision receipt format 0.2; see the [receipt spec](../receipt-spec.md) |
| `hushspec-log-entry.v1.schema.json` | Hash-linked log entry (receipts and policy events) written by chained sinks and checked by `h2h log verify` |
| `hushspec-signature.v1.schema.json` | Detached policy signature envelope 0.2; see the [signing spec](../signing-spec.md) |
| `hushspec-keyring.v1.schema.json` | Trusted keyring consumed by verify-on-load and `h2h verify --keyring` |
| `hushspec-bundle.v1.schema.json` | Policy bundle attestation (DSSE envelope with an in-toto statement) produced by `h2h bundle create` |
| `hushspec-framework-registry.v1.schema.json` | Schema for [`spec/registries/frameworks.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/frameworks.yaml), the compliance frameworks `metadata.controls[].framework` may name |
| `hushspec-error-codes.v1.schema.json` | Schema for [`spec/registries/error-codes.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/error-codes.yaml) and for the `<name>.expect.yaml` sidecars that pin the code each `invalid/` vector is rejected with |
| `hushspec-merge-vector.v1.schema.json` | The merge-vector directory convention under `fixtures/*/merge/` (`base.yaml`, `child-*.yaml`, `expected-*.yaml`, optional `fixture.yaml`) |
| `hushspec-conformance-report.v1.schema.json` | Conformance report emitted by `hushspec-testkit --report`; see [Conformance Levels](conformance.md) |
| `hushspec-engine-profile-experimental.v1.schema.json` | Experimental external engine identity, executable digest, arguments and build materials |
| `hushspec-engine-request-experimental.v1.schema.json` | Experimental digest-bound external engine request, without expected answers |
| `hushspec-engine-response-experimental.v1.schema.json` | Experimental engine observation and echoed request binding |
| `hushspec-conformance-execution-experimental.v1.schema.json` | Experimental execution packet completion record, artifact digests and planned result slots |
| `hushspec-invocation-journal-experimental.v1.schema.json` | Experimental trusted invocation entries and closing checkpoints; embedded policies/receipts and state transitions require separate verification |
| `hushspec-report.v1.schema.json` | Evidence report 0.1: an aggregation over receipts and policy-in-effect events for one window, emitted by `h2h report --format json` |
| `hushspec-evidence-profile-experimental.v1.schema.json` | Experimental 0.1.0 operator scope, ordered sources, byte digests and signer authorization |
| `hushspec-evidence-inventory-experimental.v1.schema.json` | Experimental 0.1.0 independently acquired stream inventory and boundaries |
| `hushspec-evidence-verification-experimental.v1.schema.json` | Experimental 0.1.0 verification result bound to native report bytes |
| `hushspec-assessment-context-experimental.v1.schema.json` | Experimental 0.1.0 local assessment-plan, SSP and resolved catalog references |
| `hushspec-registry-action-types.v0.schema.json` | Shape of [`spec/registries/action-types.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/action-types.yaml), the action types an evaluator dispatches on |
| `hushspec-registry-capabilities.v0.schema.json` | Shape of [`spec/registries/capabilities.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/capabilities.yaml), the capabilities a posture state may grant |
| `hushspec-registry-condition-types.v0.schema.json` | Shape of [`spec/registries/condition-types.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/condition-types.yaml), the `when` condition keys |
| `hushspec-registry-detectors.v0.schema.json` | Shape of [`spec/registries/detectors.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/detectors.yaml), the reference detectors the detection extension names |
| `hushspec-registry-media-types.v0.schema.json` | Shape of [`spec/registries/media-types.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/media-types.yaml), the media types registered for HushSpec documents |
| `hushspec-registry-rule-blocks.v0.schema.json` | Shape of [`spec/registries/rule-blocks.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/rule-blocks.yaml), the rule blocks `rules` may carry |
| `hushspec-registry-rule-paths.v0.schema.json` | Shape of [`spec/registries/rule-paths.yaml`](https://github.com/backbay-labs/hush/blob/main/spec/registries/rule-paths.yaml), the rule paths a receipt may cite |

The complete generated inventory below includes the frozen schemas too. Every
schema is also embedded in the `h2h` binary; `h2h schema --list` prints the
names and `h2h schema <name>` prints one to stdout.


## Schema lineage

The `*-experimental.v1.schema.json` companion artifacts declare their own
`0.1.0` contract version. Their filename lineage does not make them stable or
change the existing policy, receipt, log, report or conformance-report formats.

Document-format schemas are named per major version (`spec/versioning.md` section 9). The `.v1.` files above are the current lineage: the schemas HushSpec 1.0.0 published, referenced by every SDK, the CLI, the testkit, and the fixture modelines. The `.v0.` files describe the 0.x line and are frozen: each carries a `$comment` saying so, [`schemas/frozen-v0.json`](https://github.com/backbay-labs/hush/blob/main/schemas/frozen-v0.json) records their `sha256:` digests, and a test in the reference implementation fails when one of them changes. A document that declares a 0.x `hushspec` version validates against its `.v0.` schema; a document declaring `1.0.z` validates against `.v1.`.

`hushspec-core.v1.schema.json` differs from `hushspec-core.v0.schema.json` in two keywords: `hushspec` matches `^(0|1)\.\d+\.\d+$`, and `name` carries `minLength: 1`. The receipt, log-entry, and report schemas widen their `spec_version` patterns the same way, so a receipt for a `1.0.z` policy validates. Those four are the only validation differences between the lineages: every other `.v1.` file constrains exactly what its `.v0.` predecessor constrained.

The `.v1.` files also carry their own identity, which never affects validation. Each has a `v1` `$id` and no frozen `$comment`, a `title` naming the lineage it belongs to (a title ending in a minor -- `HushSpec Decision Receipt v0.2`, `HushSpec Log Entry v0.1` -- names a *wire format* version, which 1.0.0 did not change), and prose that points at `.v1.` companions: `hushspec-bundle.v1` sends a verifier to `hushspec-core.v1` for the canonical projection, and `hushspec-log-entry.v1` to `hushspec-receipt.v1` for an entry's receipt. The `.v0.` file of each pair still points at the `.v0.` companion, which is what a 0.x document needs.

The registry schemas (`hushspec-registry-*.v0.schema.json`) describe the files under `spec/registries/` rather than documents and keep the `.v0.` name.

`h2h schema <name>` prints the current lineage by bare name (`h2h schema core`); the frozen file is addressed as `core.v0`. `h2h schema --list` names both.

## Where the schemas are served

Each v1 schema declares its own `$id` under the project's owned domain:

```
https://hushspec.org/schemas/<file>
```

The Vercel website serves a static snapshot exported from a clean source commit
using `python3 scripts/build_schema_index.py --site-root ../hush-ui/public`.
Its build checks every indexed byte digest. Alongside the schemas it publishes:

- `https://hushspec.org/schemas/index.json` -- one entry per schema, carrying
  its file name, `$id`, retrieval `url`, SHA-256, title and description, with the
  source `commit`. The index also lists registry URLs and byte digests.
- `https://hushspec.org/registries/<file>` -- every registry under
  [`spec/registries/`](https://github.com/backbay-labs/hush/tree/main/spec/registries),
  published so the normative lists are readable at a stable URL. Nothing
  resolves these over the network: the schemas above pin the registries by
  shape, and the SDKs embed them.

Frozen v0 schemas keep their historical `hushspec.dev` identifiers byte for byte.
The project does not operate that host: use the `.org` mirror's retrieval `url`
for legacy schemas, without rewriting their IDs. Bundle predicate URIs are
identifiers, not schema download URLs, and remain unchanged.

The mdBook deployment includes schema and registry copies as a documentation
mirror. For an exact release revision, fetch a schema from GitHub:

```
https://raw.githubusercontent.com/backbay-labs/hush/v1.0.0/schemas/hushspec-core.v1.schema.json
```

The canonical host serves its indexed source commit. The release URL pins the
same release lineage. Index hashes check byte consistency; they do not
independently authenticate the website.

## Usage

### Validate with `ajv` (Node.js)

```bash
npm install -g ajv-cli

ajv validate -s schemas/hushspec-core.v1.schema.json -d policy.yaml
```

### Validate with `check-jsonschema` (Python)

```bash
pip install check-jsonschema

check-jsonschema --schemafile schemas/hushspec-core.v1.schema.json policy.yaml
```

### Editor Integration

Add a `$schema` comment to your HushSpec YAML files for editor autocompletion and validation:

```yaml
# yaml-language-server: $schema=https://hushspec.org/schemas/hushspec-core.v1.schema.json
hushspec: "1.0.0"
name: "my-policy"

rules:
  forbidden_paths:
    patterns:
      - "**/.ssh/**"
```

See [Where the schemas are served](#where-the-schemas-are-served) for pinned
GitHub retrieval URLs and the distinction between identity and retrieval.

Most YAML-aware editors (VS Code with the YAML extension, IntelliJ, etc.) will pick up the schema directive and provide autocompletion, hover documentation, and inline validation. See the [Editor Setup](../guides/editor-setup.md) guide for the SchemaStore zero-configuration option and workspace-settings alternative.

## Schema Structure

The core schema uses `additionalProperties: false` at every level, enforcing the fail-closed principle. Any field not defined in the specification will cause validation failure.

That holds inside `extensions` too. The core schema is a **compound schema
document**: `extensions.posture`, `extensions.origins` and
`extensions.detection` each `$ref` their companion schema by that schema's own
`$id`, and the three companion documents are carried verbatim in the core
schema's `$defs`. So a validator resolves the whole composition from the one
file, with no network access, and an unknown key inside an extension block is
a rejection rather than an annotation (core spec 2.1 and 9.5). Each reference
also carries `unevaluatedProperties: false`, which keeps the block closed even
if a companion schema's root ever stops setting `additionalProperties: false`.

The embedded copies are byte-for-byte the published companion files; the test
suites compare them, so a companion schema and the copy inside the core schema
cannot drift apart.

## CLI and Editor Checks

`h2h validate --strict policy.yaml` applies parsing and semantic validation;
a YAML linter alone cannot establish either. A JSON Schema validator checks
structure after YAML decoding, and therefore cannot recover duplicate keys or
anchors that a permissive decoder already erased. Prefer the SDK or CLI parser.

VS Code's YAML extension accepts the inline directive
`# yaml-language-server: $schema=https://hushspec.org/schemas/hushspec-core.v1.schema.json`.
JetBrains editors can associate that URL with policy filenames in JSON Schema
Mappings. For `yq`/Ajv pipelines, choose a YAML 1.2 decoder, retain parse-profile
validation, and use the strict CLI gate before deployment. See [editor setup](../guides/editor-setup.md).

<!-- generated-schema-inventory -->
## Complete Published Schema Inventory

Generated from release schema identities. Frozen v0 IDs retain `hushspec.dev`;
retrieval mirrors are served on `hushspec.org`. The [JSON index](https://hushspec.org/schemas/index.json) carries every byte digest.

| Schema | Declared identity |
| --- | --- |
| [hushspec-assessment-context-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-assessment-context-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-assessment-context-experimental.v1.schema.json` |
| [hushspec-bundle.v0.schema.json](https://hushspec.org/schemas/hushspec-bundle.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-bundle.v0.schema.json` |
| [hushspec-bundle.v1.schema.json](https://hushspec.org/schemas/hushspec-bundle.v1.schema.json) | `https://hushspec.org/schemas/hushspec-bundle.v1.schema.json` |
| [hushspec-conformance-execution-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-conformance-execution-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-conformance-execution-experimental.v1.schema.json` |
| [hushspec-conformance-report.v0.schema.json](https://hushspec.org/schemas/hushspec-conformance-report.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-conformance-report.v0.schema.json` |
| [hushspec-conformance-report.v1.schema.json](https://hushspec.org/schemas/hushspec-conformance-report.v1.schema.json) | `https://hushspec.org/schemas/hushspec-conformance-report.v1.schema.json` |
| [hushspec-core.v0.schema.json](https://hushspec.org/schemas/hushspec-core.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-core.v0.schema.json` |
| [hushspec-core.v1.schema.json](https://hushspec.org/schemas/hushspec-core.v1.schema.json) | `https://hushspec.org/schemas/hushspec-core.v1.schema.json` |
| [hushspec-detection.v0.schema.json](https://hushspec.org/schemas/hushspec-detection.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-detection.v0.schema.json` |
| [hushspec-detection.v1.schema.json](https://hushspec.org/schemas/hushspec-detection.v1.schema.json) | `https://hushspec.org/schemas/hushspec-detection.v1.schema.json` |
| [hushspec-engine-profile-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-engine-profile-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-engine-profile-experimental.v1.schema.json` |
| [hushspec-engine-request-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-engine-request-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-engine-request-experimental.v1.schema.json` |
| [hushspec-engine-response-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-engine-response-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-engine-response-experimental.v1.schema.json` |
| [hushspec-error-codes.v0.schema.json](https://hushspec.org/schemas/hushspec-error-codes.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-error-codes.v0.schema.json` |
| [hushspec-error-codes.v1.schema.json](https://hushspec.org/schemas/hushspec-error-codes.v1.schema.json) | `https://hushspec.org/schemas/hushspec-error-codes.v1.schema.json` |
| [hushspec-evaluator-test.v0.schema.json](https://hushspec.org/schemas/hushspec-evaluator-test.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-evaluator-test.v0.schema.json` |
| [hushspec-evaluator-test.v1.schema.json](https://hushspec.org/schemas/hushspec-evaluator-test.v1.schema.json) | `https://hushspec.org/schemas/hushspec-evaluator-test.v1.schema.json` |
| [hushspec-evidence-inventory-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-evidence-inventory-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-evidence-inventory-experimental.v1.schema.json` |
| [hushspec-evidence-profile-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-evidence-profile-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-evidence-profile-experimental.v1.schema.json` |
| [hushspec-evidence-verification-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-evidence-verification-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-evidence-verification-experimental.v1.schema.json` |
| [hushspec-framework-registry.v0.schema.json](https://hushspec.org/schemas/hushspec-framework-registry.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-framework-registry.v0.schema.json` |
| [hushspec-framework-registry.v1.schema.json](https://hushspec.org/schemas/hushspec-framework-registry.v1.schema.json) | `https://hushspec.org/schemas/hushspec-framework-registry.v1.schema.json` |
| [hushspec-hash-vector.v0.schema.json](https://hushspec.org/schemas/hushspec-hash-vector.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-hash-vector.v0.schema.json` |
| [hushspec-hash-vector.v1.schema.json](https://hushspec.org/schemas/hushspec-hash-vector.v1.schema.json) | `https://hushspec.org/schemas/hushspec-hash-vector.v1.schema.json` |
| [hushspec-invocation-journal-experimental.v1.schema.json](https://hushspec.org/schemas/hushspec-invocation-journal-experimental.v1.schema.json) | `https://hushspec.org/schemas/hushspec-invocation-journal-experimental.v1.schema.json` |
| [hushspec-keyring.v0.schema.json](https://hushspec.org/schemas/hushspec-keyring.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-keyring.v0.schema.json` |
| [hushspec-keyring.v1.schema.json](https://hushspec.org/schemas/hushspec-keyring.v1.schema.json) | `https://hushspec.org/schemas/hushspec-keyring.v1.schema.json` |
| [hushspec-log-entry.v0.schema.json](https://hushspec.org/schemas/hushspec-log-entry.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-log-entry.v0.schema.json` |
| [hushspec-log-entry.v1.schema.json](https://hushspec.org/schemas/hushspec-log-entry.v1.schema.json) | `https://hushspec.org/schemas/hushspec-log-entry.v1.schema.json` |
| [hushspec-merge-vector.v0.schema.json](https://hushspec.org/schemas/hushspec-merge-vector.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-merge-vector.v0.schema.json` |
| [hushspec-merge-vector.v1.schema.json](https://hushspec.org/schemas/hushspec-merge-vector.v1.schema.json) | `https://hushspec.org/schemas/hushspec-merge-vector.v1.schema.json` |
| [hushspec-origins.v0.schema.json](https://hushspec.org/schemas/hushspec-origins.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-origins.v0.schema.json` |
| [hushspec-origins.v1.schema.json](https://hushspec.org/schemas/hushspec-origins.v1.schema.json) | `https://hushspec.org/schemas/hushspec-origins.v1.schema.json` |
| [hushspec-posture.v0.schema.json](https://hushspec.org/schemas/hushspec-posture.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-posture.v0.schema.json` |
| [hushspec-posture.v1.schema.json](https://hushspec.org/schemas/hushspec-posture.v1.schema.json) | `https://hushspec.org/schemas/hushspec-posture.v1.schema.json` |
| [hushspec-receipt.v0.schema.json](https://hushspec.org/schemas/hushspec-receipt.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-receipt.v0.schema.json` |
| [hushspec-receipt.v1.schema.json](https://hushspec.org/schemas/hushspec-receipt.v1.schema.json) | `https://hushspec.org/schemas/hushspec-receipt.v1.schema.json` |
| [hushspec-registry-action-types.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-action-types.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-action-types.v0.schema.json` |
| [hushspec-registry-capabilities.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-capabilities.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-capabilities.v0.schema.json` |
| [hushspec-registry-condition-types.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-condition-types.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-condition-types.v0.schema.json` |
| [hushspec-registry-detectors.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-detectors.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-detectors.v0.schema.json` |
| [hushspec-registry-media-types.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-media-types.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-media-types.v0.schema.json` |
| [hushspec-registry-rule-blocks.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-rule-blocks.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-rule-blocks.v0.schema.json` |
| [hushspec-registry-rule-paths.v0.schema.json](https://hushspec.org/schemas/hushspec-registry-rule-paths.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-registry-rule-paths.v0.schema.json` |
| [hushspec-report.v0.schema.json](https://hushspec.org/schemas/hushspec-report.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-report.v0.schema.json` |
| [hushspec-report.v1.schema.json](https://hushspec.org/schemas/hushspec-report.v1.schema.json) | `https://hushspec.org/schemas/hushspec-report.v1.schema.json` |
| [hushspec-signature.v0.schema.json](https://hushspec.org/schemas/hushspec-signature.v0.schema.json) | `https://hushspec.dev/schemas/hushspec-signature.v0.schema.json` |
| [hushspec-signature.v1.schema.json](https://hushspec.org/schemas/hushspec-signature.v1.schema.json) | `https://hushspec.org/schemas/hushspec-signature.v1.schema.json` |
