Docs/Core SDK/Schema Definition

    Schema Definition

    The schema.json file is the single source of truth for an S3WORM bucket. It lives at .worm/schema.json and defines the data model, storage layout, access rules, and code generation settings for the entire bucket.


    Top-Level Fields

    FieldTypeRequiredDescription
    schemaVersionstringYesSchema format version (currently "1.0")
    sourceOfTruthstringYesSync direction: "local", "remote", or "bidirectional"
    symbolsobjectNoPath DSL symbol definitions
    dynamicTypesobjectNoCustom dynamic segment types with regex patterns
    operatorsobjectNoID generation strategies
    storageobjectNoStorage layout configuration
    pathsstring[]NoDeclared path patterns
    modelsobjectNoModel definitions (the core of the schema)
    viewsobjectNoSaved queries over models
    rulesobjectNoPath-level ACLs, scopes, and hooks
    importobjectNoAI import configuration
    generatedDirstringNoOutput directory for codegen
    aclobjectNoBucket-level access control

    Source of Truth

    The sourceOfTruth field determines which copy of the data is authoritative during sync operations.

    {
      "sourceOfTruth": "local"  // "local" | "remote" | "bidirectional"
    }
    
    ValueBehavior
    "local"Local .worm/data/ is the canonical copy. Pushes overwrite remote.
    "remote"The S3 bucket is the canonical copy. Pulls overwrite local.
    "bidirectional"Changes flow both ways. Conflicts must be resolved.

    Symbols

    Symbols define the special characters used in the path DSL. These provide semantic meaning to path segments.

    {
      "symbols": {
        "namespace": "#",
        "collection": "@",
        "dynamic": "()",
        "requiredFile": "[]"
      }
    }
    
    SymbolMeaningExample
    namespace (#)Static grouping prefix#org
    collection (@)Entity collection@customers
    dynamic (())Variable path segment(id:uuid)
    requiredFile ([])Required file within an entity[profile].json

    A complete path pattern looks like:

    #org/@customers/(id:uuid)/[profile].json
    

    Dynamic Types

    Custom types for dynamic path segments. Each type includes a regex pattern for validation.

    {
      "dynamicTypes": {
        "uuid": {
          "regex": "^[0-9a-fA-F-]{36}$"
        },
        "evm": {
          "regex": "^0x[a-fA-F0-9]{40}$"
        },
        "nanoid": {
          "regex": "^[A-Za-z0-9_-]{21}$"
        },
        "slug": {
          "regex": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
        }
      }
    }
    

    Dynamic types are referenced in path patterns using the (name:type) syntax:

    #org/@customers/(id:uuid)        # validates as UUID
    #org/@wallets/(addr:evm)         # validates as EVM address
    

    Operators

    Operators define ID generation strategies for dynamic path segments.

    {
      "operators": {
        "auto": {
          "strategy": "uuid"      // generates a UUID v4
        },
        "seq": {
          "strategy": "increment",
          "startAt": 1,
          "step": 1
        }
      }
    }
    
    StrategyBehavior
    "uuid"Generates a random UUID v4
    "increment"Sequential integer IDs with configurable startAt and step

    Storage Layout

    Controls where system directories (.oplog, .snapshots, .worm.trash) are placed within the bucket. This is a bucket-level setting that applies to all models.

    {
      "storage": {
        "layout": "root",
        "oplog": "root",
        "snapshots": "inline",
        "trash": "root"
      }
    }
    

    Layout Modes

    ModeLocationBest For
    "inline"Inside each entity folderSmall datasets, entity-level portability
    "collection"At the collection directory levelMedium datasets, per-collection audit scans
    "root"At the bucket rootLarge datasets, global audit log, clean entity paths

    Per-System Overrides

    The top-level layout sets the default. Individual system directories can override:

    {
      "storage": {
        "layout": "root",        // default for all system dirs
        "snapshots": "inline"    // override: snapshots live inside entity folders
      }
    }
    

    Path Resolution Examples

    // layout: "root"
    oplogPath("Customer", "abc-123")     // ".oplog/customers/abc-123/"
    snapshotPath("Customer", "abc-123")  // ".snapshots/customers/abc-123/"
    trashPath("Customer", "abc-123")     // ".worm.trash/customers/abc-123/"
    
    // layout: "inline"
    oplogPath("Customer", "abc-123")     // "org/customers/abc-123/.oplog/"
    snapshotPath("Customer", "abc-123")  // "org/customers/abc-123/.snapshots/"
    
    // layout: "collection"
    oplogPath("Customer", "abc-123")     // "org/customers/.oplog/abc-123/"
    snapshotPath("Customer", "abc-123")  // "org/customers/.snapshots/abc-123/"
    

    Models

    The models object is the core of the schema. Each key is a model name (PascalCase), and each value is a complete model definition.

    {
      "models": {
        "Customer": {
          "path": "#org/@customers/(id:uuid)",
          "idType": "uuid",
          "fields": {
            "name": { "type": "string", "required": true },
            "email": { "type": "string", "required": true },
            "company": { "type": "string" },
            "status": {
              "type": "string",
              "enum": ["active", "inactive", "churned"],
              "default": "active"
            },
            "tags": { "type": "string[]" },
            "createdAt": { "type": "datetime", "auto": true },
            "updatedAt": { "type": "datetime", "auto": true }
          },
          "file": "[profile].json",
          "mode": "readwrite",
          "oplog": true,
          "softDelete": true,
          "snapshots": {
            "enabled": true,
            "every": 10,
            "maxAge": "30d",
            "maxCount": 50
          }
        }
      }
    }
    

    Model-Level Fields

    FieldTypeDefaultDescription
    pathstring--Path DSL pattern for this model's entities
    idTypestring"uuid"Type of entity ID (must match a dynamicTypes entry)
    fieldsobject--Field definitions (see below)
    filestring--Filename pattern for the entity document
    modestring"readwrite"Access mode: "readonly", "readwrite", or "append"
    singletonbooleanfalseIf true, single document at the path (no ID)
    oplogbooleanfalseEnable operation log for change tracking
    softDeletebooleanfalseMove to trash on delete instead of permanent removal
    snapshotsobject--Point-in-time snapshot configuration
    refsobject--Named relationships to other models
    integrityobject--Reference integrity configuration
    manifestobject--Collection manifest for fast queries
    indexesobject--Field indexes for targeted lookups
    aclobject--Per-model access control list

    Field Definitions

    Each field in the fields object describes a property on the entity.

    interface FieldDefinition {
      type: "string" | "number" | "boolean" | "datetime"
          | "object" | "string[]" | "number[]" | "object[]";
      required?: boolean;     // must be present on save
      default?: unknown;      // value when not provided
      enum?: string[];        // allowed values
      auto?: boolean;         // auto-populated (e.g., timestamps)
      ref?: string;           // references another model name
      embedded?: boolean;     // inline data, not a foreign ref
      encrypted?: boolean;    // encrypted at rest
      acl?: string[];         // principals allowed to decrypt
    }
    

    Field Types

    TypeDescriptionExample Value
    "string"Text value"hello"
    "number"Numeric value (integer or float)42.5
    "boolean"True or falsetrue
    "datetime"ISO 8601 timestamp"2026-02-24T12:00:00Z"
    "object"Nested JSON object{ "key": "value" }
    "string[]"Array of strings["a", "b", "c"]
    "number[]"Array of numbers[1, 2, 3]
    "object[]"Array of objects[{ "name": "item" }]

    References

    The ref field creates a relationship to another model. The field stores the referenced entity's ID.

    {
      "fields": {
        "customerId": {
          "type": "string",
          "required": true,
          "ref": "Customer"
        }
      }
    }
    

    Encrypted Fields

    Fields marked encrypted: true are encrypted at rest. The optional acl array restricts which principals can decrypt the field.

    {
      "fields": {
        "ssn": {
          "type": "string",
          "encrypted": true,
          "acl": ["admin", "compliance-service"]
        }
      }
    }
    

    Access Modes

    ModeBehavior
    "readonly"Only findById, findAll, count, exists. Writes throw.
    "readwrite"Full CRUD. Default mode.
    "append"Can create new entities but never update or delete. True write-once.

    Singleton Models

    Models with singleton: true have no ID. They represent a single document at the collection path.

    {
      "models": {
        "OrgSettings": {
          "path": "#org/@settings",
          "singleton": true,
          "fields": {
            "orgName": { "type": "string", "required": true },
            "plan": { "type": "string", "enum": ["free", "pro", "enterprise"] },
            "features": { "type": "object" }
          },
          "file": "[config].json",
          "mode": "readwrite"
        }
      }
    }
    
    // Singleton SDK usage
    const settings = await worm.model("OrgSettings").get();
    await worm.model("OrgSettings").set({ orgName: "My Org", plan: "pro" });
    

    Snapshot Configuration

    {
      "snapshots": {
        "enabled": true,
        "every": 10,        // snapshot every N oplog entries
        "maxAge": "30d",    // auto-prune snapshots older than 30 days
        "maxCount": 50      // keep at most 50 snapshots per entity
      }
    }
    

    Views

    Views are saved queries defined at the schema level. They act as pre-configured filters over models.

    {
      "views": {
        "ActiveCustomers": {
          "model": "Customer",
          "filter": { "status": "active" },
          "sort": { "field": "createdAt", "order": "desc" },
          "description": "All active customers, newest first"
        },
        "UnpaidInvoices": {
          "model": "Invoice",
          "filter": { "status": { "$in": ["draft", "sent"] } },
          "sort": { "field": "issuedAt", "order": "asc" },
          "description": "Invoices not yet paid"
        },
        "RecentlyDeleted": {
          "model": "Customer",
          "source": "trash",
          "sort": { "field": "deletedAt", "order": "desc" },
          "limit": 100,
          "description": "Recently soft-deleted customers"
        }
      }
    }
    

    View Fields

    FieldTypeDescription
    modelstringWhich model this view queries
    filterobjectFilter criteria
    sortobjectSort config: { field, order }
    limitnumberMaximum results
    sourcestring"live" (default) or "trash"
    descriptionstringHuman-readable description
    // SDK usage
    const active = await worm.view("ActiveCustomers").findAll();
    const unpaid = await worm.view("UnpaidInvoices").findAll({ limit: 10 });
    

    Rules

    Rules apply path-level ACLs, scopes, validators, and write hooks.

    {
      "rules": {
        "customer-owner-only": {
          "applyTo": "#org/@customers/(id:uuid)",
          "acl": "owner",
          "scope": "entity.createdBy === principal.id",
          "validator": "required(name, email)",
          "onWrite": "log"
        }
      }
    }
    

    Rule Fields

    FieldTypeDescription
    applyTostringPath pattern this rule targets
    aclstring | objectACL shorthand or structured permissions
    scopestringExpression evaluated against path params and principal
    validatorstringValidation function name
    onWritestringHook triggered on write operations

    Rules are evaluated in order during ACL enforcement. A rule can restrict access to entities matching specific path patterns and scope expressions.


    Import Configuration

    Controls the worm import command behavior for inferring schema from existing data.

    {
      "import": {
        "ai": true,
        "prompt": "import.prompt.md"
      }
    }
    
    FieldTypeDescription
    aibooleanUse AI (OpenAI) for schema inference
    promptstringPath to the prompt file used for AI import

    Generated Directory

    The generatedDir field specifies where codegen output (TypeScript interfaces, Zod schemas) is written.

    {
      "generatedDir": ".worm/generated"
    }
    

    Running worm codegen generates typed interfaces and validation schemas from the model definitions:

    // .worm/generated/models.ts
    export interface Customer {
      id: string;
      name: string;
      email: string;
      company?: string;
      status: "active" | "inactive" | "churned";
      tags?: string[];
      createdAt: string;
      updatedAt: string;
    }
    

    Complete Example

    {
      "schemaVersion": "1.0",
      "sourceOfTruth": "local",
      "symbols": {
        "namespace": "#",
        "collection": "@",
        "dynamic": "()",
        "requiredFile": "[]"
      },
      "dynamicTypes": {
        "uuid": { "regex": "^[0-9a-fA-F-]{36}$" },
        "evm": { "regex": "^0x[a-fA-F0-9]{40}$" }
      },
      "operators": {
        "auto": { "strategy": "uuid" },
        "seq": { "strategy": "increment", "startAt": 1, "step": 1 }
      },
      "storage": {
        "layout": "root"
      },
      "paths": [
        "#org/@customers/(id:uuid)/[profile].json",
        "#org/@invoices/(id:uuid)/[data].json",
        "#org/@settings/[config].json"
      ],
      "models": {
        "Customer": {
          "path": "#org/@customers/(id:uuid)",
          "idType": "uuid",
          "fields": {
            "name": { "type": "string", "required": true },
            "email": { "type": "string", "required": true },
            "status": {
              "type": "string",
              "enum": ["active", "inactive", "churned"],
              "default": "active"
            },
            "tags": { "type": "string[]" },
            "createdAt": { "type": "datetime", "auto": true },
            "updatedAt": { "type": "datetime", "auto": true }
          },
          "file": "[profile].json",
          "mode": "readwrite",
          "oplog": true,
          "softDelete": true,
          "snapshots": { "enabled": true, "every": 10 }
        },
        "Invoice": {
          "path": "#org/@invoices/(id:uuid)",
          "idType": "uuid",
          "fields": {
            "customerId": { "type": "string", "required": true, "ref": "Customer" },
            "amount": { "type": "number", "required": true },
            "currency": { "type": "string", "default": "USD" },
            "status": {
              "type": "string",
              "enum": ["draft", "sent", "paid", "void"],
              "default": "draft"
            },
            "lineItems": { "type": "object[]" },
            "issuedAt": { "type": "datetime" },
            "paidAt": { "type": "datetime" }
          },
          "file": "[data].json",
          "mode": "readwrite",
          "oplog": true,
          "softDelete": true
        },
        "OrgSettings": {
          "path": "#org/@settings",
          "singleton": true,
          "fields": {
            "orgName": { "type": "string", "required": true },
            "plan": { "type": "string", "enum": ["free", "pro", "enterprise"] },
            "features": { "type": "object" }
          },
          "file": "[config].json",
          "mode": "readwrite",
          "oplog": false,
          "softDelete": false
        }
      },
      "views": {
        "ActiveCustomers": {
          "model": "Customer",
          "filter": { "status": "active" },
          "sort": { "field": "createdAt", "order": "desc" },
          "description": "All active customers, newest first"
        }
      },
      "rules": {
        "owner-scope": {
          "applyTo": "#org/@customers/(id:uuid)",
          "scope": "entity.createdBy === principal.id"
        }
      },
      "import": { "ai": true, "prompt": "import.prompt.md" },
      "generatedDir": ".worm/generated"
    }