Schemas
Schemas are reusable metadata templates that define the expected structure of a node's metadata.properties. They bring consistency to how data is organized across apps and agents.
Why Schemas?
Without schemas, every app invents its own metadata format. A "recipe" node from App A might store { ingredients: [...] } while App B stores { items: [...] }. Schemas solve this by providing shared definitions.
- Consistency: All apps creating "recipe" nodes use the same field names
- Validation: Metadata can be validated against a schema before saving
- Discovery: Developers browse the Schema Pool to find existing schemas instead of inventing new ones
- Interoperability: Nodes created by different apps are compatible if they share a schema
How Schemas Work
A schema defines a JSON Schema for the metadata.properties object on a node:
{
"name": "Recipe",
"category": "content",
"recommended_node_type": "recipe",
"recommended_meaning_level": "DATA",
"json_schema": {
"type": "object",
"properties": {
"ingredients": {
"type": "array",
"items": { "type": "string" }
},
"prep_time_minutes": { "type": "integer" },
"servings": { "type": "integer" }
},
"required": ["ingredients"]
}
}
When a node references this schema via schema_id, its metadata.properties can be validated against the JSON Schema definition.
Schema Visibility
| Scope | private_to | Who Can See It |
|---|---|---|
public | — | All users |
private | user | Only the schema owner |
private | app | Only the third-party app that created it |
System schemas (created by OfSelf) are always visible to everyone.
Schema Pool (Developer Dashboard)
The Developer Dashboard includes a Schema Pool tab where developers can:
- Browse all public and system schemas
- Search by name, description, or URI
- Filter by category
- Create new schemas with a form UI
- View the full JSON Schema definition for any schema
Creating a Schema
When creating a schema, you specify:
| Field | Description |
|---|---|
| Name | Human-readable name (e.g. "Recipe", "Meeting Notes") |
| Category | Grouping label (e.g. "content", "productivity", "identity") |
| Description | What this schema represents |
| Recommended Node Type | Suggested node_type for nodes using this schema |
| Recommended Meaning Level | Suggested meaning_level (DATA, CONTEXT, or IDENTITY) |
| Scope | public or private |
| Private To | user or app (when scope is private) |
| Recommended by Developer | Flag to highlight this schema in listings |
| JSON Schema | The actual JSON Schema definition |
Schema Versioning
Schemas use URI-based versioning. Each schema has a schema_uri (e.g. custom:recipe) and a version number. When you update a schema, a new version is created — the old version remains accessible.
custom:recipe v1 → original definition
custom:recipe v2 → added "cuisine" field
custom:recipe v3 → added "difficulty" field
Resolve by URI to get the latest version, or request a specific version:
# Latest version
GET /schemas/uri/custom:recipe
# Specific version
GET /schemas/uri/custom:recipe?version=2
Schema Inheritance
Schemas can extend a parent schema using the extends field. The child inherits all properties from the parent and can add its own.
{
"name": "Italian Recipe",
"extends": "parent-schema-uuid",
"json_schema": {
"type": "object",
"properties": {
"region": { "type": "string" },
"pasta_type": { "type": "string" }
}
}
}
When validated, the resolved schema merges parent + child properties.
Schema Permissions
When registering a third-party app, you can request schema permissions:
| Permission | Description |
|---|---|
schemas.read | Read schemas (specify schema_ids or allow_all) |
schemas.write | Create/update schemas (specify schema_ids or allow_all) |
{
"requested_permissions": {
"tags": { "read": true, "create": true },
"files": { "read": true },
"schemas": {
"read": { "schema_ids": [], "allow_all": true },
"write": { "schema_ids": [], "allow_all": false }
}
}
}
Using Schemas with Nodes
- Find or create a schema that matches your data structure
- Create nodes with
schema_idreferencing the schema - Validate metadata against the schema before or after creation
# Create a node with a schema
curl -X POST "https://api.ofself.ai/api/v1/nodes" \
-H "X-API-Key: your-api-key" \
-H "X-User-ID: user-123" \
-H "Content-Type: application/json" \
-d '{
"title": "Grandmother'\''s Pasta",
"node_type": "recipe",
"meaning_level": "DATA",
"graph_view": "identity",
"schema_id": "recipe-schema-uuid",
"metadata": {
"properties": {
"ingredients": ["pasta", "tomatoes", "basil"],
"prep_time_minutes": 45,
"servings": 4
}
}
}'
# Validate metadata against a schema
curl -X POST "https://api.ofself.ai/api/v1/schemas/recipe-schema-uuid/validate" \
-H "X-API-Key: your-api-key" \
-H "X-User-ID: user-123" \
-H "Content-Type: application/json" \
-d '{
"metadata": {
"ingredients": ["pasta", "tomatoes"],
"prep_time_minutes": 30
}
}'
Next
- Schemas API — Full API reference for all schema endpoints
- Nodes — How nodes use schemas for structured metadata
- Register Your App — Setting up schema permissions