# Courses — markdown files

A course is **course.md** plus the **lessons** it lists: people and agents write them as files,
the team server publishes the course, and subscribers take it in the **Academy** (lessons in
order, video on top, progress kept). A lesson is a workspace's own folder, so one lesson can be
in several courses.

```
.cowork/courses/onboarding/  the folder name is the course's store name (lowercase, digits, -)
  course.md                  front matter (its lessons: line) + the description people read before subscribing
  assets.json                optional, like any published folder: {"item": {"tags": ["sales"]}}
.cowork/lessons/
  welcome/                   a lesson: the folder name is its id ("welcome")
    lesson.md                front matter + the lesson in markdown
    home.png                 a picture it shows: ![The Home screen](home.png)
  first-steps/
    lesson.md
    shots/editor.webp        subfolders are fine: ![The editor](shots/editor.webp)
```

## course.md

```markdown
---
title: Sales Onboarding
level: Beginner
lessons: welcome, first-steps
---
Everything a new rep needs in their first week — the tools, the pipeline, the first call.
```

- `title` **required**; `level` = `Beginner` | `Intermediate` | `Advanced` (optional).
- `lessons` — the lesson ids it teaches, comma-separated, **in order**: the line is the course.
  Each id is a folder in `.cowork/lessons/`. Add a lesson to a course by adding its id; another
  course may list the same one.
- The body is the course's description (markdown, ≤ 2000 characters) — the listing shows it.

## lesson.md

```markdown
---
title: Your first call
minutes: 8
video: https://www.youtube.com/watch?v=M7lc1UVf-VE
---
What to say in the first two minutes, and what to log after.

## Before the call

- Read the account notes.

![The account page](account.png)

## After the call

Log it in the CRM. See [the call guide](https://example.com/guide).
```

- `title` **required**; `minutes` a whole number (optional); `video` optional — a **YouTube,
  Vimeo or Loom** link, played above the lesson.
- The body is the lesson. `##` headings are its sections; lists, tables, `code`, quotes all render.
- Front matter is plain `key: value` lines between `---` lines (quotes optional).

## Rules (publish checks every one and names the file)

- Every id on the `lessons:` line is a folder `.cowork/lessons/<id>/` holding `lesson.md`; ids are
  lowercase letters, digits and `-`, unique in the line. Reordering the line reorders the course
  without losing anyone's progress; renaming a lesson's folder makes it a new lesson (fix the line
  of every course that lists it).
- Published, the course is one folder: each lesson travels as `NN-<id>/` beside course.md (NN = its
  place). A course folder may also hold its own `NN-<id>/` lesson folders — then the line must list
  each of them too.
- Pictures are `.png .jpg .jpeg .gif .webp .svg` files **in the lesson's own folder** (or its
  subfolders), referenced relatively — or an `https://` image. Never `../`, never another lesson's.
- Links go to `https://` pages or `#headings` — a relative link can't open from the Academy.
- At most 40 lessons; the whole course ≤ 25 MB (keep video out of it — link it).
- No scripts, no iframes: the Academy sanitizes the markdown.

## Make, check, publish

```bash
# Create → Courses → New course in the IDE writes .cowork/courses/<name>/course.md and a first lesson,
# .cowork/lessons/<name>-welcome/ — or write the files yourself.
cowork publish .cowork/courses/onboarding --dry-run          # checks it: prints the outline, or the problem
cowork publish .cowork/courses/onboarding --team-server acme # publish (admins of that team server)
cowork team-server store acme                                 # it is listed as a course
```

In the IDE: **Manage Workspace → Components → Courses & Lessons** lists both; a course's page adds
and removes its lessons, a lesson's page puts it in courses or deletes it (from every course).
**Publish… → A course** publishes one. Publishing again makes the next version; subscribers get it
within a minute. A course is **subscribed**, never installed: on the team server's page →
**Subscribe** → it appears in the Academy.

If a course was unpublished and is published again under the same name, it comes back as the
same course: subscriptions and progress resume.
