Language · Reference
Schema.
KGL schemas define node types, required fields, and allowed relationships. They are warning-only — a file without required fields is still valid KGL, but a linter will flag the missing fields. Write .kgl files freely first, add schema validation as your graph matures.
Schema files
Schema is defined in _schema.kgl files. Two kinds:
Root schema
/_schema.kgl
Defines global rules for the entire graph. All node type and relationship type definitions here apply everywhere unless overridden by a local schema.
Local schema
/people/_schema.kgl
/projects/_schema.kgl
Extends or tightens the root schema for a specific folder. Inherits all root definitions. Local definitions for the same type override the root definition for files in that folder only.
Schema lookup for any .kgl file: local _schema.kgl first, then walk up to root. First definition of a type wins.
Node type definitions
@NodeType Person
name!: text
joined?: date
role?: text
Field markers
| Marker | Meaning |
|---|---|
field!: type | Required. Linter warns if absent on a matching node. |
field?: type | Optional. Documents the field exists without requiring it. |
Fields without a marker are undocumented — they can still appear in data files, but the schema says nothing about them.
Inheritance
@NodeType Contractor
extends: Person
contract-end!: date
extends pulls in all fields from the named type. The extending type can add new required or optional fields on top.
Relationship type definitions
@RelType employs
from: Person → Project|Service
role!: text
since!: date
note?: text
from — endpoint constraints
from: SourceType → TargetType
Constrains which node types may appear on each side of the relationship. A linter warns if a relationship is used between incompatible types.
Both sides support type unions:
from: Project|Service → Project|Service
This means: either a Project or Service may link to either a Project or Service using this relationship.
Relationship properties
Properties defined under a @RelType work the same as node fields — ! for required, ? for optional. A linter warns if a required relationship property is missing when that relationship is used in a data file.
Local override example
# people/_schema.kgl
# Extends root schema for the /people folder.
@NodeType Person
extends: Person
team!: text
github?: text
This adds team as required and github as optional for all @Person nodes in the /people folder. The root schema's name!, joined?, and role? fields are still inherited.
Complete root schema example
# _schema.kgl
## Node types
@NodeType Person
joined!: date
role?: text
@NodeType Contractor
extends: Person
contract-end!: date
@NodeType Project
status!: text
deadline?: date
@NodeType Service
owner!: text
url?: text
@NodeType Decision
date!: date
status!: text
context?: text
## Relationship types
@RelType reports-to
from: Person → Person
since?: date
@RelType employs
from: Person → Project|Service
role?: text
since!: date
@RelType staffed-by
from: Project → Person
role!: text
since!: date
@RelType depends-on
from: Project|Service → Project|Service
since?: date
sunset-date?: date
note?: text
@RelType mentors
from: Person → Person
started!: date
focus?: text
@RelType owned-by
from: Project|Service → Person
since?: date
Linter warnings
A linter checking this schema would warn on:
Missing required field
@Person Charlie Watts
# ⚠ warning: missing required field 'joined' (from @NodeType Person in _schema.kgl)
# ⚠ warning: missing required field 'team' (from @NodeType Person in people/_schema.kgl)
Type mismatch on relationship
[depends-on] → people/diana.kgl#Diana Park
# ⚠ warning: relationship 'depends-on' expects Project|Service → Project|Service
# but source is @Person — type mismatch
Missing required relationship property
[staffed-by] → people/alice.kgl#Alice Nguyen
# ⚠ warning: missing required property 'role' on relationship 'staffed-by'
# ⚠ warning: missing required property 'since' on relationship 'staffed-by'
Design notes
- Schemas are additive, not restrictive. An undocumented field in a data file is not a warning — only missing required fields are.
- A
@NodeTypethat doesn't appear in the schema is not warned on. Unknown types are valid. - Enums (allowed values for fields) are a planned future extension.