Course Authoring Guide

Everything you need to create a course compatible with Course Imports — folder structure, metadata format, block types, and content best practices.

Build courses with Claude Code

Download the Claude Code skill to generate complete, spec-compliant courses automatically. Unzip into your .claude/skills/ directory and run /creating-course [topic].

Download Skill

Folder structure

A course is a single folder containing a course.json metadata file and a topics/ directory. Each topic is a numbered subfolder with its own content.json and any referenced files.

my-course/
├── course.json
└── topics/
    ├── 01-introduction/
    │   ├── content.json
    │   ├── intro.md
    │   └── hello.py
    ├── 02-variables-and-types/
    │   ├── content.json
    │   ├── overview.md
    │   ├── example.py
    │   └── diagram.png
    └── 03-functions/
        ├── content.json
        └── explanation.md

course.json

The root metadata file. All fields are required unless noted.

{
  "id": "intro-to-python",
  "title": "Introduction to Python",
  "description": "A beginner-friendly course covering Python fundamentals.",
  "version": "1.0.0",
  "author": "Jane Smith",
  "tags": ["programming", "python", "beginner"],
  "topicOrder": [
    "01-introduction",
    "02-variables-and-types",
    "03-functions"
  ]
}
Field Type Description
idstringUnique identifier (kebab-case)
titlestringDisplay title
descriptionstringShort summary of the course
versionstringSemver version string
authorstringCourse author name
tagsstring[]Keywords for categorisation
topicOrderstring[]Ordered list of topic folder names (must match folders in topics/)

Topics

Each entry in topicOrder must correspond to a subfolder inside topics/.

Prefix folder names with a number for ordering, e.g. 01-introduction. The display title is derived by stripping the numeric prefix and title-casing the remainder.

Each topic folder must contain a content.json file — an ordered JSON array of blocks rendered top-to-bottom.

[
  { "type": "text", "src": "intro.md" },
  { "type": "code", "language": "python", "src": "hello.py", "label": "hello.py" },
  { "type": "callout", "style": "info", "body": "Python is case-sensitive." },
  { "type": "quiz", "question": "What does print() do?",
    "options": ["Saves a file", "Outputs text", "Creates a variable"],
    "answer": 1, "explanation": "print() outputs text to the console." },
  { "type": "reveal", "label": "ELI5: What is print?",
    "body": "Think of print() like a megaphone." },
  { "type": "image", "src": "diagram.png", "alt": "Memory model diagram" },
  { "type": "checkpoint", "label": "I can write and run a Python script" }
]

Block types

Text

Renders markdown content. Reference an external .md file with src, or provide content inline.

{ "type": "text", "src": "intro.md" }
{ "type": "text", "content": "Welcome to the course. This is **markdown**." }
FieldTypeRequiredDescription
type"text"YesMust be "text"
srcstringNoPath to a .md file relative to the topic folder
contentstringNoInline markdown string (used if src is absent)

One of src or content must be provided.

Code

Displays a syntax-highlighted code block.

{ "type": "code", "language": "python", "src": "hello.py", "label": "hello.py" }
{ "type": "code", "language": "javascript", "content": "console.log('hello')" }
FieldTypeRequiredDescription
type"code"YesMust be "code"
languagestringYesLanguage identifier for syntax highlighting
srcstringNoPath to a source file relative to the topic folder
contentstringNoInline code string (used if src is absent)
labelstringNoDisplay label shown above the code block

One of src or content must be provided.

Quiz

Presents a question with selectable options.

{
  "type": "quiz",
  "question": "What does the print() function do?",
  "options": [
    "Saves a file",
    "Outputs text to the console",
    "Creates a variable"
  ],
  "answer": 1,
  "explanation": "print() writes output to the standard console."
}
FieldTypeRequiredDescription
type"quiz"YesMust be "quiz"
questionstringYesThe question text
optionsstring[]YesList of answer choices
answernumberYesZero-based index of the correct option
explanationstringNoShown after the user answers

Callout

A highlighted box for tips, warnings, or extra info.

{ "type": "callout", "style": "warning", "body": "Do not use eval() in production code." }
FieldTypeRequiredDescription
type"callout"YesMust be "callout"
style"info" | "warning" | "tip"YesVisual style of the callout
bodystringYesMarkdown-formatted callout content

Reveal

A collapsible block that hides content behind a clickable header. Useful for supplementary material.

{
  "type": "reveal",
  "label": "ELI5: What is a variable?",
  "body": "Think of a variable like a labeled box..."
}
FieldTypeRequiredDescription
type"reveal"YesMust be "reveal"
labelstringNoCollapsed header text (defaults to "Reveal")
bodystringYesMarkdown content shown when expanded

Recommended uses: ELI5 explanations, deep dives, common mistakes, and exercises.

Checkpoint

A completion marker rendered as a toggleable button. Place at the end of a topic.

{ "type": "checkpoint", "label": "I can write and call a Python function" }
FieldTypeRequiredDescription
type"checkpoint"YesMust be "checkpoint"
labelstringNoButton text (defaults to "Mark as complete")

Phrase as a self-assessment: "I can..." or "I understand..." statements.

Image

Displays an image with alt text.

{
  "type": "image",
  "src": "diagram.png",
  "alt": "Python variable memory model",
  "caption": "How Python stores variables in memory"
}
FieldTypeRequiredDescription
type"image"YesMust be "image"
srcstringYesPath to image file relative to the topic folder
altstringYesAlt text for accessibility
captionstringNoCaption displayed below the image

Images must be under 10 MB.

Topic completion rules

  • Topics without quizzes or checkpoints are marked complete when first viewed.
  • Topics with quizzes are marked complete only when all quizzes have been answered.
  • Topics with checkpoints are marked complete when all checkpoints have been toggled.
  • Topics with both require all quizzes answered and all checkpoints toggled.

Validation checklist

The app validates courses on load. Use this checklist to catch issues before importing:

  • course.json exists at the root and is valid JSON
  • All required fields are present (id, title, description, version, author, tags, topicOrder)
  • A topics/ directory exists
  • Every entry in topicOrder has a matching folder in topics/
  • Every topic folder contains a valid content.json (a JSON array)
  • Every block in content.json has a type field
  • All src paths point to files that exist within the topic folder (no ../ path traversal)
  • Images are under 10 MB
  • Multiple-choice quizzes have an options array and a valid answer index
  • Text and code blocks provide either src or content

Writing effective content

Recommended topic structure

  1. Overview (15–30 lines) — frame the problem this topic solves, include 3–5 learning objectives
  2. Core content (interleaved text + code, 20–50 lines per file) — one concept per file, weave code into narrative
  3. Inline knowledge checks — 3–5 quizzes placed after each major concept, every quiz needs an explanation
  4. Supplementary depth — at least 2 reveal blocks per topic (ELI5 + deep dive)
  5. Callouts (2–4 per topic) — tips, warnings, and context distributed throughout
  6. Key takeaways — 3–5 bullet recap before the checkpoint
  7. Checkpoint — "I can..." or "I understand..." phrasing

Writing style

  • Write as a knowledgeable colleague at a whiteboard, not a textbook
  • Open every topic with the problem before the solution
  • Use concrete analogies for abstract concepts
  • Use second person ("you"), present tense
  • Vary sentence rhythm — short sentences punch, longer ones connect ideas
  • Never use foo/bar/baz — use realistic names and scenarios
  • Show the "wrong way" before the "right way" where helpful

Ready to create a course?

Download Claude Code Skill