Skip to content

/cassette-video-edit

Edit, trim, cut, caption, subtitle, reframe, combine, add background music to, or export video, audio, and image files through Cassette. Use this skill whenever the user asks to change, preview, or render a media file in the project — even if they never say "Cassette" or name a

shell
$ npx -y skills add Cassette-Editor/oh-my-cassette --skill cassette-video-edit --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/cassette-video-edit
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

Edit, trim, cut, caption, subtitle, reframe, combine, add background music to, or export video, audio, and image files through Cassette. Use this skill whenever the user asks to change, preview, or render a media file in the project — even if they never say "Cassette" or name a

SKILL.md

cassette-video-edit.SKILL.md
name: cassette-video-edit
description: Edit, trim, cut, caption, subtitle, reframe, combine, add background music to, or export video, audio, and image files through Cassette. Use this skill whenever the user asks to change, preview, or render a media file in the project — even if they never say "Cassette" or name a tool — for example "trim the intro off demo.mp4", "add subtitles to this clip", "make me a 30-second cut with music", "why is there dead air at the start". Drives the local Oh My Cassette stdio MCP tools in Codex or Claude as one multi-turn conversation with the Cassette agent, with per-turn timeline previews, guided questions, and rendering only on explicit export.
version: 2.1.0
metadata:
  tags: [cassette, video, codex, claude, mcp, media-editing]
  category: media

Oh My Cassette local workflow

Cassette edits the media; you carry the messages. The `cassette` MCP server is a local stdio child process that opens no port and talks directly to the separate Cassette backend. Do not start or depend on the repository's FastAPI web-demo server for this workflow — that is a different adapter.

Two details live outside this file to keep it short. Read them when they apply:

  • `references/auth.md` — any `auth_*` error, or the user is not signed in on this machine.
  • `references/previews.md` — showing a timeline, contact sheet, or storyboard, and the plan-review

pause.

Courier doctrine

You are a courier between the user and the Cassette agent, not an editor or a brief writer.

  • Pass the user's editing words to `cassette_run_job` as `message` VERBATIM. Never rewrite,

optimize, summarize, translate, or expand them. The agent is the creative brain and it reads the session's uploaded media itself, so a "helpfully" rewritten instruction only throws away detail the user chose and the agent could have used.

  • Relay the agent's questions and plans back verbatim too. You add exactly three things: the

timeline delta, the version numbers, and any validated artifact path.

  • Do not call `cassette_make_prompt`. It is a legacy brief builder, kept only so the tool-name set

stays stable.

  • Never ask upfront about model, thinking level, optimization, or BGM. The defaults match the web

editor, and front-loading configuration questions is precisely the friction this workflow exists to remove.

Safety and identity

  • Only files inside the active host project roots or explicitly configured media roots are

ingestible. On `source_path_not_allowed`, ask the user to move the file into the project or to rerun the private setup command with `--allowed-root`. Do not go hunting for a path that works.

  • Keep the returned `session_id` and `job_id`. Sessions are isolated by default; hand one to

another host only when the user deliberately asks for a Codex or Claude handoff.

  • Use only paths and resource links returned in `artifacts`. Never invent an export path or ask the

MCP runtime to expose another local file.

The editing loop

One session is one continuous conversation on one persistent agent thread. The agent remembers every previous turn, so a follow-up like "make that title bigger" needs no context restating.

1. Call `cassette_ingest_media` once per source asset. Omit `session_id` on the first call so the runtime generates one, then reuse the returned value everywhere. 2. Call `cassette_list_assets` and confirm the intended files are present. 3. For each editing request, call `cassette_run_job` with the user's verbatim `message` and the same `session_id`. 4. Relay what comes back (see routing below), then wait for the user's next instruction. 5. Pass `export=true` only on a turn where the user expresses finish or export intent.

If the user explicitly asks for background music, `cassette_match_exact_bgm` takes a concrete title/artist, `jamendo_music_matcher` a configured mood/genre, and `cassette_match_bgm` is the Free To Use fallback. Then continue the conversation as normal.

One turn, end to end

User:  trim the dead air off the front of demo.mp4 and add a title card

You:   cassette_run_job(session_id="s_41k",
                        message="trim the dead air off the front of demo.mp4 and add a title card")
       → phase="succeeded"
         timeline_delta="v6→v9: trimmed 3.2s from head; added title card 0.0–2.5s"
         quality.timeline_ctl=<digest>, artifacts=[contact sheet]

       "v6→v9: trimmed 3.2s off the head and added a 2.5s title card. Nothing is rendered
        yet — want to see the contact sheet, or should I export?"

User:  export it

You:   cassette_run_job(session_id="s_41k", message="export it", export=true)
       → phase="review_required"
       cassette_review_completion(job_id="j_88", decision="export",
                                  reason="user asked to export; trim and title card both landed")
       → phase="exported", artifacts=[…/exports/j_88/demo_cut.mp4]

Note what did not happen: no status polling, no rewriting of the user's words, and no rendering until the user asked for it.

Routing on typed state

Treat the structured `phase` and `next_action` fields as authoritative. Do not decide routing, progress, or completion from keywords in prose.

`cassette_run_job` **is** the wait. It returns when the turn is settled, streaming MCP progress notifications while the agent works, and answers with a terminal phase. One call per user turn.

| phase | what it means | what you do | |---|---|---| | `succeeded` | edit committed, **nothing rendered** | relay `data.job.timeline_delta` + the digest, continue the conversation | | `needs_user` | the agent asked a question | relay it, then `cassette_answer_question(job_id, response)` | | `review_required` | export turn awaiting judgement | evaluate the result, then `cassette_review_completion(job_id, decision, reason)` — only `decision=export` renders | | `exported` | the render finished | present the validated `artifacts` and their resource links | | `failed` / `canc

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withoh-my-cassette

Oh My Cassette is an open-source AI video editing plugin and local MCP server for Claude Code, Codex, Hermes Agent, and OpenCode.

Get the whole plugin, auto-invoked
Stats
139
Stars
0
Views
2
Forks
Active
Maintenance
Python
Language
MIT
License
15h ago
Last commit
1mo ago
Created

Repo: Cassette-Editor/oh-my-cassette