Skip to main content
Glama

splicedeck

checks licence: Apache-2.0 Python 3.12+ runtime dependencies: 0

A video editor an AI agent drives, running on your own machine.

One call dresses a cut in a template: motion graphics, overlays, captions and a beat grid to cut against. One pass over a source gives you both a cleaned long-form master and vertical clips. And it remembers how each client, channel or show likes to be cut, so the next edit starts where the last one ended.

There is no timeline to drag and no account to create. Nothing is uploaded.


Status: the pipeline runs end to end, and memory reaches the cut

A source becomes a delivered file today. Measured on the reference machine (Windows 11, Python 3.13, ffmpeg 8.1.2) against a real 223 MB .mov:

inspect   2.6 s     draft  27 ms     splice  27 ms     verify  42 ms
deliver   157 s  ->  1920×1080 h264 + aac, -23.0 LUFS, decodes clean

python -m pytest reports 1425 passed, 2 skipped in about four minutes. Thirty-one verbs reach the CLI and eighteen of them reach an MCP server, both generated from one table so they cannot drift apart.

One headline feature does not work yet. Cutting by quoting needs a speech binary that no manifest can currently obtain. Read What does not work before you plan around it.


Install

You need Python 3.12 or newer and ffmpeg 8.x on your PATH. splicedeck neither installs nor bundles ffmpeg, and docs/first-run.md §4 explains why that is deliberate.

The setup script asks where the workspace goes, offers to install ffmpeg after showing you the exact command, scaffolds everything and writes an MCP config:

curl -fsSLO https://raw.githubusercontent.com/ihuzaifashoukat/splicedeck/main/install.sh
less install.sh && bash install.sh
irm https://raw.githubusercontent.com/ihuzaifashoukat/splicedeck/main/install.ps1 -OutFile install.ps1
notepad install.ps1; powershell -ExecutionPolicy Bypass -File install.ps1

Read it before you run it. A curl | bash one-liner would be a poor advertisement for a project whose README is largely about a threat model.

If you would rather do it yourself, or want the tests:

uv tool install splicedeck                    # or: pipx install splicedeck
git clone https://github.com/ihuzaifashoukat/splicedeck.git && cd splicedeck
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]"   # Windows
.venv/bin/python  -m pip install -e ".[dev]"      # macOS, Linux

Not on PyPI yet. There is no release, so uv tool install splicedeck will 404 until the first tag is pushed. Until then use the script, a clone, or uv tool install "git+https://github.com/ihuzaifashoukat/splicedeck.git".

docs/install.md has every route, the per-platform ffmpeg commands, the environment variables, and a prompt you can paste into an AI agent to have it install and wire up splicedeck for you.

Try it

The workspace root is whichever directory you run in, and spd init scaffolds one:

mkdir my-edit && cd my-edit
spd init                                      # bookmarks/ casebook/ elements/ ledger/ media/ profiles/ templates/
mkdir -p casebook/parties/demo
spd ready                                     # what is present, and what each gap blocks

init never overwrites. Re-running it after you have edited a profile fills in whatever is missing and leaves your edits alone. The files it writes are byte-identical to the ones this repository ships, and python -m checks.starter --check enforces that.

Then put your footage under media/ and cut:

spd inspect --path media/your-file.mov               # mints a source handle
spd draft --party demo --source s1 --bookmark baseline --profile wide-1080
spd apply --sheet c1 --template clean-master         # overlays, motion, beat grid
spd splice --sheet c1 --source a --in_ticks 0 --out_ticks 900000 \
           --source_in_ticks 0 --cause manual
spd verify --sheet c1
spd deliver --sheet c1

Sources must live inside the workspace. A path with a drive letter in it is refused PATH_OUTSIDE_WORKSPACE before anything is read.

A party is created by a human, by hand, on purpose. draft refuses UNKNOWN_PARTY until casebook/parties/<name>/ exists.

To drive it from an MCP-capable assistant, register the server:

{"mcpServers": {"splicedeck": {
  "command": "C:\\src\\splicedeck\\.venv\\Scripts\\python.exe",
  "args": ["-m", "splicedeck.surface.mcp"],
  "cwd": "C:\\src\\splicedeck"}}}

cwd must be the workspace, because the workspace root is the working directory and nothing else discovers it. python -m splicedeck.surface.mcp --tools prints the generated tool list and exits, which is how you tell a broken server from a broken host configuration. docs/mcp.md is the full guide.

Templates: the look in one call

apply dresses a cut sheet in a named template. It places the overlays, writes the beat grid the agent then cuts against, and records on the sheet which template it used.

Four ship today:

Template

What it is

clean-master

A calm talking-head master carrying one lower-third and no beat grid

quick-beat

A fast-cut vertical: three beat slots with a pulsing accent on each

bold-run

A promo look: full-bleed intro and outro cards around two beat slots

bare-mark

One small mark on screen and nothing else

A template's overlays animate when the optional motion tier is installed, and fall back to a still imprint when it is not. Six animated compositions ship in scenes/, written for this project and licensed with it.

Slots are enforced. verify refuses to pass a sheet with an unfilled slot, and a cut landing outside a slot's tolerance is refused SLOT_TOO_TIGHT with the nearest legal edges returned as ready-to-send calls. That is what lets an agent hit a rhythm it cannot see.

You can write your own. spd compose --kind template validates and writes a hand-authored template or element card. It is deliberately CLI-only: the MCP server may not write to templates/, and docs/templates.md §4 explains the reasoning rather than treating it as an oversight.

Why memory

An edit is a thousand small judgements and almost all of them repeat. How long to hold after a punchline. Whether this speaker's filler is noise or personality. How big captions have to be on a phone at arm's length. A stateless tool makes you re-supply that context every session, which is why "AI editing" so often produces something technically correct and tonally wrong.

Here, a decision you make once is recorded and reused:

subtitle.size_px = 74
  when {surface: vertical, frame: 1080x1920}
  set by  a render you shipped and kept, 2026-08-02
  before  66

That record lives in your repository as reviewable text. You can read the diff, correct a bad entry by editing a line, and git revert a change that made the edits worse. It is a behaviour changelog, kept in the same place as everything else you version.

Two rules keep it trustworthy:

  • Nothing durable is written by the model. A record describes something a human did: shipped a render and kept it, restored a moment the cut removed. The agent can point at what happened; it cannot compose what gets remembered.

  • Every write passes a human gate. No preference is learned silently.

That loop runs today. spd set, ship, keep, restore and discard append acts to a party's hash-chained ledger and stage a proposal from each one; an act cannot be appended to a chain that does not verify. spd review then asks for the value blind, showing the bounds and the shipped cut but never the number, and a matching answer becomes a sealed case and a regenerated findings.lock.txt. The next draft resolves against it: the bookmark opens the settings, the casebook overrides the ones a human settled, and the sheet records which lock it read.

Local first, and complete

A fresh clone with no API keys and no cloud account produces a finished, delivered file on your own machine. That is the baseline, not a degraded mode.

Cloud services can be switched on where they genuinely help, such as a hosted speech API for difficult audio or diarisation, but nothing becomes required and no deliverable depends on one. ffmpeg does the work as a child process. It is never vendored and never linked.

The project also refuses to guess about your hardware. Encoder support is proven by test-encoding rather than by reading a feature list, because feature lists lie. On the development machine ffmpeg -encoders advertises an NVIDIA encoder that fails at runtime, while the Intel one that actually works goes unmentioned in every guide.

What works

  • One analysis pass, two deliverables. Transcription and analysis run once per source. The long-form master and the vertical clips both read the same results.

  • Frame-accurate cutting with no audio drift. Audio stays PCM until the mux and is encoded once. The delivered samples are byte-identical to a reference assembly built in Python over 45 and 120 joins. Measured, not asserted.

  • Templates and motion in one call, with a beat grid the agent cuts against and a still fallback when the motion tier is absent.

  • Captions that stay legible. Size and contrast floors are enforced by the renderer, and text that would land under a platform's own interface is refused rather than drawn. Glyphs are shaped and rasterised by a pure-stdlib TrueType parser, so imprints are byte-reproducible and committed as goldens.

  • Vertical framing that admits uncertainty. When the subject cannot be tracked confidently it declines to auto-frame and says why. A confidently wrong crop is worse than an honest refusal, because nobody reviews the one that looked fine.

  • Rights that hold up. Music, effects and stock footage carry a record of where they came from and what the terms permit. A delivery refuses to run if any asset lacks one.

  • Typed refusals that carry their own correction. A refusal arrives with retry_with, a list of ready-to-send calls. There are 102 codes, each with a construction site and a test proving it is reachable.

What does not work

Stated plainly, because a status section that omits this is the reason the last one was worthless.

Not working

Why

Blocks

Cutting by quoting

splicedeck/listen/fetchable.toml pins both download entries at a host that does not resolve, with placeholder all-zero digests. No route obtains the speech binary, including placing it by hand.

hear, quote, captions from speech

Subject tracking by model

No detector is pinned or shipped (docs/framing.md F5). The boundary is settled — a CLI child process, never an imported extension — but which binary fills it is not.

watch --subject largest at the model tier

Cancelling from an MCP host

The stdio loop is single-threaded, so nothing can arrive during a tools/call.

cancel over MCP. The CLI and Ctrl-C are unaffected.

CHANGELOG.md carries the same list, and the two are meant to stay in sync.

Two tiers below the model one do work. subject: "centre" is geometric and needs nothing. SPD_SIGHT_LOCATOR=reduce selects a weights-free locator that finds the subject by temporal-median background subtraction in pure stdlib Python, no numpy and no compiled extension anywhere.

Checked against a face detector on the reference master, that locator's median agreed to within 0.1% of frame width. On the same footage it then reported certainty 0.26 and fitted no path at all, because a speaker who barely moves against a static background leaves nothing for background subtraction to hold onto. Both of those are the right answer: the arithmetic is sound, and the honest limit of a weights-free tier is a hole rather than a centred guess (docs/framing.md §7). Footage with a moving subject tracks fine.

How you drive it

Through an MCP server and Skills, so any MCP-capable assistant can use it, plus a CLI exposing exactly the same verbs. Both surfaces are generated from splicedeck/surface/verbs.py, and python -m checks.golden --check fails the build if they drift apart.

The server speaks five protocol revisions, 2024-11-05 through 2026-07-28, and answers both the initialize handshake and server/discover.

Failures are typed. A refusal carries its own correction as ready-to-send calls rather than prose an agent has to interpret, so recovery is one turn:

{"ok": false, "verb": "draft", "refused": "BOOKMARK_UNKNOWN",
 "plain": "No bookmark by that name is shipped.",
 "needs_human": false,
 "retry_with": [{"verb": "draft", "args": {"bookmark": "baseline", "party": "demo",
   "profile": "wide-1080", "situation": "default", "source": "s1"}}]}

Skills

Four skills teach an agent the verb order, the traps between verbs, and how to turn a refusal into the next correct call. They live in .claude/skills/, and a clone picks them up with no install at all.

Skill

Fires when

cutting-a-deliverable

Turning a source into a delivered file

cutting-vertical-clips

Carving a 9:16 clip and keeping the subject in frame

recovering-from-a-refusal

Any ok: false, or an spd command exiting 1

contributing-to-splicedeck

Editing this codebase, or when two documents disagree

This repository is also a Claude Code plugin and its own marketplace:

claude plugin marketplace add ihuzaifashoukat/splicedeck
claude plugin install splicedeck@splicedeck

Or install the skills into any of the agents the skills CLI supports, including Codex, Cursor, OpenCode, Antigravity, Cline, Gemini CLI, Zed and Windsurf:

npx skills add ihuzaifashoukat/splicedeck            # add --list to look first

Both routes ship the skills only. They do not register the MCP server, because the server needs an absolute interpreter path and a cwd that neither a plugin nor a skill installer can know. install.sh writes that for you, and docs/mcp.md has it by hand.

Every other agent runtime reads AGENTS.md.

Design

The specification is written before the code, deliberately.

Document

What it settles

AGENTS.md

The contract every contributor and agent works under

docs/architecture.md

The map: runtimes, packages, data flow

docs/first-run.md

Clone to delivered file, and the Windows traps

docs/install.md

Every install route, and a prompt for an AI agent

docs/mcp.md

Driving splicedeck from an assistant

docs/cut-sheet.md

The core artifact: integer-timed, diffable, human-readable

docs/templates.md

Templates, slots, and what apply and compose do

docs/casebook.md

How memory is stored, resolved and gated

docs/security.md

The threat model, and why memory is an attack surface

docs/bookmarks.md

Styles, and the axes they are points in

docs/agent-surface.md

The verb table and the refusal catalogue

docs/roadmap.md

The feature areas, and what each has to prove

Persistent memory in an agent is a security surface, not just a feature. Anything an attacker can write into it outlives the conversation that planted it. If you read one document, read docs/security.md.

Non-goals

Assembling a film from many sources. Generating video or music. A timeline GUI. Real-time collaboration. A hosted service. Automatically choosing which moments become clips, since it presents candidates and waits for a person.

Requirements

Python 3.12 or newer, and ffmpeg 8.x on your PATH. No compiled Python extension is used on any default path, so there is no build step and no platform runtime to install first. Windows, macOS and Linux; CI covers Ubuntu and Windows, and macOS is untested by machine.

The motion tier additionally needs Node and an npm install inside scenes/. It is optional, and a delivery without it falls back to still imprints.

Contributing

Issues and design critique are welcome. CONTRIBUTING.md is the front door: setup, the checks to run, how to add a verb or a refusal code, and the things that get a pull request rejected regardless of merit. Read AGENTS.md first. The twelve hard rules are load-bearing, and a change that breaks one is rejected on that basis alone.

By taking part you agree to the Code of Conduct.

Security

Please do not open a public issue for a vulnerability. SECURITY.md has the reporting route and what is in scope.

Licence

Apache-2.0. Copyright 2026 Huzaifa Shoukat.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Agentic video editing on real footage: cut, caption, reframe, score, and export at full quality.

  • A real timeline video editor for AI agents: journaled edits, FFmpeg/MLT rendering, exports

  • Make videos and docs with your AI agent — describe what you need, every output stays editable.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ihuzaifashoukat/splicedeck'

If you have feedback or need assistance with the MCP directory API, please join our Discord server