---
title: Turn a syllabus into a course of lesson videos
description: Turn a course syllabus into a set of lesson videos that share one look, one voice and one template, made lesson by lesson from a shared plan.
---
Turn a syllabus into a video course: many lesson videos, e-learning modules, a course series with one look. Your agent keeps the syllabus as a brief in the project, builds one lesson as the template, then copies it for each lesson with new titles, new narration and new visuals. Every lesson stays an editable timeline.

Use invideo for this when you want every lesson to match, and the plan, the template and every lesson in one project that you and your agent both work from.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it this prompt.

```text
Make a video course in invideo from syllabus.md. Save the syllabus as a
brief. Build lesson 1 first as the template and show it to me. After my
yes, make the other lessons from it, a few at a time, and mark each one
done in the brief.
```

In a chat app, you paste the syllabus and drag in slides or footage. In a terminal, the agent reads the syllabus and the lesson folders.

## What you need

The syllabus drives everything.

- The syllabus: lesson titles, learning goals, and a script or notes per lesson.
- Material per lesson: slides, screen recordings, footage, or permission for stock and text slides.
- One voice for the whole course.
- The look: brand colors, fonts, an intro and an outro.

## Steps

The template lesson is the step to get right. Every later lesson copies it.

<Steps>
<Step title="Save the syllabus as a brief">
The agent calls `new_brief` with the course name and a one-line description. Then it adds one note per lesson with `edit`, under headings like `lesson-01`. It sees the brief's URL, which you open in invideo.
</Step>
<Step title="Build the template lesson">
The agent builds lesson 1 on a branch made with `timeline_history`: an intro, the title with `add_text`, the narration, the visuals, captions and an outro. It voices the narration as the voice step below shows, and saves the model and the `voice_id` in the brief. It sees lesson 1's timeline URL, and sends it to you.
</Step>
<Step title="Approve the template">
You watch lesson 1 in the editor, and the agent makes your changes before it copies anything. It sees your yes.
</Step>
<Step title="Copy the template per lesson">
For each lesson, the agent calls `edit_timeline` with `duplicate_timeline`, named for the lesson. Each copy shares nothing with the template. It sees the new timeline's id.
</Step>
<Step title="Voice each lesson">
1. The agent runs `find_models` with "course narration voice" once, picks one, and reads its inputs with `get_model`. A good pick is `seed_tts_2_0`, with a voice from `seed_tts_2_0_voices`. Your agent can search for others with `find_models`. Every lesson uses the model and `voice_id` saved in the brief.
2. It calls `generate` with the lesson's script as `prompt`, the `voice_id` and `dry_run: true`, and tells you the price.
3. For a price of 1 credit or more it waits for your yes. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key` like `course-voice-02`. It gets a thread URL and, when the result lands, a sequence URL. It reads that URL with `read` and never calls `generate` again to check.
</Step>
<Step title="Fill in each lesson">
The agent sends one `edit_timeline` call on the copy: `set_text` for the title, `place_media` mode `replace` for the visuals and the new narration, and `trim_clip` to fit the cut. It sees a new `state_token` per lesson.
</Step>
<Step title="Check, export and mark each lesson">
The agent calls `capture` and `check_timeline` on the lesson, then `export` with its `timeline_id` and an `idempotency_key` like `course-lesson-02`. Then it adds the timeline and export URLs to the lesson's note with `edit`. It sees an export card with status `completed`, and the brief shows the lesson as done.
</Step>
</Steps>

Run it in parts: a few lessons per session, and check them before the next batch. A new session reads the brief and goes on from there.

The terminal version. `invideo context edit` changes part of the brief:

```bash
invideo edit show <branch-url> --json
invideo edit change <branch-url> --timeline T1 --token <state_token> \
  --operations @copy-lesson-02.json
invideo gen models <project-url> --query "course narration voice"
invideo gen model <project-url> --model seed_tts_2_0
invideo gen run <page-url> --model seed_tts_2_0 --dry-run \
  -i prompt=@lesson-02.txt -i voice_id=<voice-id>
invideo gen run <page-url> --model seed_tts_2_0 \
  --max-credits <price> --idempotency-key course-voice-02 \
  -i prompt=@lesson-02.txt -i voice_id=<voice-id>
invideo status <thread-url> --wait
invideo notebook show <thread-url>
invideo edit show <branch-url> --timeline T2 --json
invideo edit change <branch-url> --timeline T2 --token <state_token> \
  --operations @fill-lesson-02.json
invideo edit capture <branch-url> --timeline T2 --at 2,30,90 \
  --out ./frames
invideo edit check <branch-url>
invideo edit export <branch-url> --format video --quality 1080 \
  --timeline T2 --idempotency-key course-lesson-02 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./lessons/lesson-02
invideo context edit <brief-url> --old "Lifting safely. todo." \
  --new "Lifting safely. done."
```

Where each value comes from:

- `<branch-url>` is the template's branch, the `.branch_url` that `invideo branch new <edit-url>` returned when lesson 1 was built.
- `<state_token>` is the `state_token` from `invideo edit show <branch-url>`. Each change makes the old token stale, so the agent reads the branch again before the next change.
- `T2` is the copy's timeline id, from `invideo edit show` after the copy.
- `<voice-id>` is the course voice saved in the brief, a `seed_tts_2_0_voices` id.
- `<project-url>` is the course project, from `invideo project new`. `<page-url>` is a notebook page of the project, listed by `invideo notebook show <project-url>`.
- `<price>` is the dry run's `.estimated_credits`. `<thread-url>` is the `url` the paid `gen run` returns, and `notebook show` on it lists the voice's sequence URL.
- `<card-url>` is `.sequences[0]` of the export answer. `invideo status` waits but saves nothing. `invideo notebook show` saves the video as `./lessons/lesson-02/export.mp4`, and the agent renames it to `lesson-02`. The `--file-name` export option does not name the saved file.
- `<brief-url>` is the brief's URL from `new_brief` or `invideo context new-brief`.

The brief, as `read` shows it, part way through. `<edit-url>` and `<export-url>` are each lesson's timeline URL and export URL, which the agent writes in.

```text
# Safety basics course
> Short lessons for new warehouse staff.
> status: in progress

## lesson-01
Fire exits. done. <edit-url> <export-url>

## lesson-02
Lifting safely. done. <edit-url> <export-url>

## lesson-03
Forklift zones. todo.
```

The copy and the fill for one lesson. Each file is the bare list of ops that `--operations` takes. The file behind `@copy-lesson-02.json`:

```json
[
  { "op": "duplicate_timeline", "timeline": "T1",
    "name": "Lesson 2: Lifting safely" }
]
```

The file behind `@fill-lesson-02.json`. `c40` is the title clip's id on `T2`, from `invideo edit show <branch-url> --timeline T2`:

```json
[
  { "op": "set_text", "clip": "c40", "text": "Lesson 2: Lifting safely" }
]
```

## Cost and time

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything.

- Costs credits: the narration per lesson, transcripts for captions, stock clips, and any generated visuals.
- Free: the brief, the template, every copy and edit, `capture` and `export`.

The template lesson takes under an hour. Each later lesson takes a few minutes of agent time plus the voice. See [Credits](/account/credits) for prices.

## If something goes wrong

Most problems come from long runs and the wrong timeline.

| Symptom | Fix |
| --- | --- |
| `get_model` or `generate` refuses the model as not found | Models retire. Run `find_models` with the job in words, use the best match, and tell the person which model you used. |
| `generate` refuses the voice: "voice_ids are model-specific" | The voice comes from another model's library. Use a `seed_tts_2_0_voices` id with `seed_tts_2_0`. |
| `invideo status --wait` ends and the folder is empty | `status` does not download. Run `invideo notebook show <card-url> --out <dir>`. |
| A lesson changed the template | The ops used the template's ids. Read the copy with `get_timeline` and use its ids. |
| An export shows the wrong lesson | Pass that lesson's `timeline_id` in `export`. |
| A new session starts over | Read the brief first. It lists the lessons that are done. |
| `edit` on the brief is refused | `old_text` must be in it once, as `read` shows it. Read it again. |
| Two exports for one lesson | Pass an `idempotency_key` per lesson. A retry then finds the first export. |
| CLI exit 5 | Credits ran out. Stop the batch, tell the person, and note where you stopped in the brief. |
| Avoid: make every lesson before the template is approved | Instead: get a yes on lesson 1 first. |

## Prompts to try

Each prompt is a real variation of this job.

```text
Add a new lesson to the course from the notes below, from the same template,
and add it to the brief.
```

```text
Change the intro in every lesson to the new logo. Start with lesson 1 and
show me before you do the rest.
```

```text
Make a short trailer for the course from the best moments of each
lesson.
```

## When to use something else

invideo makes the lesson videos. Packaging them as SCORM, quizzes and learner tracking happen in your LMS or an authoring tool such as Articulate Rise or iSpring. Upload the MP4s and caption files there.

## Related

- [Turn slides into a narrated video, one deck or hundreds](/how-to/training/slides-to-narrated-video)
- [Voice a script or narrate a course](/how-to/training/voice-a-script-or-narrate-a-course)
- [Make an SRT captions file for an LMS](/how-to/training/srt-for-an-lms)
- [Turn a CSV into many videos with a script](/how-to/developers/csv-to-videos)
- [Update one line and re-render, keep the rest](/how-to/training/update-one-line)