OpenMAIC DSL Contract: The 8 Core Primitives Explained

The OpenMAIC DSL contract defines eight core primitives—Stage, SceneCore, Action, Slide, SlideContent, QuizContent, AssetMeta/BinaryBlob, and RuntimeSession—that form the stage-first data model used by the entire platform.

The OpenMAIC DSL contract is the foundational TypeScript-based specification that powers the OpenMAIC learning platform. Exported from the @openmaic/dsl package, this contract serves as the single source of truth for the editor, runtime, storage layer, and all APIs. Every component in the system builds upon a small set of carefully designed primitives.

Understanding the Stage-First Architecture

OpenMAIC adopts a stage-first design philosophy. A Stage represents the complete learning unit—the root container that holds everything else. This approach ensures that serialization, versioning, and cross-platform compatibility remain straightforward regardless of how complex the interactive content becomes.

The primitives follow a clear containment hierarchy:

  • Stage → contains SceneCore instances
  • SceneCore → bundles Action objects and binds to a Slide
  • Slide → renders SlideContent elements
  • RuntimeSession → tracks mutable state during user interaction

The 8 Core Primitives in OpenMAIC

Stage

The Stage primitive is the root container defined in src/schema-roots.ts. It stores metadata (title, description, tags), an array of scenes, and optional runtime configuration including voice settings, agent definitions, and video manifests.

// From src/schema-roots.ts
interface Stage {
  id: string;
  title: string;
  description?: string;
  tags?: string[];
  scenes: SceneCore[];
  voice?: VoiceConfig;
  agents?: AgentConfig[];
  videoManifest?: VideoManifest;
  version: number;
}

SceneCore<TAction = Action>

SceneCore is the basic unit of a stage, also defined in src/schema-roots.ts. It uses a generic parameter to carry the exact action type, enabling type-safe extensions of the DSL. Each scene groups actions that apply to a single slide.

// From src/schema-roots.ts
interface SceneCore<TAction = Action> {
  id: string;
  slide: Slide;
  actions: TAction[];
  duration?: number;
  transition?: TransitionConfig;
}

Action and Concrete Sub-types

Action primitives represent the atomic operations driving interactivity. Defined in src/action.ts, the DSL provides a rich hierarchy including:

  • SpotlightAction — highlight specific elements
  • LaserAction — pointer annotations
  • SpeechAction — voice narration
  • WbDrawShapeAction — whiteboard drawing
  • PlayVideoAction — media playback
  • DiscussionAction — collaborative prompts
  • WidgetSetStateAction — interactive component updates

Each action carries the precise data needed for client-side rendering and execution.

// From src/action.ts
interface SpotlightAction {
  type: 'spotlight';
  target: ElementTarget;
  duration: number;
  intensity?: number;
}

Slide

The Slide primitive in src/slide.ts defines the visual representation of a scene. It contains background properties, drawable elements, and optional theming data.

// From src/slide.ts
interface Slide {
  background: BackgroundConfig;
  elements: SlideContent[];
  theme?: ThemeConfig;
  layout?: LayoutConfig;
}

SlideContent

SlideContent is the union type of all drawable elements, defined in src/stage.ts. The DSL enumerates every possible visual component:

  • PPTImageElement — raster images
  • PPTShapeElement — vector shapes
  • PPTCodeElement — syntax-highlighted code blocks
  • PPTVideoElement — embedded video
  • PPTAudioElement — audio embeds
  • PPTTextElement — rich text
  • PPTIframeElement — external web content

QuizContent

QuizContent is a specialized slide type for assessments, also defined in src/stage.ts. It extends the base slide structure with question arrays, scoring logic, and feedback mechanisms.

// From src/stage.ts
interface QuizContent extends Slide {
  type: 'quiz';
  questions: Question[];
  shuffleOptions?: boolean;
  allowRetry?: boolean;
  feedbackMode: 'immediate' | 'deferred';
}

AssetMeta and BinaryBlob

The AssetMeta and BinaryBlob primitives in src/storage.ts define the minimal storage contract for external resources. The DSL specifies only three required operations—put, resolve, and remove—leaving concrete implementations to the storage package.

// From src/storage.ts
interface AssetMeta {
  id: string;
  mimeType: string;
  size: number;
  checksum: string;
}

interface BinaryBlob {
  data: ArrayBuffer;
  meta: AssetMeta;
}

interface StorageContract {
  put(blob: BinaryBlob): Promise<AssetMeta>;
  resolve(id: string): Promise<BinaryBlob>;
  remove(id: string): Promise<void>;
}

RuntimeSession

RuntimeSession in src/runtime.ts is the mutable runtime counterpart to the immutable Stage. It adds version tracking and maintains the client's working state including current position, playback status, and user interactions.

// From src/runtime.ts
interface RuntimeSession extends RuntimeVersioned {
  runtimeDslVersion: string;
  stage: Stage;
  state: RuntimeState;
}

interface RuntimeState {
  currentScene: string;
  playback: {
    paused: boolean;
    speed: number;
    position?: number;
  };
  userState?: Record<string, unknown>;
}

Working with the Primitives: Practical Example

The following example demonstrates how the core primitives compose to create a complete learning unit:

import { Stage, SceneCore, Action, Slide, RuntimeSession } from '@openmaic/dsl';

// Define a slide with visual content
const slide: Slide = {
  background: { color: '#f5f5f5' },
  elements: [
    {
      type: 'shape',
      id: 'shape-1',
      shape: 'circle',
      x: 0.5,
      y: 0.5,
      width: 0.2,
      height: 0.2,
      style: { fill: '#e74c3c', stroke: '#c0392b' },
    },
  ],
};

// Create an action that spotlights the element
const spotlightAction: Action = {
  type: 'spotlight',
  target: { kind: 'element', id: 'shape-1' },
  duration: 3.5,
  intensity: 0.8,
};

// Bundle into a scene
const scene: SceneCore = {
  id: 'intro-scene',
  slide,
  actions: [spotlightAction],
  duration: 10,
};

// Assemble the complete stage
const demoStage: Stage = {
  id: 'circles-intro',
  title: 'Introduction to Geometric Shapes',
  description: 'Interactive exploration of basic shapes',
  scenes: [scene],
  version: 1,
};

// Runtime representation for active session
const activeSession: RuntimeSession = {
  runtimeDslVersion: '1.0.0',
  stage: demoStage,
  state: {
    currentScene: 'intro-scene',
    playback: { paused: false, speed: 1 },
  },
};

Key Source Files in the OpenMAIC DSL Contract

File Purpose Location
src/schema-roots.ts Central definitions of Stage, SceneCore, and related root types packages/@openmaic/dsl/src/schema-roots.ts
src/stage.ts Detailed Stage interfaces, slide types, and quiz structures packages/@openmaic/dsl/src/stage.ts
src/slides.ts All slide element definitions packages/@openmaic/dsl/src/slides.ts
src/action.ts Action hierarchy and concrete implementations packages/@openmaic/dsl/src/action.ts
src/runtime.ts RuntimeSession and mutable state contracts packages/@openmaic/dsl/src/runtime.ts
src/storage.ts AssetMeta, BinaryBlob, and storage contracts packages/@openmaic/dsl/src/storage.ts

Summary

The OpenMAIC DSL contract establishes a rigorous, type-safe foundation for interactive learning content through eight core primitives:

  • Stage — the root learning unit container
  • SceneCore — the generic scene bundling actions and slides
  • Action — atomic interactivity operations with rich sub-types
  • Slide — visual presentation layer
  • SlideContent — union of all drawable element types
  • QuizContent — assessment-specialized slide variant
  • AssetMeta/BinaryBlob — minimal external resource contracts
  • RuntimeSession — mutable runtime state tracking

All higher-level features—including voice design, multi-agent configurations, video manifests, and problem-based learning data—extend these primitives rather than introducing parallel structures. This design ensures consistency across the OpenMAIC editor, runtime engine, storage backends, and API surfaces.

Frequently Asked Questions

What is the OpenMAIC DSL contract used for?

The OpenMAIC DSL contract defines the canonical data model that all platform components use to represent interactive learning content. It enables seamless serialization, version migration, and cross-platform compatibility by providing a single, type-safe specification in TypeScript.

How does SceneCore use generics in the OpenMAIC DSL?

SceneCore<TAction = Action> uses a generic parameter with a default value to allow type-safe extensions. Custom DSL variants can substitute constrained action types while maintaining full IntelliSense and compile-time verification without breaking existing code.

Where are actions defined in the OpenMAIC source code?

All action types reside in src/action.ts within the @openmaic/dsl package. The file exports both the base Action type and concrete implementations like SpotlightAction, LaserAction, and WbDrawShapeAction, each with specific payload schemas.

What distinguishes RuntimeSession from Stage in OpenMAIC?

Stage captures the immutable, authored content of a learning unit, while RuntimeSession tracks the mutable state during active user interaction—including current position, playback settings, and accumulated user responses. The runtime version adds runtimeDslVersion for compatibility checking.

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 →