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].
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 |
|---|---|---|
id | string | Unique identifier (kebab-case) |
title | string | Display title |
description | string | Short summary of the course |
version | string | Semver version string |
author | string | Course author name |
tags | string[] | Keywords for categorisation |
topicOrder | string[] | 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**." }
| Field | Type | Required | Description |
|---|---|---|---|
type | "text" | Yes | Must be "text" |
src | string | No | Path to a .md file relative to the topic folder |
content | string | No | Inline 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')" }
| Field | Type | Required | Description |
|---|---|---|---|
type | "code" | Yes | Must be "code" |
language | string | Yes | Language identifier for syntax highlighting |
src | string | No | Path to a source file relative to the topic folder |
content | string | No | Inline code string (used if src is absent) |
label | string | No | Display 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."
}
| Field | Type | Required | Description |
|---|---|---|---|
type | "quiz" | Yes | Must be "quiz" |
question | string | Yes | The question text |
options | string[] | Yes | List of answer choices |
answer | number | Yes | Zero-based index of the correct option |
explanation | string | No | Shown 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." }
| Field | Type | Required | Description |
|---|---|---|---|
type | "callout" | Yes | Must be "callout" |
style | "info" | "warning" | "tip" | Yes | Visual style of the callout |
body | string | Yes | Markdown-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..."
}
| Field | Type | Required | Description |
|---|---|---|---|
type | "reveal" | Yes | Must be "reveal" |
label | string | No | Collapsed header text (defaults to "Reveal") |
body | string | Yes | Markdown 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" }
| Field | Type | Required | Description |
|---|---|---|---|
type | "checkpoint" | Yes | Must be "checkpoint" |
label | string | No | Button 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"
}
| Field | Type | Required | Description |
|---|---|---|---|
type | "image" | Yes | Must be "image" |
src | string | Yes | Path to image file relative to the topic folder |
alt | string | Yes | Alt text for accessibility |
caption | string | No | Caption 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.jsonexists 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
topicOrderhas a matching folder intopics/ - Every topic folder contains a valid
content.json(a JSON array) - Every block in
content.jsonhas atypefield - All
srcpaths point to files that exist within the topic folder (no../path traversal) - Images are under 10 MB
- Multiple-choice quizzes have an
optionsarray and a validanswerindex - Text and code blocks provide either
srcorcontent
Writing effective content
Recommended topic structure
- Overview (15–30 lines) — frame the problem this topic solves, include 3–5 learning objectives
- Core content (interleaved text + code, 20–50 lines per file) — one concept per file, weave code into narrative
- Inline knowledge checks — 3–5 quizzes placed after each major concept, every quiz needs an explanation
- Supplementary depth — at least 2 reveal blocks per topic (ELI5 + deep dive)
- Callouts (2–4 per topic) — tips, warnings, and context distributed throughout
- Key takeaways — 3–5 bullet recap before the checkpoint
- 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