Creating Courses
course.yml Reference
The top-level course.yml file defines course metadata and references child content by path. The CLI recognizes the fields below; unknown YAML keys are ignored by its YAML decoder.
Full Example
slug: "kubernetes-fundamentals"
title: "Kubernetes Fundamentals"
description: "Learn the core concepts of Kubernetes container orchestration"
category: "DevOps"
difficulty: "intermediate" # beginner | intermediate | advanced
estimatedTime: 180 # Optional seed; computed from loaded content when available
instructors:
- "Jane Doe"
instructorEmails:
- "[email protected]"
owner: "pov-demo"
teaser: "Master Kubernetes fundamentals through hands-on exercises"
icon: "kubernetes"
tags:
- "kubernetes"
- "containers"
- "devops"
prerequisites:
- "Basic understanding of containers and Docker"
- "Command line familiarity"
sections:
- id: "introduction"
title: "Introduction to Kubernetes"
description: "Understanding the fundamentals"
order: 1
contentItems:
- path: "sections/01-introduction/01-what-is-kubernetes"
order: 1
- path: "sections/01-introduction/02-kubernetes-quiz-1"
order: 2
- id: "core-concepts"
title: "Core Kubernetes Concepts"
order: 2
contentItems:
- path: "sections/02-core-concepts/01-pods-and-containers"
order: 1
accessTier: "free"
freePreview: false
comingSoon: false
isBeta: falseThis example contains only fields that the current pov push-course request preserves. It intentionally omits CLI-bundle-only metadata.
Required Fields
| Field | Type | Description |
|---|---|---|
slug | string | Required non-empty identifier. The CLI does not enforce uniqueness or a URL-safe format. |
title | string | Display name shown to learners. |
category | string | Course category. The validator requires a non-empty value. |
difficulty | string | beginner, intermediate, or advanced (lowercase, exact). |
sections | array | At least one section is required; each must have a title and at least one loadable content item. |
CLI Bundle Fields and Current Push
The CLI sends the bundle as JSON, but the current course API stores only its matching request fields. “Persisted” below means the current pov push-course path retains it.
| Field | Type | Description |
|---|---|---|
description, teaser, icon, subcategory, owner, ownerEmail | string | Accepted without a validator requirement and persisted by the current push API. |
tags, prerequisites, instructors, instructorEmails | string[] | Accepted without a validator requirement and persisted by the current push API. |
accessTier, freePreview, comingSoon, isBeta | mixed | Accepted without a validator requirement and persisted by the current push API. |
estimatedTime | number | Content-derived time replaces the initial value when positive; the resulting value is persisted by the current push API. |
image | string | Accepted into the CLI bundle as JSON image, but the current API accepts imageUrl instead. The current push path discards image. |
learningObjectives, skillsGained, structuredPrerequisites, tier, ribbon | mixed | Accepted into the CLI bundle, but the current course API has no matching create-request field, so the current push path discards them. |
Computed and Ignored Fields
| Field | Type | Description |
|---|---|---|
totalLessons, totalQuizzes, totalLabs | computed | Created from loaded child content. The current course API does not store these bundle counters. |
totalContent | unsupported | A runtime model field, but the modular course loader does not read or populate it. |
published, featured, createdAt, updatedAt, version | ignored | The modular loader accepts these keys but does not copy them into the course bundle; do not rely on them for publishing or versioning. |
Sections Structure
Each entry in sections has:
| Field | Description |
|---|---|
id | Accepted identifier; no uniqueness or format rule is enforced here. |
title | Required non-empty display name. |
description, isOptional | Optional section metadata. |
order | Accepted integer passed through to the section; no sequencing rule is enforced. |
contentItems[].path | A path to a directory containing lesson.yml, quiz.yml, or lab.yml; loading fails if none exists. |
contentItems[].order | Accepted integer passed to the loaded item; no sequencing rule is enforced. |
Do Not Use These Loader Keys
| Field | Status | Description |
|---|---|---|
published, featured | ignored | Accepted by the modular YAML struct, then discarded when the course bundle is created. |
createdAt, updatedAt, version | ignored | Accepted by the modular YAML struct, then discarded when the course bundle is created. |
