Schema validation¶
Sphinx-Needs (≥ 6.0) includes a powerful schema validation system
based on JSON Schema.
The schema_definitions_from_json option in [needs]
points to a JSON file of validation rules
that check individual need properties and cross-need relationships.
Use this when per-field schema constraints (see Field schemas)
are not enough —
for example to enforce that certain need types carry specific fields,
or that linked needs satisfy particular conditions.
See also
- sphinx-needs schema documentation
The full sphinx-needs schema reference.
Minimal example¶
[needs]
schema_definitions_from_json = "schemas.json"
With a schemas.json alongside your ubproject.toml:
{
"schemas": [
{
"id": "spec-needs-priority",
"message": "Specifications must have a priority",
"select": {
"properties": { "type": { "const": "spec" } }
},
"validate": {
"local": { "required": ["priority"] }
}
}
]
}
Overview¶
Schema validation operates at multiple levels:
Field-level schemas — defined inline on
[needs.fields]or[needs.links], these validate every value entered for that field globally (see Field schemas).Schema definitions — defined in a
schemas.jsonfile (viaschema_definitions_from_json), these provide advanced validation including type-specific rules, conditional constraints, and cross-need (network) validation.
Both levels complement each other: field-level schemas enforce global constraints for a field, while schema definitions allow complex, type-specific validation logic.
Configuration¶
- schema_definitions_from_json
Type:
string(default:"")Path to a JSON file containing schema definitions. Available since sphinx-needs 6.0.
[needs] schema_definitions_from_json = "schemas.json"
The schemas.json file¶
The schema file has two top-level keys:
"$defs"(optional): Reusable schema components referenced via$ref"schemas"(required): Array of validation rule objects
{
"$defs": {
"type-spec": {
"properties": {
"type": { "const": "spec" }
}
},
"safe-need": {
"properties": {
"asil": { "enum": ["A", "B", "C", "D"] }
},
"required": ["asil"]
}
},
"schemas": [
{
"id": "spec-id-pattern",
"severity": "warning",
"message": "Spec IDs must be uppercase",
"select": {
"$ref": "#/$defs/type-spec"
},
"validate": {
"local": {
"properties": {
"id": { "pattern": "^SPEC_[A-Z0-9_]+$" }
}
}
}
}
]
}
Each schema object in the schemas array supports:
id(optional): Identifier for the schema rule (used in error messages)severity(optional):"violation"(default),"warning", or"info"message(optional): Custom message shown when validation failsselect(optional): JSON Schema that filters which needs this rule applies to. If omitted, the rule applies to all needs.validate(required): Validation rules with two subsections:local: Validates properties of the need itselfnetwork: Validates relationships with linked needs
Type system¶
Sphinx-Needs supports the following types for need fields,
defined via schema.type in [needs.fields]:
Primitive types:
string,boolean,integer,numberArray types:
arraywith typed items (e.g.schema = {type = "array", items = {type = "string"}})
Type information from [needs.fields] is automatically injected
into schemas.json rules,
so you don’t need to repeat "type": "string" in every schema.
If you do specify a type in the schema file,
it must match the field definition.
Local validation¶
Local validation checks properties of a single need without any information from other needs. This makes it suitable for instant feedback in IDEs.
Example: enforce that efforts is between 0 and 20,
and that approval is required when efforts exceed 15:
{
"schemas": [
{
"id": "efforts-range",
"select": {
"properties": { "type": { "enum": ["spec", "feat"] } }
},
"validate": {
"local": {
"properties": {
"efforts": {
"minimum": 0,
"maximum": 20
}
}
}
}
},
{
"id": "approval-required-for-high-effort",
"severity": "violation",
"message": "Approval required when efforts > 15",
"select": {
"properties": {
"type": { "enum": ["spec", "feat"] },
"efforts": { "minimum": 16 }
},
"required": ["efforts"]
},
"validate": {
"local": {
"required": ["approval"]
}
}
}
]
}
The select filter narrows which needs the rule applies to.
The validate.local section uses standard JSON Schema properties:
properties, required, allOf, anyOf, oneOf, not,
unevaluatedProperties, etc.
Network validation¶
Network validation checks relationships between linked needs. After link resolution, the validator follows outgoing links and validates properties of the target needs.
Example: a safe implementation must link to at least one safe, approved specification:
{
"id": "safe-impl-links",
"message": "Safe impl must link to approved safe specs",
"select": {
"allOf": [
{ "$ref": "#/$defs/type-impl" },
{ "$ref": "#/$defs/safe-need" }
]
},
"validate": {
"network": {
"links": {
"contains": {
"local": {
"allOf": [
{ "$ref": "#/$defs/type-spec" },
{ "$ref": "#/$defs/safe-need" },
{
"properties": {
"approval": { "const": true }
}
}
]
}
},
"minContains": 1
}
}
}
}
Key network validation properties:
validate.network.<link_type>.items— schema that all linked needs must matchvalidate.network.<link_type>.contains— schema that some linked needs must matchminContains/maxContains— how many linked needs must satisfy thecontainsschemavalidate.local.properties.<link_type>.minItems/maxItems— total link count constraints (checked locally since links are ID lists)
Network validation can be nested to validate multi-hop chains (e.g. impl → spec → feat), up to 4 levels deep.
Reusable definitions ($defs)¶
Define common schema fragments in $defs and reference them with $ref:
{
"$defs": {
"type-impl": {
"properties": { "type": { "const": "impl" } }
},
"type-spec": {
"properties": { "type": { "const": "spec" } }
},
"safe-need": {
"properties": {
"asil": { "enum": ["A", "B", "C", "D"] }
},
"required": ["asil"]
},
"safe-spec": {
"allOf": [
{ "$ref": "#/$defs/safe-need" },
{ "$ref": "#/$defs/type-spec" }
]
}
},
"schemas": []
}
$ref must be the only key in the object where it appears.
Recursive references are not allowed.
Severity levels¶
Each schema rule can specify a severity:
"info"— informational, logged as a Sphinx warning"warning"— logged as a Sphinx warning"violation"— logged as a Sphinx error (default)
{
"severity": "warning",
"message": "Consider adding a priority field",
"validate": {
"local": {
"required": ["priority"]
}
}
}
Validation messages can be suppressed using Sphinx’s suppress_warnings:
# In conf.py
suppress_warnings = [
"sn_schema_violation", # all violations
"sn_schema_warning", # all warnings
"sn_schema_info", # all info messages
"sn_schema_violation.local_fail", # only local failures
]
Supported field constraints¶
The following JSON Schema constraints are available per type.
These can be used both in [needs.fields] inline schemas
and in schemas.json validation rules.
String:
minLength, maxLength, pattern, format, enum, const
Integer / Number:
minimum, maximum, exclusiveMinimum, exclusiveMaximum,
multipleOf, enum, const
Boolean:
const
Array:
items (with sub-schema), minItems, maxItems,
uniqueItems, contains, minContains, maxContains
String format values:
"date", "date-time", "time", "duration",
"email", "uri", "hostname", "uuid", "regex"
Note
Regex pattern values must be cross-engine compatible
(Python, Rust, SQLite).
Avoid lookaheads, lookbehinds, backreferences,
and nested quantifiers.
Complete example¶
The following shows a ubproject.toml with typed fields
and a schemas.json that validates them:
ubproject.toml:
[needs]
id_required = true
schema_definitions_from_json = "schemas.json"
[[needs.types]]
directive = "feat"
title = "Feature"
prefix = "FEAT_"
[[needs.types]]
directive = "spec"
title = "Specification"
prefix = "SPEC_"
[[needs.types]]
directive = "impl"
title = "Implementation"
prefix = "IMPL_"
[needs.links.implements]
outgoing = "implements"
incoming = "implemented by"
[needs.fields.efforts]
schema = {type = "integer", minimum = 0, maximum = 100}
[needs.fields.approval]
schema = {type = "boolean"}
[needs.fields.asil]
schema = {type = "string", enum = ["QM", "A", "B", "C", "D"]}
schemas.json:
{
"$defs": {
"type-impl": {
"properties": { "type": { "const": "impl" } }
},
"type-spec": {
"properties": { "type": { "const": "spec" } }
},
"safe-need": {
"properties": {
"asil": { "enum": ["A", "B", "C", "D"] }
},
"required": ["asil"]
}
},
"schemas": [
{
"id": "effort-limits",
"message": "Efforts must be between 0 and 20 for specs",
"select": {
"properties": { "type": { "const": "spec" } }
},
"validate": {
"local": {
"properties": {
"efforts": { "maximum": 20 }
}
}
}
},
{
"id": "safe-impl-chain",
"message": "Safe impl must link to safe spec",
"select": {
"allOf": [
{ "$ref": "#/$defs/type-impl" },
{ "$ref": "#/$defs/safe-need" }
]
},
"validate": {
"network": {
"implements": {
"contains": {
"local": {
"allOf": [
{ "$ref": "#/$defs/type-spec" },
{ "$ref": "#/$defs/safe-need" }
]
}
},
"minContains": 1
}
}
}
}
]
}
Further reading¶
For the complete reference including all validation options, error message formats, debug tooling, and migration guides, see the sphinx-needs schema validation documentation.