---
title: Turn release notes or a changelog into a video every week
description: Turn this week's release notes or changelog into a short branded video, built from last week's video as the template.
---
Turn release notes into a video: a changelog video, a "what's new" update, a weekly product update for customers or the team. Your agent reads the notes, writes a short script, voices it, and places your screenshots with on-brand text. From the second week on, it copies last week's timeline and swaps only what changed.

Use invideo for this when the same video repeats every week, so your brand kit and last week's timeline do most of the work and only the news is new.

## Quickest path

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

```text
Make this week's "What's new" video in our invideo project from
CHANGELOG.md, the newest section. Copy last week's timeline. Use the
brand entry in context/brands. Use the screenshots in ./shots, one per
change. Voice a short script. Show me frames before you export.
```

In a chat app, you paste the notes and drag the screenshots in. In a terminal, the agent reads the changelog and the screenshot folder.

## What you need

The first week takes setup. Later weeks need only the news.

- The release notes: a changelog file, a page you paste, or a list.
- One screenshot or short screen recording per change. invideo does not capture pages, so you or your agent's own browser or screenshot tool makes them.
- The brand kit, once: colors, fonts as TTF, OTF, WOFF or WOFF2 files, and the logo.
- The voice, once. The agent keeps the same `voice_id` every week.

## Steps

The first run sets up the brand entry. Every later run starts at the copy step.

<Steps>
<Step title="Write the brand entry, once">
The agent writes a context entry at `…/context/brands/acme.md` with `write`: colors as hex, the font names, where the logo is. It brings the fonts in with `add_media` on the timeline's URL. It sees the entry's URL, and each font's id in what `add_media` returns.
</Step>
<Step title="Read the notes and write the script">
The agent reads the newest release notes and writes one short line per change, with an opening and a closing line. It shows you the script. It sees your yes or your changes.
</Step>
<Step title="Voice it">
1. On the first run, the agent runs `find_models` with "narration voice", picks one, and reads its inputs with `get_model`. A good pick is `elevenlabs_text_to_speech.elevenlabs_tts_v4`, with a voice from `elevenlabs_text_to_speech_voices`. Your agent can search for others with `find_models`. On later runs, it runs `read` on last week's thread for the same model and `voice_id`.
2. It calls `generate` with the script as `prompt`, that `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 `week-44-voice`. 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="Copy last week's timeline">
The agent calls `edit_timeline` with `duplicate_timeline` on last week's timeline, named for this week. The copy shares nothing with the old one. It sees the new timeline's id in what `edit_timeline` returns.
</Step>
<Step title="Swap the news">
The agent brings in the screenshots with `add_media`, then sends one `edit_timeline` call on the copy: `place_media` mode `replace` for each screenshot and the voice, `set_text` and `set_text_style` for the titles, and `trim_clip` to fit the cut. It sees a new `state_token`.
</Step>
<Step title="Check, then export">
The agent calls `capture` on every screenshot and title and `check_timeline`, then `export` with `timeline_id` set to the new timeline. It sees an export card with status `completed`.
</Step>
</Steps>

The terminal version:

```bash
invideo context write <project-url>/context/brands/acme.md \
  --markdown @acme-brand.md
invideo asset upload <edit-url> ./shots/*.png
invideo gen models <project-url> --query "narration voice"
invideo gen model <project-url> \
  --model elevenlabs_text_to_speech.elevenlabs_tts_v4
invideo gen run <page-url> \
  --model elevenlabs_text_to_speech.elevenlabs_tts_v4 --dry-run \
  -i prompt=@this-week.txt -i voice_id=<voice-id>
invideo gen run <page-url> \
  --model elevenlabs_text_to_speech.elevenlabs_tts_v4 \
  --max-credits <price> --idempotency-key week-44-voice \
  -i prompt=@this-week.txt -i voice_id=<voice-id>
invideo status <thread-url> --wait
invideo notebook show <thread-url>
invideo edit show <edit-url> --json
invideo edit change <edit-url> --timeline T3 --token <state_token> \
  --operations @copy.json
invideo edit show <edit-url> --timeline T4 --json
invideo edit change <edit-url> --timeline T4 --token <state_token> \
  --operations @swap.json
invideo edit capture <edit-url> --timeline T4 --at 2,10,20,40 \
  --out ./frames
invideo edit check <edit-url>
invideo edit export <edit-url> --format video --timeline T4 --quality 1080 \
  --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out
```

Where each value comes from:

- `<project-url>` is the project the weekly videos live in. `<edit-url>` is its edit's URL, from `invideo edit new` on the first run.
- `<voice-id>` comes from last week's thread, read with `invideo notebook show`. It works only with `elevenlabs_text_to_speech.elevenlabs_tts_v4`.
- `<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. `notebook show` on it lists the voice's sequence URL.
- `<state_token>` comes from `invideo edit show`. The copy makes the old token stale, so the agent reads the edit again before the swap.
- `T3` is last week's timeline and `T4` the copy, both from `invideo edit show`.
- `<card-url>` is `.sequences[0]` of the export answer. `invideo status` waits but saves nothing. `invideo notebook show` saves the video as `./out/export.mp4`, and the agent renames it.

The copy is one op. The swap uses the new timeline's clip ids, read after the copy. Each file is the bare list of ops that `--operations` takes, and the timeline it acts on comes from `--timeline`. The file behind `@copy.json`:

```json
[
  { "op": "duplicate_timeline", "timeline": "T3",
    "name": "What's new, week 44" }
]
```

The file behind `@swap.json`. `m21` is the new screenshot's bin id from `invideo asset upload`. `c31` is the old screenshot and `c35` the title, on `T4`, from `invideo edit show`. `<font-id>` is the font's id in the media bin, from what `add_media` returns.

```json
[
  { "op": "place_media", "asset": "m21", "track": "V1", "at_f": 150,
    "source_start_seconds": 0, "source_end_seconds": 5,
    "mode": "replace", "replace_clip": "c31", "linked_audio": false },
  { "op": "set_text", "clip": "c35", "text": "Dark mode is here" },
  { "op": "set_text_style", "clip": "c35",
    "style": { "font": "<font-id>", "color": "#5b3df5",
      "font_weight": 700 } }
]
```

## 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 voice each week, and captions if you add them with a transcript.
- Free: the brand entry, the copy, every swap, `capture` and `export`.

The first video takes under an hour. Later weeks take a few minutes of agent time. See [Credits](/account/credits) for prices.

## If something goes wrong

Most problems are ids from 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. |
| `invideo status --wait` ends and the folder is empty | `status` does not download. Run `invideo notebook show <card-url> --out <dir>`. |
| The edit changed last week's video | The ops used the old timeline's ids. Read the copy with `get_timeline` and use its ids. |
| The export is last week's video | Pass `timeline_id` for the new timeline in `export`. |
| The font does not change | `font` takes the font's id from the media bin, not its name. Bring the file in with `add_media` on the timeline's URL. |
| `write` refused on the brand entry | Someone changed it since your read. `read` it again and pass the new `revision`, or change one part with `edit`. |
| A screenshot is cropped | Fit it with `fit_frame`, or ask for screenshots at the timeline's shape. |
| CLI exit 3 | The edit changed since your read. Run `invideo edit show` and rebuild. |
| Avoid: rebuild the video from scratch each week | Instead: copy last week's timeline with `duplicate_timeline`. |

## Prompts to try

Each prompt is a real variation of this job.

```text
Make a short vertical version of this week's update for LinkedIn,
from the same timeline, with captions.
```

```text
Set up our brand kit in invideo from brand.pdf: colors, fonts and logo.
Then make the first weekly update from the notes below.
```

```text
Make this week's update for the internal team only. Add the bug fixes
section too. No voice, only text and music.
```

## When to use something else

invideo does not capture web pages or record screens. Use your agent's browser, a screenshot tool, or a screen recorder, then bring the files in. To run this every week without you, a CI job can run the CLI. See [Run invideo in CI and on servers](/how-to/ci-and-servers).

## Related

- [Run invideo in CI and on servers](/how-to/ci-and-servers)
- [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)
- [Voice a script or narrate a course](/how-to/training/voice-a-script-or-narrate-a-course)
- [Check your video before you say it is done](/how-to/check-your-video)