Schema Validation - banisterious/obsidian-charted-roots GitHub Wiki
Schema Validation
Schema validation allows you to define data consistency rules for your person notes. Schemas ensure that specific properties exist, have correct types, and satisfy custom constraints.
Table of Contents
- Overview
- Schema Note Format
- Creating Schemas
- Schema Scope
- Property Types
- Conditional Requirements
- Constraints
- Running Validation
- Commands and Context Menu
- Examples
- Data Quality Integration
Overview
Schemas are special notes (with cr_type: schema in frontmatter) that define validation rules for person notes. Use schemas to:
- Enforce required properties: Ensure all people in a collection have specific fields
- Validate data types: Check that dates are dates, numbers are numbers, etc.
- Restrict values: Limit properties to specific enum values
- Cross-validate: Ensure logical consistency (e.g., death date after birth date)
- Validate wikilinks: Verify that linked notes exist and have the correct type
Schemas follow a UI-first design - you can create and manage them entirely through the Control Center without manually editing files.
Schema Note Format
Schema notes use flat frontmatter properties (Obsidian best practice) with the schema definition in a JSON code block.
Frontmatter Properties
| Property | Type | Required | Description |
|---|---|---|---|
cr_type |
string |
Yes | Must be "schema" |
cr_id |
string |
Yes | Unique identifier |
name |
string |
Yes | Display name |
description |
string |
No | Optional description |
applies_to_type |
string |
Yes | Scope type: collection, folder, universe, or all |
applies_to_value |
string |
Conditional | Required for collection, folder, universe scopes |
JSON Code Block
The schema definition is stored in a fenced code block with language json schema (or just json):
---
cr_type: schema
cr_id: schema-example-001
name: Example Schema
description: Validates example properties
applies_to_type: all
---
# Example Schema
This schema validates all person notes.
```json schema
{
"requiredProperties": ["name", "born"],
"properties": {
"gender": {
"type": "enum",
"values": ["Male", "Female", "Other"]
},
"age_at_death": {
"type": "number",
"min": 0,
"max": 150
}
},
"constraints": []
}
```
Creating Schemas
Via Control Center (Recommended)
- Open Control Center (
Ctrl/Cmd + P→ "Charted Roots: Open control center") - Navigate to the Schemas tab
- Click Create schema
- Fill in the form:
- Name: Display name for the schema
- Description: Optional explanation
- Scope: Who this schema applies to
- Required properties: Which fields must exist
- Property definitions: Type validation for specific properties
- Constraints: Custom validation rules
- Click Create
The modal generates the schema note automatically - no manual JSON editing required.
Editing Existing Schemas
- Open Control Center → Schemas tab
- Find your schema in the gallery
- Click the Edit button (pencil icon)
- Modify the schema in the modal
- Click Save changes
Schema Scope
Schemas can apply to different subsets of person notes:
| Scope | Description | applies_to_value |
|---|---|---|
all |
All person notes in the vault | Not needed |
collection |
People with a specific collection property |
Collection name |
folder |
People in a specific folder | Folder path |
universe |
People with a specific universe property |
Universe name |
Examples
All people:
applies_to_type: all
House Stark members:
applies_to_type: collection
applies_to_value: "House Stark"
People in staging folder:
applies_to_type: folder
applies_to_value: "People/Staging"
Middle-earth characters:
applies_to_type: universe
applies_to_value: "Middle-earth"
Property Types
Define expected types for frontmatter properties:
| Type | Description | Additional Options |
|---|---|---|
string |
Text value | - |
number |
Numeric value | min, max |
date |
Date string (YYYY, YYYY-MM, YYYY-MM-DD) | - |
boolean |
True/false | - |
enum |
One of specific values | values (array) |
wikilink |
Link to another note | targetType (place, map, person) |
array |
List of values | - |
Number Range Validation
{
"properties": {
"age_at_death": {
"type": "number",
"min": 0,
"max": 150
}
}
}
Enum Validation
{
"properties": {
"gender": {
"type": "enum",
"values": ["Male", "Female", "Other", "Unknown"]
}
}
}
Wikilink Target Validation
Verify that linked notes exist and have the correct type:
{
"properties": {
"birth_place": {
"type": "wikilink",
"targetType": "place"
}
}
}
Conditional Requirements
Properties can be required only when certain conditions are met:
{
"properties": {
"death_place": {
"type": "wikilink",
"targetType": "place",
"requiredIf": {
"property": "died",
"exists": true
}
},
"magic_type": {
"type": "enum",
"values": ["warging", "greensight", "none"],
"requiredIf": {
"property": "has_magic",
"equals": true
}
}
}
}
Condition Types
| Condition | Description |
|---|---|
exists: true |
Required if property has any value |
exists: false |
Required if property is empty/missing |
equals: value |
Required if property equals specific value |
notEquals: value |
Required if property does not equal value |
Constraints
Constraints are JavaScript expressions that validate relationships between properties. They run in a sandboxed environment with access to the person's frontmatter.
{
"constraints": [
{
"rule": "!died || born",
"message": "Cannot have death date without birth date"
},
{
"rule": "!died || !born || new Date(died) >= new Date(born)",
"message": "Death date must be after birth date"
}
]
}
Available Variables
Within constraint expressions, you can access any frontmatter property directly by name:
name- Person's nameborn- Birth datedied- Death dategender- Gender- Any other frontmatter property
Examples
Death after birth:
{
"rule": "!died || !born || new Date(died) >= new Date(born)",
"message": "Death date must be after birth date"
}
Parents cannot be same person:
{
"rule": "!father_id || !mother_id || father_id !== mother_id",
"message": "Father and mother cannot be the same person"
}
Age validation:
{
"rule": "!age_at_death || age_at_death <= 150",
"message": "Age at death seems unrealistic (>150)"
}
Running Validation
From Schemas Tab
- Open Control Center → Schemas tab
- Click Validate vault
- Review results showing:
- Total people validated
- Pass/fail counts
- Error breakdown by type
- List of violations with links to affected notes
Commands and Context Menu
Commands
| Command | Description |
|---|---|
Charted Roots: Open schemas tab |
Open Control Center to Schemas tab |
Charted Roots: Validate vault against schemas |
Run full vault validation |
Context Menu
Person notes:
- Right-click → Charted Roots → Validate against schemas
- Validates the single person against all applicable schemas
Schema notes:
- Right-click → Charted Roots → Edit schema
- Right-click → Charted Roots → Validate matching notes — Runs validation against only notes matching this schema's target type, with a progress modal and result summary
- Right-click → Charted Roots → Open schemas tab
Examples
Basic Required Fields Schema
---
cr_type: schema
cr_id: schema-basic-required
name: Basic Required Fields
description: Ensures all people have essential information
applies_to_type: all
---
# Basic Required Fields
```json schema
{
"requiredProperties": ["name", "cr_id"],
"properties": {},
"constraints": []
}
```
House Stark Schema (World-Building)
---
cr_type: schema
cr_id: schema-house-stark
name: House Stark Schema
description: Validation rules for House Stark members
applies_to_type: collection
applies_to_value: "House Stark"
---
# House Stark Schema
```json schema
{
"requiredProperties": ["allegiance", "combat_style"],
"properties": {
"race": {
"type": "enum",
"values": ["human", "direwolf"],
"default": "human"
},
"magic_type": {
"type": "enum",
"values": ["warging", "greensight", "none"],
"requiredIf": {
"property": "has_magic",
"equals": true
}
},
"allegiance": {
"type": "wikilink"
},
"birth_place": {
"type": "wikilink",
"targetType": "place"
}
},
"constraints": [
{
"rule": "magic_type !== 'greensight' || race !== 'direwolf'",
"message": "Direwolves cannot have greensight"
}
]
}
```
Date Validation Schema
---
cr_type: schema
cr_id: schema-date-validation
name: Date Validation
description: Ensures date fields are logically consistent
applies_to_type: all
---
# Date Validation Schema
```json schema
{
"requiredProperties": [],
"properties": {
"born": {
"type": "date"
},
"died": {
"type": "date"
}
},
"constraints": [
{
"rule": "!died || born",
"message": "Cannot have death date without birth date"
},
{
"rule": "!died || !born || new Date(died) >= new Date(born)",
"message": "Death date must be on or after birth date"
}
]
}
```
Import Quality Schema
---
cr_type: schema
cr_id: schema-import-quality
name: Import Quality Check
description: Validates imported GEDCOM data in staging folder
applies_to_type: folder
applies_to_value: "People/Staging"
---
# Import Quality Check
```json schema
{
"requiredProperties": ["name", "cr_id"],
"properties": {
"born": {
"type": "date"
},
"gender": {
"type": "enum",
"values": ["Male", "Female", "M", "F"]
}
},
"constraints": []
}
```
Data Quality Integration
Schemas can protect custom property values from normalization operations.
Schema-Aware Sex Normalization
The "Normalize sex values" operation in Data Quality can be configured to respect schemas with custom sex enum values. When Schema-aware mode is enabled in Preferences → Data Quality:
- Person notes with an applicable schema defining a custom
sexenum are skipped - Notes without such schemas are normalized to GEDCOM M/F as usual
This allows worldbuilders to define custom biological sex values (e.g., for alien species) while genealogists maintain GEDCOM compatibility.
Example schema for custom sex values:
---
cr_type: schema
cr_id: schema-alien-species
name: Alien Species Schema
description: Custom sex values for non-human species
applies_to_type: universe
applies_to_value: "Sci-Fi Universe"
---
# Alien Species Schema
```json schema
{
"requiredProperties": ["name", "species"],
"properties": {
"sex": {
"type": "enum",
"values": ["male", "female", "neuter", "hermaphrodite", "asexual"],
"description": "Biological sex for this species"
},
"species": {
"type": "string"
}
},
"constraints": []
}
```
With this schema in place and Schema-aware normalization enabled, person notes in the "Sci-Fi Universe" with sex values like "hermaphrodite" or "neuter" will be preserved when running "Normalize sex values".
See Data Quality - Normalization Modes for configuration details.
See Also
- Frontmatter Reference - All frontmatter properties
- Data Management - Managing your family data
- Import & Export - Importing data that needs validation
- Data Quality - Batch operations and normalization