OpenMAIC JSON Schema Artifacts for Non-TypeScript Consumers: Complete Guide

The @openmaic/dsl package provides three canonical JSON Schema files—stage.schema.json, scene.schema.json, and action.schema.json—that enable any runtime to validate MAIC documents without TypeScript dependencies.

The OpenMAIC DSL (Domain-Specific Language) is designed as a cross-platform slide-contract format for interactive educational content. While the source of truth lives in TypeScript, the project ships language-neutral JSON Schema artifacts that let Python, Go, JavaScript, or any other runtime validate MAIC documents against the exact same contract. This article examines the three schema files, their generation pipeline, and practical validation patterns for non-TS consumers.

The Three Core JSON Schema Artifacts

The @openmaic/dsl package exports three interrelated schemas under the schema/ directory. Each maps to a foundational type in the MAIC data model.

stage.schema.json: Top-Level Lesson Container

stage.schema.json describes the root Stage object—the lesson skeleton that aggregates all content.

  • Contains: Lesson metadata, whiteboard list, video manifest, scene references, and global settings
  • Generated from: The Stage TypeScript interface via gen-schema.mjs (Stage: 'stage.schema.json')
  • Source: /packages/@openmaic/dsl/scripts/gen-schema.mjs lines 16–18

Non-TS consumers import it directly:

import stageSchema from '@openmaic/dsl/schema/stage.schema.json' with { type: 'json' };

This pattern appears in /packages/@openmaic/dsl/README.md lines 95–97, which documents the standard import syntax for JSON modules.

scene.schema.json: Canvas and Action Container

scene.schema.json defines the Scene object—a temporal canvas that groups slides with synchronized whiteboard actions.

  • Contains: Slide array, background configuration, whiteboard action timeline, and the generic Action union reference
  • Generated from: The SerializedScene interface via the same build script (SerializedScene: 'scene.schema.json')

The schema captures the complete serialized form of a scene, including all playback-relevant state.

action.schema.json: Playback Verb Taxonomy

action.schema.json enumerates the Action union—every interactive verb the MAIC runtime understands.

  • Contains: Discriminated union of all actions (spotlight, laser pointer, speech synthesis, widget interactions, pen strokes, etc.) with their required fields and @default annotations
  • Generated from: The Action type definition (Action: 'action.schema.json')

This schema uses JSON Schema's oneOf or discriminator patterns to enforce that each action object contains the correct discriminator field (type) and shape.

Schema Generation Pipeline

The schemas are not hand-authored—they are generated at build time from the authoritative TypeScript sources. This guarantees zero drift between the TS types and the JSON Schema contract.

Build-Time Generation with ts-json-schema-generator

In /packages/@openmaic/dsl/scripts/gen-schema.mjs, the generation logic maps type names to output filenames:

// From gen-schema.mjs lines 16-18
const SCHEMA_MAP = {
  Stage: 'stage.schema.json',
  SerializedScene: 'scene.schema.json',
  Action: 'action.schema.json'
};

The script uses ts-json-schema-generator to:

  1. Parse the TypeScript AST in src/*.ts
  2. Extract JSDoc annotations (including @default values)
  3. Emit strict JSON Schema v7+ files with required arrays, additionalProperties constraints, and discriminant mappings

Package Export Configuration

The package.json in /packages/@openmaic/dsl/ declares explicit export maps for the schema files:

{
  "exports": {
    "./schema/*": "./dist/schema/*"
  }
}

This allows consumers to use the clean import paths shown above rather than deep-linking into node_modules.

Zero-Runtime-Dependency Validation

The schemas contain no runtime dependencies—they are pure JSON data files. Any standards-compliant validator can consume them.

JavaScript/Node.js Validation with Ajv

import Ajv from 'ajv';
import stageSchema from '@openmaic/dsl/schema/stage.schema.json' with { type: 'json' };
import sceneSchema from '@openmaic/dsl/schema/scene.schema.json' with { type: 'json' };
import actionSchema from '@openmaic/dsl/schema/action.schema.json' with { type: 'json' };

const ajv = new Ajv({ allErrors: true, strict: false });

const validateStage = ajv.compile(stageSchema);
const validateScene = ajv.compile(sceneSchema);
const validateAction = ajv.compile(actionSchema);

function validateMAIC(doc) {
  if (!validateStage(doc)) {
    console.error('Stage validation failed:', validateStage.errors);
    return false;
  }
  
  if (!validateScene(doc.scene)) {
    console.error('Scene validation failed:', validateScene.errors);
    return false;
  }
  
  for (const action of doc.scene.actions ?? []) {
    if (!validateAction(action)) {
      console.error('Action validation failed:', validateAction.errors);
      return false;
    }
  }
  
  return true;
}

Python Validation with jsonschema

import json
import jsonschema

# Load schemas from package or copy them into your project

with open('stage.schema.json') as f:
    stage_schema = json.load(f)
with open('scene.schema.json') as f:
    scene_schema = json.load(f)
with open('action.schema.json') as f:
    action_schema = json.load(f)

def validate_maic_document(doc: dict) -> None:
    """
    Validates a MAIC document against all three layers.
    Raises jsonschema.ValidationError on first failure.
    """
    # Validate root structure

    jsonschema.validate(instance=doc, schema=stage_schema)
    
    # Validate nested scene

    jsonschema.validate(instance=doc.get('scene', {}), schema=scene_schema)
    
    # Validate each action in the timeline

    for action in doc.get('scene', {}).get('actions', []):
        jsonschema.validate(instance=action, schema=action_schema)
    
    print("Document is valid MAIC")

Cross-Language Contract Guarantees

The JSON Schema artifacts serve critical functions for polyglot MAIC implementations.

Exact Shape Preservation

The schemas capture:

  • Required fields via required arrays
  • Discriminated unions via oneOf with propertyName discriminators
  • Default values from JSDoc @default annotations
  • String literal unions from TypeScript literal types
  • Nested object constraints with additionalProperties: false where appropriate

Version Stability

Each schema release corresponds to the DSL_VERSION constant defined in the source. When the TypeScript model changes, the build pipeline regenerates all three files atomically. This ensures that:

  • Schema versions never lag behind the runtime implementation
  • Non-TS consumers can pin to exact schema versions via npm semver
  • Breaking changes in the contract trigger major version bumps in the package

Alternative: In-Process Validators

For Node.js consumers who prefer direct function calls over schema compilation, /packages/@openmaic/dsl/src/validate.ts exports pre-compiled validators that mirror the schema logic. These use the same underlying types but skip the JSON Schema indirection—useful when bundle size matters less than validation speed.

Summary

  • Three canonical schemas: stage.schema.json, scene.schema.json, and action.schema.json provide complete coverage of the MAIC data model
  • Build-time generation: gen-schema.mjs in the dsl package produces these files from TypeScript sources using ts-json-schema-generator
  • Zero-dependency consumption: Pure JSON files work with any validator—Ajv, Python's jsonschema, Go's gojsonschema, etc.
  • Version-locked contracts: Schemas regenerate automatically with each build, maintaining parity with the DSL_VERSION
  • Flexible import paths: Package exports in package.json enable clean imports via @openmaic/dsl/schema/*.schema.json

Frequently Asked Questions

How do I import OpenMAIC schemas in a CommonJS project?

Use dynamic import or copy the schema files to your project. The package only ships ESM exports. For CommonJS, install the package and reference the files directly from node_modules/@openmaic/dsl/dist/schema/, or use fs.readFileSync to load the JSON. The schemas themselves are valid JSON and impose no module system requirements.

Can I use these schemas with OpenAPI or AsyncAPI specifications?

Yes. The JSON Schema dialect (draft-07 or later) is compatible with OpenAPI 3.x schema objects. You can reference the schema files via $ref in OpenAPI components, or extract sub-schemas for specific action types. The action.schema.json in particular provides a complete union definition suitable for API request/response validation.

What happens if I validate with an outdated schema version?

Validation will reject documents that use newer fields or action types introduced in later DSL versions. The schemas enforce additionalProperties: false on key objects, so unrecognized properties trigger validation errors. Always match your schema version to the DSL_VERSION declared in the documents you are validating—this field is available in the Stage header.

Are the schemas sufficient for runtime type coercion?

No. JSON Schema validates structure, not semantics. The schemas ensure that a spotlight action has the required targetId string, but they do not verify that the ID points to an existing element in the scene graph. For full semantic validation, use the TypeScript runtime in /packages/@openmaic/dsl/src/validate.ts or implement equivalent logic in your target language.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →