Course Schema

Courses are defined as YAML files with three top-level keys: course, sections, and concepts. The schema is validated with Zod at import time.

Top-level structure

course:
  id: string              # kebab-case, globally unique
  name: string
  description: string
  estimatedHours: number
  version: string         # e.g., "2026.1"
  sourceDocument: string  # official source reference

sections:               # optional, ordered list
  - id: string
    name: string
    description: string
    sectionExam: ...      # optional exam gate

concepts:               # required, array of concept objects
  - id: string
    name: string
    ...

course

Top-level metadata about the course.

FieldTypeDescription
id*stringKebab-case identifier, globally unique (e.g., aws-saa-c03)
name*stringHuman-readable course name
descriptionstringCourse description
estimatedHours*numberEstimated total study hours (must be positive)
version*stringSemantic version string (e.g., "2026.1")
sourceDocumentstringReference to official source (e.g., exam guide, textbook)

sections

Optional ordered list of sections. Concepts reference sections by ID.

FieldTypeDescription
id*stringSection identifier
name*stringSection display name
descriptionstringSection description
sectionExamobjectOptional section exam gate (see below)

sectionExam

Section-end certification checkpoints. Every blueprint concept must belong to the section.

FieldTypeDescription
enabledbooleanWhether the exam is active (default: true)
passingScorenumberScore to pass, 0.0-1.0 (default: 0.75)
timeLimitMinutesnumberOptional time limit in minutes
questionCountnumberTotal questions (default: 10). Must be >= sum of blueprint minQuestions
blueprintarrayArray of { conceptId, minQuestions } — each concept must be in this section
instructionsstringExam instructions shown to learner

concepts

A concept represents one teachable idea that can be tested independently. Too broad and students get stuck. Too narrow and the graph becomes unwieldy.

FieldTypeDescription
id*stringKebab-case identifier, unique within the course
name*stringHuman-readable concept name
sectionstringSection ID this concept belongs to
difficulty*1-101=basic definition, 5=application, 8=complex analysis, 10=multi-step
estimatedMinutes*numberEstimated study time in minutes (positive integer)
tagsstring[]Tags for filtering (e.g., "foundational", "calculation")
sourceRefstringSource reference (e.g., "NFPA 1001-2019 JPR 4.3.1")
prerequisitesstring[]Array of concept IDs that must be mastered first (max 3-4 direct)
encompassingarrayImplicit repetition edges: { concept: id, weight: 0.0-1.0 }
knowledgePointsarrayArray of KP objects (see below). Empty = graph stub

knowledgePoints

Each knowledge point teaches one load-bearing move, distinction, or case. There is no fixed cap on KPs per concept. Fully-authored concepts should have as many KPs as the staircase requires, often around 3-5, with progressive difficulty. Each KP follows: instruction → content → worked example → practice.

FieldTypeDescription
id*stringKP identifier, unique within the concept
instructionstringMarkdown instruction text (or file path ending in .md/.txt/.html)
instructionContentarrayStructured content blocks (image, video, link, callout)
workedExamplestringStep-by-step worked example text
workedExampleContentarrayStructured content blocks for the worked example
problemsarrayArray of problem objects (see below). Need 3+ per KP

Content blocks

Used in instructionContent and workedExampleContent for media and references. The type field determines the variant.

image

Screenshot or diagram

Fields: url, alt, caption?, width?

video

External demo or walkthrough

Fields: url, title, caption?

link

Supporting document or page

Fields: url, title, description?

callout

Highlighted note

Fields: title, body

problems

Practice problems attached to each knowledge point. The adaptive engine needs at least 3 problems per KP. Two consecutive correct answers passes a KP.

FieldTypeDescription
id*stringProblem identifier, globally unique across the course
type*enummultiple_choice | fill_blank | true_false | ordering | matching | scenario
question*stringThe question text
optionsstring[]At least two distinct options for choice, scenario, or ordering problems. Matching uses left|right pairs.
correct*varies by problem typeAnswer contract for the selected type. See the requirements below.
explanationstringShown after answering — should name the likely misconception
difficulty1-5Problem difficulty level (integer 1-5)
  • Multiple choice and scenario: Set a zero-based integer index within the options. For four options, valid answers are 0 through 3.
  • True or false: Set true or false, as a boolean or a string.
  • Fill blank: Set nonempty text, a number, or an object with an answer and optional alternatives.
  • Ordering: List every option text once in the correct order, or supply comma-separated indices that include every option once.
  • Matching: Use left|right option pairs. Map every left label to an offered right label, or provide a full comma-separated index order.

Example course YAML

This excerpt illustrates the schema. It needs complete teaching content and practice variants before publication. Review the source facts and run validation and the review gate before importing a finished course.

aws-saa-c03.yaml
course:
  id: aws-saa-c03
  name: AWS Solutions Architect Associate
  description: Comprehensive prep for the AWS SAA-C03 exam
  estimatedHours: 40
  version: "2026.1"
  sourceDocument: "AWS SAA-C03 Exam Guide"

sections:
  - id: foundations
    name: Cloud Foundations
    description: Core AWS concepts and global infrastructure
  - id: networking
    name: Networking
    description: VPC, subnets, routing, and connectivity

concepts:
  - id: shared-responsibility
    name: AWS Shared Responsibility Model
    section: foundations
    difficulty: 3
    estimatedMinutes: 20
    tags: [foundational, security]
    sourceRef: "SAA-C03 Domain 1"
    prerequisites: []
    knowledgePoints:
      - id: shared-responsibility-kp1
        instruction: |
          AWS uses a shared responsibility model. AWS manages
          security OF the cloud (hardware, networking, facilities).
          You manage security IN the cloud (data, IAM, encryption).
        workedExample: |
          Scenario: A company stores PII in S3. Who is responsible
          for encrypting that data? Answer: The customer — S3
          encryption is the customer's responsibility.
        problems:
          - id: sr-kp1-p1
            type: multiple_choice
            question: "Who is responsible for patching the underlying EC2 hypervisor?"
            options:
              - "The customer"
              - "AWS"
              - "Shared equally"
              - "The VPC owner"
            correct: 1
            explanation: "AWS manages the hypervisor. Customers manage the OS and applications running on EC2."
            difficulty: 2
          - id: sr-kp1-p2
            type: multiple_choice
            question: "A company needs to encrypt S3 objects at rest. Whose responsibility is this?"
            options:
              - "AWS — they manage S3 infrastructure"
              - "The customer — data encryption is their responsibility"
              - "S3 encrypts everything by default, no action needed"
              - "The VPC security group controls this"
            correct: 1
            explanation: "While S3 now encrypts by default with SSE-S3, managing encryption keys and choosing encryption methods is the customer's responsibility."
            difficulty: 3
          - id: sr-kp1-p3
            type: scenario
            question: "Your auditor asks who manages physical security at an AWS data center. What do you tell them?"
            options:
              - "We manage it through security groups"
              - "AWS manages all physical data center security"
              - "It depends on the region"
              - "Physical security is a shared responsibility"
            correct: 1
            explanation: "Physical security is entirely AWS's responsibility — it's security OF the cloud."
            difficulty: 4

  - id: vpc-basics
    name: VPC Fundamentals
    section: networking
    difficulty: 4
    estimatedMinutes: 30
    tags: [networking, foundational]
    sourceRef: "SAA-C03 Domain 2"
    prerequisites:
      - shared-responsibility
    knowledgePoints: []  # stub — needs graspful fill concept

Authoring guidelines

Concept granularity

A concept = one teachable idea that can be tested independently. Good: "Forms of Co-Ownership (Joint Tenancy, Tenancy in Common, TBE)". Too broad: "All of Property Law". Too narrow: "Definition of Joint Tenancy" (make this a KP instead).

Prerequisites

Max 3-4 direct prerequisites per concept (working memory limit). Only list direct prerequisites — transitive ones are inferred. If A→B→C, don't add A→C explicitly.

Knowledge points

Fully-authored concepts should have as many KPs as the staircase requires, often around 3-5. Each KP teaches one load-bearing move. Difficulty should rise one small step at a time — learners should feel like climbing a staircase, not jumping a gap.

Problem quality

  • Multiple choice: 4 options, 1 correct. Distractors should be plausible.
  • Fill blank: Accept reasonable variations (the system normalizes).
  • Ordering: 4-6 steps max. Every step must be necessary.
  • Scenario: Audio description + follow-up. Best for complex application.
  • Explanations should name the likely misconception, not just reveal the answer.

Encompassing weights

  • 1.0: Fully exercises the target as a subskill
  • 0.5-0.7: Substantially exercises the target
  • 0.2-0.4: Partially exercises the target
  • < 0.2: Probably not worth listing

Progress-safe evolution

After a course has active learners, keep course.id, section id, concept id, and KP id stable across revisions. Safe changes: refine instruction, add worked examples, revise problems, add new concepts. Unsafe: renaming slugs in place. Use --archiveMissing when retiring content.

Validation rules

The importer validates the following at import time:

  • No cycles in the prerequisite graph
  • All referenced concept IDs exist
  • Encompassing weights are 0.0-1.0
  • Every authored concept has at least 1 KP
  • Every authored KP has at least 2 problems
  • Section exam blueprint concepts belong to the section
  • Section exam questionCount ≥ sum of blueprint minQuestions

Run graspful validate locally before importing to catch errors early. The review gate runs additional quality checks on top of schema validation.