Skip to Content
Numinance
Protocol

Kinds and JSON Schema

How the sixteen configuration kinds map to protobuf messages, the strict JSON Schemas generated from them, and what numi validate --files does and does not check.

View as .mdUpdated
Available in public spec
The kinds, generated schemas and the Go loader are in numinance-spec. The open numi validate --files checks schema and loader only; profile resolution and floors need the proprietary engine.

Configuration is typed. Each YAML kind is a protobuf message, its JSON Schema is generated from that message, and an unknown field is an error, not a silent ignore.

When to use this page

Use it to understand why a YAML file under .numinance/ is valid or not, to find the generated schema for a kind, or to wire the schemas into an editor or CI. For how to write each kind, go to the configuration section; for the error messages you will see, see Validation and errors.

The envelope

Every kind is one message with the same envelope: api_version, kind, metadata, spec and extensions. In YAML the envelope key is spelled apiVersion and every other key is proto snake_case.

schemas/examples/AutonomyPolicy/org-ladder.yaml
apiVersion: numinance.dev/v1
kind: AutonomyPolicy
metadata: {name: org-ladder, scope: SCOPE_ORG}
spec:
  defaults: {level: AUTONOMY_LEVEL_PR}
  rules:
    - {match: {playbook: dependency-upgrade, risk: RISK_CLASS_LOW}, level: AUTONOMY_LEVEL_MERGE}
  floors:
    rules:
      - {match: {risk: RISK_CLASS_HIGH}, max_level: AUTONOMY_LEVEL_SUGGEST}
      - {match: {environment: production}, max_level: AUTONOMY_LEVEL_MERGE}
Envelope fieldRole
apiVersionVersion of the kind. numinance.dev/v1 for all kinds except EvalSet, which is numinance.dev/v1alpha1.
kindWhich kind the resource is.
metadataname (required, unique per kind and scope) and scope (required, not SCOPE_UNSPECIFIED).
specThe kind-specific body.
extensionsExtension data under reverse-DNS keys. Unknown fields anywhere else are schema errors.

Enum values are spelled by their full proto name (SCOPE_ORG, RISK_CLASS_LOW); durations use the protobuf JSON form (7200s). Per the schemas README, this key spelling is pending ratification and may change before the first tag.

ContextBundle is produced by Numinance and never authored, so its envelope is apiVersion, kind and spec with no metadata and no extensions; the loader refuses it. EvalSet is alpha and off by default.

The sixteen kinds

KindProto fileapiVersionWritten byConfiguration page
AdapterSelectoradapter_selector.protonuminance.dev/v1YouAdapters and environments
ArchitecturePackarchitecture_pack.protonuminance.dev/v1YouToolchains and packs
AutonomyPolicyautonomy_policy.protonuminance.dev/v1YouAutonomy policy
BudgetPolicybudget_policy.protonuminance.dev/v1YouGovernance kinds
ContextBundlecontext_bundle.protonuminance.dev/v1ProducedEvals and context bundle
ControlPackcontrol_pack.protonuminance.dev/v1YouGovernance kinds
EnvironmentProviderenvironment_provider.protonuminance.dev/v1YouAdapters and environments
EvalSeteval_set.protonuminance.dev/v1alpha1You (alpha)Evals and context bundle
ExecutorManifestexecutor_manifest.protonuminance.dev/v1YouAdapters and environments
IndexerPluginindexer_plugin.protonuminance.dev/v1YouToolchains and packs
KnowledgeConnectionknowledge_connection.protonuminance.dev/v1YouKnowledge connection
LanguageToolchainlanguage_toolchain.protonuminance.dev/v1YouToolchains and packs
Playbookplaybook.protonuminance.dev/v1YouPlaybooks
ResidencyPolicyresidency_policy.protonuminance.dev/v1YouGovernance kinds
SDLCProfilesdlc_profile.protonuminance.dev/v1YouSDLC profile
StageRegistrystage_registry.protonuminance.dev/v1YouStage registry

Proto files are under proto/numinance/kinds/v1/. Each authored kind has at least one example under schemas/examples/KIND/.

How the schemas are generated

buf.gen.yaml runs a JSON Schema plugin over the numinance.kinds.v1 package only:

buf.gen.yaml (excerpt)
  - local: ["go", "-C", "../tools", "tool", "protoc-gen-jsonschema"]
    out: schemas/gen
    opt: target=json-strict-bundle
    types:
      - numinance.kinds.v1

The json-strict-bundle target produces JSON Schema 2020-12 with JSON names (apiVersion; multi-word kind fields set json_name to their snake_case name), no aliases or string numbers, and a self-contained file per message: dependencies sit under $defs and every $ref is local.

  • The schema of a kind is schemas/gen/numinance.kinds.v1.KIND.jsonschema.strict.bundle.json, for example numinance.kinds.v1.AutonomyPolicy.jsonschema.strict.bundle.json.
  • The generator also writes a file for every other message it sees (specs, Metadata, the annotation options). A loader does not use those.
  • Generated files are never edited by hand. The spec repository's just gen regenerates them (it also runs the Go, Python and TypeScript generators from the same buf.gen.yaml; see Generating clients).
  • 64-bit integers are avoided in kinds, because protojson writes them as strings and the strict schema rejects strings there.
  • Merge directives are declared with a field option and are not carried by the JSON Schema.

Two gates

  1. The schema is the first gate. It rejects unknown fields (additionalProperties), wrong types and wrong enum spellings.
  2. The loader is the second. sdk/go/kindyaml also checks what a schema cannot: metadata and spec present, apiVersion and kind equal to their constants, no zero enum value, required lists non-empty, and reverse-DNS extensions keys. Each kind adds checks, listed in sdk/go/kindyaml/README.md.

numi validate --files PATH runs both. It is strict schema plus loader only: no profile resolution, no floors. A pass means the resource is well-formed, not that your configuration is resolved or ready. Ordinary open numi validate schema-passes and then exits 7 because profile resolution needs the Numinance engine build.

$ numi validate --files --json schemas/examples/AutonomyPolicy
{"status":"ok","revision":"files","documents":[{"scope":"file","path":"org-ladder.yaml","kind":"AutonomyPolicy","name":"org-ladder","status":"ok"}]}
✓ verifiedReal run against the spec checkout (revision 3c74d59); the valid example above· numinance-spec @ 3c74d59 · 2026-11-09· 0

A file with an unknown field under spec fails the first gate. This YAML is deliberately invalid:

bad.yaml
apiVersion: numinance.dev/v1
kind: AutonomyPolicy
metadata: {name: org-ladder, scope: SCOPE_ORG}
spec:
  not_a_field: true
$ numi validate --files bad
revision: "files"
invalid  file "bad.yaml": kind: does not match the kind schema: schema: value does not match (violations: 1): \"/spec/not_a_field\": additionalProperties
✓ verifiedReal run of numi validate --files on the invalid file above· numinance-spec @ 3c74d59 · 2026-11-09· 3

Exit codes and more real error messages are on Validation and errors and numi validate.

Scope and merge directives

Resolution loads org, then repo, then component. These two enums are in kinds/v1/meta.proto.

MergeDirective

MergeDirective says how profile resolution merges a field across org, repo and component scope; it is declared with the merge field option, only on fields reached from spec through singular messages. This enum may grow: a resolver that does not know a value refuses the profile.

NumberValueMeaning
0MERGE_DIRECTIVE_UNSPECIFIEDThe default of a field without the option: a singular numinance message merges field by field, and any other field (scalar, enum, list, map, well-known type) is replaced; a oneof is replaced as a unit.
1MERGE_DIRECTIVE_REPLACEReplaces the whole value, a message included, with the narrower scope's value.
2MERGE_DIRECTIVE_APPENDKeeps the wider scope's names, then adds the narrower scope's names not already present; only on repeated string fields.
3MERGE_DIRECTIVE_FORBIDMarks a floor: only a kind loaded from the org scope (not its own metadata.scope) or a control pack may set it; a narrower scope fails validation. Only on a field with presence (never a list, map or oneof member) and never below a REPLACE parent.

Scope

Scope is the level a kind applies at; resolution loads org, then repo, then component.

NumberValueMeaning
0SCOPE_UNSPECIFIEDThe zero value; a loader rejects it.
1SCOPE_ORGApplies to every repository of the organisation; only org-scoped kinds may set floors.
2SCOPE_REPOApplies to one repository.
3SCOPE_COMPONENTApplies to one component of a repository.

SCOPE_ORG kinds may set floors. A merge directive of MERGE_DIRECTIVE_FORBID marks a floor: only a kind loaded from the org scope or a control pack may set it, and a narrower scope fails validation. The directive is the field option numinance.kinds.v1.merge, extension number 50003. A resolver that does not know a directive value refuses the profile. Resolution itself is outside the open build.

Using the schemas in your editor or CI

The schema files are plain JSON Schema 2020-12 documents, so any validator that supports 2020-12 and local $ref can use them. The Go loader embeds the kind schemas (schemas/embed.go), so numi validate --files needs no network. For repository CI, running numi validate --files .numinance is the supported check in the open build.

Failure modes and safeguards

SituationResult
Unknown field outside extensionsSchema error, for example additionalProperties at a path.
scope missing or SCOPE_UNSPECIFIEDLoader error.
Enum written in short form (PR rather than AUTONOMY_LEVEL_PR)Schema error.
ContextBundle authored by handLoader refuses it.
EvalSet with a default loaderRefused; the alpha loader option is enabled for numi validate --files.
Profile resolution requested in the open buildExit 7.

Next steps

On this page