video-edit-cli 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- video_edit_cli-0.1.1/.claude/skills/release/SKILL.md +122 -0
- video_edit_cli-0.1.1/.gitignore +11 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/PKG-INFO +20 -9
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/README.md +12 -1
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/pyproject.toml +14 -5
- video_edit_cli-0.1.1/skills/create-clips/SKILL.md +63 -0
- video_edit_cli-0.1.1/skills/create-clips/references/package-format.md +43 -0
- video_edit_cli-0.1.1/skills/video-editor/SKILL.md +55 -0
- video_edit_cli-0.1.1/skills/video-editor/agents/openai.yaml +4 -0
- video_edit_cli-0.1.1/skills/video-editor/references/audio-restoration.md +33 -0
- video_edit_cli-0.1.1/skills/video-editor/references/cut-review.md +26 -0
- video_edit_cli-0.1.1/skills/video-editor/references/edit-plan.md +39 -0
- video_edit_cli-0.1.1/skills/video-editor/references/multicamera.md +25 -0
- video_edit_cli-0.1.1/skills/video-editor/references/subtitles-and-assets.md +32 -0
- video_edit_cli-0.1.1/skills/video-editor/references/transcription.md +31 -0
- video_edit_cli-0.1.1/skills/video-editor/references/vertical-video.md +26 -0
- video_edit_cli-0.1.1/skills/video-editor/references/workspace.md +27 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/__init__.py +1 -1
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/cli.py +32 -0
- video_edit_cli-0.1.1/src/video_editor/skills.py +61 -0
- video_edit_cli-0.1.1/tests/conftest.py +50 -0
- video_edit_cli-0.1.1/tests/generate_fixtures.py +169 -0
- video_edit_cli-0.1.1/tests/test_acceptance.py +473 -0
- video_edit_cli-0.1.1/tests/test_audio.py +205 -0
- video_edit_cli-0.1.1/tests/test_inspection.py +237 -0
- video_edit_cli-0.1.1/tests/test_multicam.py +206 -0
- video_edit_cli-0.1.1/tests/test_packaging.py +318 -0
- video_edit_cli-0.1.1/tests/test_plans.py +150 -0
- video_edit_cli-0.1.1/tests/test_review.py +143 -0
- video_edit_cli-0.1.1/tests/test_skills.py +34 -0
- video_edit_cli-0.1.1/tests/test_transcription.py +187 -0
- video_edit_cli-0.1.1/tests/test_workspace.py +62 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/assets.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/audio/__init__.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/audio/analysis.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/audio/comparison.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/audio/denoise.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/audio/mastering.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/errors.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/ffmpeg.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/inspection.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/media.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/plans.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/profiles.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/provenance.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/reframe.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/rendering.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/result.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/review.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/__init__.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/edit-plan.schema.json +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/project-profile.schema.json +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/result.schema.json +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/transcript.schema.json +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/schemas/workspace.schema.json +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/subtitles.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/sync.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/transcription/__init__.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/transcription/base.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/transcription/fixture.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/transcription/mlx_whisper.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/transcription/views.py +0 -0
- {video_edit_cli-0.1.0 → video_edit_cli-0.1.1}/src/video_editor/workspace.py +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: >
|
|
4
|
+
Release process for the video-edit-cli package. Handles version bumping
|
|
5
|
+
(major/minor/patch/beta), changelog updates, pre-release quality checks, wheel
|
|
6
|
+
verification (including the bundled agent skills), publishing to PyPI, git tagging,
|
|
7
|
+
and the GitHub Release. Use this skill whenever the user wants to cut a release,
|
|
8
|
+
bump the version, or publish to PyPI — even if they just say "let's ship it".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# video-edit-cli Release Process
|
|
12
|
+
|
|
13
|
+
Releases are published locally with `uv publish` (authenticated via the
|
|
14
|
+
`UV_PUBLISH_TOKEN` environment variable), then tagged and mirrored as a GitHub
|
|
15
|
+
Release. CI (`test.yml`) is the quality gate but does not publish.
|
|
16
|
+
|
|
17
|
+
## Before you start
|
|
18
|
+
|
|
19
|
+
Verify the preconditions. If any fail, stop and tell the user.
|
|
20
|
+
|
|
21
|
+
1. **Clean working tree** — `git status` shows no uncommitted changes
|
|
22
|
+
2. **On `main` and up to date** — `git pull`; releases only come from main
|
|
23
|
+
3. **CI green on HEAD** — `gh run list --branch main --limit 1` shows success
|
|
24
|
+
4. **Publish token present** — `test -n "$UV_PUBLISH_TOKEN"`
|
|
25
|
+
|
|
26
|
+
Ask the user what kind of release this is (patch / minor / major / beta). If
|
|
27
|
+
they already said, don't ask again.
|
|
28
|
+
|
|
29
|
+
## Step 1: Figure out what changed
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git log $(git describe --tags --abbrev=0)..HEAD --oneline
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Cross-reference with the `[Unreleased]` section of `CHANGELOG.md`; add any
|
|
36
|
+
missing entries under the Keep a Changelog categories (Added / Changed /
|
|
37
|
+
Fixed / Removed / Docs).
|
|
38
|
+
|
|
39
|
+
## Step 2: Run quality checks
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv run ruff check .
|
|
43
|
+
uv run ruff format --check .
|
|
44
|
+
uv run ty check
|
|
45
|
+
uv run pytest
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Fix any failure before continuing.
|
|
49
|
+
|
|
50
|
+
## Step 3: Bump the version
|
|
51
|
+
|
|
52
|
+
The version lives in **two** places; they must match:
|
|
53
|
+
|
|
54
|
+
1. `pyproject.toml` — `version = "X.Y.Z"`
|
|
55
|
+
2. `src/video_editor/__init__.py` — `__version__ = "X.Y.Z"`
|
|
56
|
+
|
|
57
|
+
Beta convention: `0.2.0` → `0.2.1b1` → `0.2.1b2` → `0.2.1`.
|
|
58
|
+
|
|
59
|
+
## Step 4: Update the changelog
|
|
60
|
+
|
|
61
|
+
In `CHANGELOG.md`: rename `## [Unreleased]` to `## [X.Y.Z] - YYYY-MM-DD`,
|
|
62
|
+
add a fresh empty `## [Unreleased]` section on top, and review the entries
|
|
63
|
+
for user-facing clarity. The release notes are taken from this section.
|
|
64
|
+
|
|
65
|
+
## Step 5: Build and verify the artifacts
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
rm -rf dist && uv build
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then verify the wheel — this is the step that catches packaging regressions:
|
|
72
|
+
|
|
73
|
+
- The `video-edit-cli` executable works from a clean venv:
|
|
74
|
+
`uv venv /tmp/vec-rel && uv pip install -p /tmp/vec-rel/bin/python dist/*.whl`
|
|
75
|
+
then run `--help` and `skills list`.
|
|
76
|
+
- **Bundled skills are present**: `unzip -l dist/*.whl | grep video_editor/skills/`
|
|
77
|
+
must show `SKILL.md` and references for every skill in
|
|
78
|
+
`video_editor.skills.SHIPPED_SKILLS` (repo `skills/` dir is the source of truth;
|
|
79
|
+
the force-include entries in `pyproject.toml` do the bundling).
|
|
80
|
+
- All JSON schemas are present: `unzip -l dist/*.whl | grep schemas/`.
|
|
81
|
+
|
|
82
|
+
## Step 6: Commit, tag, publish
|
|
83
|
+
|
|
84
|
+
Show the user a summary (version, changelog entry, files touched) and get
|
|
85
|
+
confirmation before pushing or publishing.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
git add pyproject.toml src/video_editor/__init__.py CHANGELOG.md
|
|
89
|
+
git commit -m "release: vX.Y.Z"
|
|
90
|
+
git tag vX.Y.Z
|
|
91
|
+
git push origin main vX.Y.Z
|
|
92
|
+
uv publish
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If `uv publish` fails mid-upload, it is safe to re-run; PyPI rejects
|
|
96
|
+
duplicate files idempotently.
|
|
97
|
+
|
|
98
|
+
## Step 7: GitHub Release
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
gh release create vX.Y.Z --title "vX.Y.Z" --notes "<the X.Y.Z changelog section>"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Step 8: Verify
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
uv pip install --no-cache -p /tmp/vec-verify/bin/python video-edit-cli==X.Y.Z --index-url https://pypi.org/simple
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
(Create the venv first; PyPI's simple index can lag ~1–2 minutes after upload —
|
|
111
|
+
retry rather than assuming failure.) Confirm `video-edit-cli skills install`
|
|
112
|
+
works from the fresh install, then share the links:
|
|
113
|
+
|
|
114
|
+
- PyPI: https://pypi.org/project/video-edit-cli/X.Y.Z/
|
|
115
|
+
- GitHub Release: `gh release view vX.Y.Z --json url`
|
|
116
|
+
|
|
117
|
+
## If something goes wrong after tagging
|
|
118
|
+
|
|
119
|
+
PyPI versions are immutable — a broken published version cannot be replaced.
|
|
120
|
+
Fix forward with a new patch release. If the tag was pushed but nothing was
|
|
121
|
+
published, you may delete and re-create it (`git tag -d vX.Y.Z && git push
|
|
122
|
+
origin :refs/tags/vX.Y.Z`) — confirm with the user first.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: video-edit-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Headless, project-agnostic video-editing CLI with atomic subcommands for AI agents.
|
|
5
|
-
|
|
5
|
+
Project-URL: Repository, https://github.com/computerlovetech/video-edit-cli
|
|
6
|
+
Project-URL: Issues, https://github.com/computerlovetech/video-edit-cli/issues
|
|
7
|
+
Keywords: agents,cli,editing,ffmpeg,video
|
|
6
8
|
Classifier: Development Status :: 3 - Alpha
|
|
7
9
|
Classifier: Environment :: Console
|
|
8
10
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -11,15 +13,13 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
11
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
14
|
Classifier: Programming Language :: Python :: 3.14
|
|
13
15
|
Classifier: Topic :: Multimedia :: Video :: Conversion
|
|
16
|
+
Requires-Python: >=3.11
|
|
14
17
|
Requires-Dist: jsonschema>=4.21
|
|
15
18
|
Requires-Dist: pyyaml>=6
|
|
16
|
-
Requires-Dist: deepfilternet>=0.5 ; extra == 'df'
|
|
17
|
-
Requires-Dist: mlx-whisper>=0.4 ; extra == 'mlx'
|
|
18
|
-
Requires-Python: >=3.11
|
|
19
|
-
Project-URL: Issues, https://github.com/computerlovetech/video-edit-cli/issues
|
|
20
|
-
Project-URL: Repository, https://github.com/computerlovetech/video-edit-cli
|
|
21
19
|
Provides-Extra: df
|
|
20
|
+
Requires-Dist: deepfilternet>=0.5; extra == 'df'
|
|
22
21
|
Provides-Extra: mlx
|
|
22
|
+
Requires-Dist: mlx-whisper>=0.4; extra == 'mlx'
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
25
|
# video-edit-cli
|
|
@@ -55,7 +55,18 @@ uv run video-edit-cli filmstrip create --input recording.mp4 \
|
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
The companion skill in `skills/video-editor/` teaches agents the editing method;
|
|
58
|
-
this package owns the mechanics.
|
|
58
|
+
this package owns the mechanics. The skill ships inside the package — install it
|
|
59
|
+
into a project with:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
video-edit-cli skills install # copies into .claude/skills/
|
|
63
|
+
video-edit-cli skills install --target <dir>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Alternatively, manage it with agr: `agr add computerlovetech/video-edit-cli/video-editor`.
|
|
67
|
+
Skills in `skills/` that are not listed in `video_editor.skills.SHIPPED_SKILLS`
|
|
68
|
+
(and the matching force-include entries in `pyproject.toml`) are agr-only and do
|
|
69
|
+
not ship in the wheel. Tests generate small deterministic fixtures at
|
|
59
70
|
runtime (`tests/generate_fixtures.py`); no media is committed.
|
|
60
71
|
|
|
61
72
|
Quality gates (run from this directory):
|
|
@@ -31,7 +31,18 @@ uv run video-edit-cli filmstrip create --input recording.mp4 \
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
The companion skill in `skills/video-editor/` teaches agents the editing method;
|
|
34
|
-
this package owns the mechanics.
|
|
34
|
+
this package owns the mechanics. The skill ships inside the package — install it
|
|
35
|
+
into a project with:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
video-edit-cli skills install # copies into .claude/skills/
|
|
39
|
+
video-edit-cli skills install --target <dir>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Alternatively, manage it with agr: `agr add computerlovetech/video-edit-cli/video-editor`.
|
|
43
|
+
Skills in `skills/` that are not listed in `video_editor.skills.SHIPPED_SKILLS`
|
|
44
|
+
(and the matching force-include entries in `pyproject.toml`) are agr-only and do
|
|
45
|
+
not ship in the wheel. Tests generate small deterministic fixtures at
|
|
35
46
|
runtime (`tests/generate_fixtures.py`); no media is committed.
|
|
36
47
|
|
|
37
48
|
Quality gates (run from this directory):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "video-edit-cli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.1"
|
|
4
4
|
description = "Headless, project-agnostic video-editing CLI with atomic subcommands for AI agents."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -39,11 +39,20 @@ dev = [
|
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
[build-system]
|
|
42
|
-
requires = ["
|
|
43
|
-
build-backend = "
|
|
42
|
+
requires = ["hatchling>=1.25"]
|
|
43
|
+
build-backend = "hatchling.build"
|
|
44
44
|
|
|
45
|
-
[tool.
|
|
46
|
-
|
|
45
|
+
[tool.hatch.build.targets.wheel]
|
|
46
|
+
packages = ["src/video_editor"]
|
|
47
|
+
|
|
48
|
+
# Ship the user-facing agent skills inside the package (playwright-cli pattern):
|
|
49
|
+
# the canonical copies stay in the repository-root skills/ directory, and only
|
|
50
|
+
# the listed skills are bundled. Development-only skills must not be added here.
|
|
51
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
52
|
+
"skills/video-editor" = "video_editor/skills/video-editor"
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.sdist]
|
|
55
|
+
include = ["src", "skills", "tests", "README.md", "pyproject.toml"]
|
|
47
56
|
|
|
48
57
|
[tool.pytest.ini_options]
|
|
49
58
|
markers = [
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-clips
|
|
3
|
+
description: Derive several publishable social clips (YouTube Shorts, standard YouTube videos, LinkedIn) from a long-form recording — podcast episode, interview, vlog, talk, or livestream. Use when the user asks to make clips, shorts, highlights, or teasers from a video, especially after a main edit already exists. Builds on the video-editor skill and the video-edit-cli CLI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You turn one long recording into a small set of clips worth publishing, each
|
|
7
|
+
packaged with everything needed to post it. The `video-editor` skill and the
|
|
8
|
+
`video-edit-cli` CLI are your workbench for all media mechanics; this skill owns
|
|
9
|
+
the clip-release workflow. Read the `video-editor` skill first if it is not
|
|
10
|
+
already loaded — its invariants (immutable sources, evidence before edits,
|
|
11
|
+
validate before rendering) all apply here.
|
|
12
|
+
|
|
13
|
+
## Inputs
|
|
14
|
+
|
|
15
|
+
Establish these before cutting anything; ask only for what you cannot infer.
|
|
16
|
+
|
|
17
|
+
- **Source**: an existing video-editor workspace (preferred — reuse its
|
|
18
|
+
transcript, plans, and hashes) or standalone media (then `workspace init` first).
|
|
19
|
+
- **Clip count**: default 3–5 if unspecified.
|
|
20
|
+
- **Full-episode URL**: needed for descriptions; use a `[LINK]` placeholder and
|
|
21
|
+
say so if unknown.
|
|
22
|
+
- **Language**: of the recording; copy is written in the same language unless
|
|
23
|
+
asked otherwise.
|
|
24
|
+
- **Formats**: default is both 9:16 vertical and 16:9 horizontal per clip.
|
|
25
|
+
- **Brand/voice**: any project profile, tone guidance, or naming conventions the
|
|
26
|
+
hosting repo provides (e.g. a project-specific publishing skill or profile YAML).
|
|
27
|
+
|
|
28
|
+
## Method
|
|
29
|
+
|
|
30
|
+
1. **Know the material.** Reuse the workspace transcript if present; otherwise
|
|
31
|
+
transcribe (see the video-editor transcription reference). Skim the full
|
|
32
|
+
transcript before selecting anything.
|
|
33
|
+
2. **Select moments editorially.** Choose self-contained segments with a hook in
|
|
34
|
+
the first seconds, one clear idea, and a natural ending — a claim, a result, a
|
|
35
|
+
story, a provocation. You choose; no command picks highlights for you. Target
|
|
36
|
+
20–90 s for Shorts. Prefer moments that stand alone without episode context.
|
|
37
|
+
3. **Tighten boundaries on evidence.** Use word-level transcript timing to start
|
|
38
|
+
on the first word of a sentence and end on a completed thought; verify each
|
|
39
|
+
boundary visually (frames/preview) before rendering.
|
|
40
|
+
4. **Render both formats per clip.** Vertical via `short create-plan` (mind the
|
|
41
|
+
vertical-video reference — check for burned-in captions before cropping faces);
|
|
42
|
+
horizontal as a straight excerpt at source aspect. Master audio to the
|
|
43
|
+
platform loudness target and run `output validate` on every deliverable.
|
|
44
|
+
5. **Subtitles.** Burn styled subtitles into both renders when the source has
|
|
45
|
+
none; always keep `subtitles.srt` and `subtitles.vtt` sidecars. If the source
|
|
46
|
+
already has burned-in captions, do not double-caption — mux instead.
|
|
47
|
+
6. **Write the copy.** For each clip, in the recording's language:
|
|
48
|
+
- `youtube-short.txt` — clickable title (line 1) + short description with the
|
|
49
|
+
episode link and relevant hashtags.
|
|
50
|
+
- `youtube-video.txt` — title + fuller description linking the episode.
|
|
51
|
+
- `linkedin.txt` — a self-contained post (hook, substance, link); no
|
|
52
|
+
clickbait that the clip doesn't cash.
|
|
53
|
+
7. **Package and review.** Assemble the layout in
|
|
54
|
+
[references/package-format.md](references/package-format.md), review every
|
|
55
|
+
render's cut boundaries and framing, and report any residual defects honestly.
|
|
56
|
+
|
|
57
|
+
## Boundaries
|
|
58
|
+
|
|
59
|
+
- Never modify the main edit or the source media; clips are derived artifacts.
|
|
60
|
+
- Do not publish anywhere — the deliverable is the reviewed package. Publishing
|
|
61
|
+
is owned by project-specific skills (e.g. a podcast's release skill).
|
|
62
|
+
- Project-specific tone, branding, output location, and naming conventions come
|
|
63
|
+
from the hosting repo; when absent, use the defaults above and say so.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Clip package format
|
|
2
|
+
|
|
3
|
+
One directory per clip, numbered in publish order, slug from the clip's topic:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
clips/
|
|
7
|
+
01-<topic-slug>/
|
|
8
|
+
vertical.mp4 # 9:16 master, validated
|
|
9
|
+
horizontal.mp4 # 16:9 master, validated
|
|
10
|
+
subtitles.srt
|
|
11
|
+
subtitles.vtt
|
|
12
|
+
youtube-short.txt # title on line 1, blank line, description
|
|
13
|
+
youtube-video.txt # title on line 1, blank line, description
|
|
14
|
+
linkedin.txt # complete post text
|
|
15
|
+
manifest.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`manifest.json` records provenance and the editorial decision:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"schema_version": "1",
|
|
23
|
+
"slug": "01-<topic-slug>",
|
|
24
|
+
"source": {"path": "…", "sha256": "…"},
|
|
25
|
+
"range": {"start": 123.45, "end": 187.2},
|
|
26
|
+
"reason": "why this moment was selected",
|
|
27
|
+
"language": "da",
|
|
28
|
+
"episode_url": "https://…",
|
|
29
|
+
"renders": {
|
|
30
|
+
"vertical": {"file": "vertical.mp4", "canvas": "1080x1920"},
|
|
31
|
+
"horizontal": {"file": "horizontal.mp4", "canvas": "1920x1080"}
|
|
32
|
+
},
|
|
33
|
+
"validation": "passed"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Rules:
|
|
38
|
+
|
|
39
|
+
- Every render keeps its `*.provenance.json` sidecar next to it.
|
|
40
|
+
- Formats a clip intentionally omits are left out of `renders` (and the reason
|
|
41
|
+
noted in the summary), never shipped unvalidated.
|
|
42
|
+
- If the episode URL is unknown, use `[LINK]` in all copy and `null` in the
|
|
43
|
+
manifest, and flag it in the final summary.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: video-editor
|
|
3
|
+
description: Edit, inspect, transcribe, cut, master, or package video and audio media with the headless `video-edit-cli` CLI. Use when the user asks to edit a recording, cut a video, inspect unfamiliar media, extract audio, preview a range, synchronize cameras, make a vertical clip, or produce podcast/episode deliverables.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are the editor; the `video-edit-cli` CLI is your workbench. It exposes atomic,
|
|
7
|
+
deterministic primitives that print one JSON result on stdout. You form the
|
|
8
|
+
editorial plan yourself — no command decides what to keep, remove, or highlight.
|
|
9
|
+
|
|
10
|
+
Run `video-edit-cli --help` (and `--help` on any subcommand) for the authoritative
|
|
11
|
+
command surface; inside this repository run it as `uv run video-edit-cli …`.
|
|
12
|
+
|
|
13
|
+
## Invariants (hold for every task)
|
|
14
|
+
|
|
15
|
+
- Source media is immutable. Never overwrite, re-encode in place, or delete an
|
|
16
|
+
original. Every derived file is new and keeps its `*.provenance.json` sidecar.
|
|
17
|
+
- Evidence before edits: never act on a range you have not inspected through
|
|
18
|
+
metadata, transcript, frames, waveform, or preview.
|
|
19
|
+
- Validate before rendering; preview before mastering when edits are material.
|
|
20
|
+
- Prefer the cheapest sufficient evidence: `probe` and transcript first for
|
|
21
|
+
dialogue; targeted visual/audio inspection only where a decision needs it.
|
|
22
|
+
|
|
23
|
+
## Method
|
|
24
|
+
|
|
25
|
+
1. **Establish the outcome.** Restate what deliverable is requested and what
|
|
26
|
+
media exists. Done when you can name the requested outputs and every source
|
|
27
|
+
file involved.
|
|
28
|
+
2. **Set up a workspace.** Read [references/workspace.md](references/workspace.md),
|
|
29
|
+
then `video-edit-cli workspace init`. Done when `workspace.json` lists every
|
|
30
|
+
source with its hash.
|
|
31
|
+
3. **Inspect the media.** `probe` every source; gather audio, proxies, frames,
|
|
32
|
+
filmstrips, waveforms, or range previews as decisions require. For dialogue
|
|
33
|
+
media read [references/transcription.md](references/transcription.md) and
|
|
34
|
+
transcribe first. Done when you know each source's duration, streams, and
|
|
35
|
+
content well enough to justify the plan you are about to form.
|
|
36
|
+
4. **Plan and render.** Read [references/edit-plan.md](references/edit-plan.md)
|
|
37
|
+
before creating or modifying a plan; author the plan yourself, validate it,
|
|
38
|
+
and render a preview. Done when the validated plan renders and its manifest
|
|
39
|
+
exists.
|
|
40
|
+
5. **Review and revise.** Read [references/cut-review.md](references/cut-review.md);
|
|
41
|
+
inspect every boundary of any render you produced. Done when each cut passes
|
|
42
|
+
or its defect is fixed or explicitly reported.
|
|
43
|
+
6. **Finish the deliverable.** Done when every requested output exists, passes
|
|
44
|
+
its relevant validation, and your summary reports remaining defects honestly.
|
|
45
|
+
|
|
46
|
+
## Branch references (read when the condition applies)
|
|
47
|
+
|
|
48
|
+
- Audio cleanup/mastering requested, or analysis finds degraded speech →
|
|
49
|
+
[references/audio-restoration.md](references/audio-restoration.md)
|
|
50
|
+
- Packaged deliverable (project profile, subtitles, assets, music, master
|
|
51
|
+
render) → [references/subtitles-and-assets.md](references/subtitles-and-assets.md)
|
|
52
|
+
- Multiple synchronized visual/audio sources →
|
|
53
|
+
[references/multicamera.md](references/multicamera.md)
|
|
54
|
+
- Vertical or short-form deliverable →
|
|
55
|
+
[references/vertical-video.md](references/vertical-video.md)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Audio restoration and mastering
|
|
2
|
+
|
|
3
|
+
Audio enhancement is adaptive: characterize first, then choose the lightest
|
|
4
|
+
treatment that meets the request. Never apply neural restoration blindly, and
|
|
5
|
+
always keep a mastering-only baseline candidate.
|
|
6
|
+
|
|
7
|
+
1. **Characterize.** `video-edit-cli audio analyze --input <wav>` reports
|
|
8
|
+
integrated loudness, true peak, loudness range, clipping indicators, silence
|
|
9
|
+
spans, and a high-frequency-dropoff signal. Decide from these numbers whether
|
|
10
|
+
the recording is clean, noisy, clipped, or band-limited.
|
|
11
|
+
2. **Baseline.** `video-edit-cli audio master --input <wav> --output <ws>/renders/mastered.wav`
|
|
12
|
+
applies the deterministic chain (highpass, gentle compression, two-pass
|
|
13
|
+
BS.1770 loudness normalization). Targets default to −16 LUFS / −1.5 dBTP;
|
|
14
|
+
take project targets from the external profile when one is supplied.
|
|
15
|
+
3. **Denoise only when analysis or listening justifies it.**
|
|
16
|
+
`video-edit-cli audio denoise --input <wav> --output <ws>/renders/denoised.wav
|
|
17
|
+
--backend deepfilternet` (requires the `df` extra). Master the denoised
|
|
18
|
+
result too, so candidates differ only in restoration.
|
|
19
|
+
4. **Compare at matched loudness.** `video-edit-cli audio compare --input <a>
|
|
20
|
+
--input <b> --output-dir <ws>/reports/ab` writes loudness-matched excerpts
|
|
21
|
+
plus metrics. Metrics rank candidates; they do not prove speech still sounds
|
|
22
|
+
natural — review the excerpts before choosing, and say which candidate you
|
|
23
|
+
chose and why.
|
|
24
|
+
|
|
25
|
+
Invariants: intermediates stay lossless WAV (the commands enforce this);
|
|
26
|
+
originals are never replaced; every processed file keeps its provenance
|
|
27
|
+
sidecar naming backend, model, and parameters. If the recording is damaged
|
|
28
|
+
beyond conservative treatment (heavy clipping, missing bandwidth), report the
|
|
29
|
+
limitation rather than reaching for reconstruction that alters the voice.
|
|
30
|
+
|
|
31
|
+
Completion: the delivered audio meets the requested loudness/true-peak targets
|
|
32
|
+
(verify with `audio analyze`), the mastering-only baseline still exists as an
|
|
33
|
+
artifact, and any denoising applied is justified in your summary.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Cut review
|
|
2
|
+
|
|
3
|
+
A render is unreviewed until every boundary has evidence. The loop is
|
|
4
|
+
render → inspect → revise → re-render, repeated until each cut passes or its
|
|
5
|
+
defect is explicitly reported.
|
|
6
|
+
|
|
7
|
+
1. `video-edit-cli cuts list --manifest <render>.manifest.json` enumerates every
|
|
8
|
+
boundary with its output time and the source out/in times it joins.
|
|
9
|
+
2. For each cut, `video-edit-cli cut inspect --manifest <manifest> --cut <i>
|
|
10
|
+
--output-dir <workspace>/reports --transcript <transcript.json>` produces a
|
|
11
|
+
filmstrip, waveform, short preview, before/after frames, and a report with
|
|
12
|
+
deterministic checks:
|
|
13
|
+
- `black_frames_near_cut` / `silence_near_cut` — timestamps flagged by
|
|
14
|
+
blackdetect/silencedetect in the review window.
|
|
15
|
+
- `clipped_word_before` / `clipped_word_after` — a transcript word whose span
|
|
16
|
+
straddles the cut point (pass `--transcript` whenever one exists).
|
|
17
|
+
3. Judge the evidence yourself: look at the filmstrip and frames for visual
|
|
18
|
+
jumps, posture/continuity mismatches, or mid-gesture cuts, and play or
|
|
19
|
+
inspect the preview's waveform for audible bumps. `passed: true` means the
|
|
20
|
+
deterministic checks found nothing — it does not certify the cut feels right.
|
|
21
|
+
4. Fix a defective cut by writing a revised plan (`parent_plan` set, adjusted
|
|
22
|
+
in/out times), re-rendering, and re-inspecting that boundary.
|
|
23
|
+
|
|
24
|
+
Completion: every cut in the final render has a report in
|
|
25
|
+
`<workspace>/reports/`, and each is either clean or explicitly listed as an
|
|
26
|
+
unresolved defect when you present the result.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Edit plans
|
|
2
|
+
|
|
3
|
+
A plan is an ordered keep-list compiled deterministically to FFmpeg: each
|
|
4
|
+
timeline clip keeps `[in, out)` seconds of a source, in output order. Times come
|
|
5
|
+
from transcript JSON or direct inspection — never estimated. The authoritative
|
|
6
|
+
field reference is `video-edit-cli/src/video_editor/schemas/edit-plan.schema.json`;
|
|
7
|
+
unknown fields fail validation.
|
|
8
|
+
|
|
9
|
+
Minimal plan:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"schema_version": "1",
|
|
14
|
+
"plan_id": "rough-cut-1",
|
|
15
|
+
"created_by": "<agent>",
|
|
16
|
+
"sources": [{"id": "src-1", "path": "/abs/path/recording.mp4"}],
|
|
17
|
+
"timeline": [
|
|
18
|
+
{"source": "src-1", "in": 0.5, "out": 42.1, "reason": "keep intro"},
|
|
19
|
+
{"source": "src-1", "in": 55.0, "out": 120.4, "reason": "false start removed at 42.1-55.0"}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
|
|
26
|
+
- Every clip carries a `reason` — the editorial justification for what this keep
|
|
27
|
+
implies was removed. Write reasons a reviewer could audit.
|
|
28
|
+
- Clips on the same source must be in increasing source order and must not
|
|
29
|
+
overlap; a plan that reorders or repeats source material is rejected.
|
|
30
|
+
- Store plans in `<workspace>/plans/`, one file per revision; set `parent_plan`
|
|
31
|
+
when revising instead of editing a rendered plan in place.
|
|
32
|
+
- `video-edit-cli plan validate --plan <file>` checks schema, references, ranges
|
|
33
|
+
against real media, and ordering; it also reports output duration and the cut
|
|
34
|
+
boundaries you must later inspect.
|
|
35
|
+
- `video-edit-cli render preview --plan <file> --output <workspace>/previews/<name>.mp4`
|
|
36
|
+
renders the validated rough cut (360p default) and writes
|
|
37
|
+
`<output>.manifest.json` mapping every output-time boundary back to source
|
|
38
|
+
times — the input for cut review. Never present a render whose boundaries you
|
|
39
|
+
have not inspected.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Multi-camera editing
|
|
2
|
+
|
|
3
|
+
Applies when multiple synchronized (or synchronizable) recordings cover the
|
|
4
|
+
same session — extra cameras, separate audio recorders, screen captures.
|
|
5
|
+
|
|
6
|
+
1. **Synchronize first.** `video-edit-cli sync analyze --reference <a> --other <b>`
|
|
7
|
+
estimates the offset by audio correlation and reports candidates and a
|
|
8
|
+
confidence ratio; it never rewrites sources. Verify a low-confidence result
|
|
9
|
+
by inspecting waveforms around the claimed alignment before trusting it.
|
|
10
|
+
2. **Apply explicitly.** `video-edit-cli sync apply --input <b> --offset <s>
|
|
11
|
+
--output <ws>/renders/b-aligned.mp4` (or a `.json` output for mapping
|
|
12
|
+
metadata only). All plan times then refer to the aligned timeline.
|
|
13
|
+
3. **Relate sources to roles.** Record which source is which camera/mic in the
|
|
14
|
+
workspace `--role` labels; project camera aliases live in the external
|
|
15
|
+
profile, not here.
|
|
16
|
+
4. **Choose cameras with evidence.** A clip's `video_source` selects the camera
|
|
17
|
+
while audio stays on the clip's `source`. Decide switches from transcript
|
|
18
|
+
context plus filmstrips of each candidate camera — check the speaker is
|
|
19
|
+
usable (framing, focus, reactions) on the camera you pick.
|
|
20
|
+
5. **Review switches like cuts.** Every camera switch is a boundary in the
|
|
21
|
+
render manifest; inspect each with `cut inspect` for continuity (posture,
|
|
22
|
+
gaze, gesture) across the switch.
|
|
23
|
+
|
|
24
|
+
Completion: sources verified aligned, every switch justified by inspected
|
|
25
|
+
evidence, and the single-source path still used when only one camera is usable.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Packaging: profiles, subtitles, assets, master render
|
|
2
|
+
|
|
3
|
+
Project identity — canvases, codecs, loudness targets, music, brand assets,
|
|
4
|
+
fonts, subtitle style — lives in an external YAML project profile passed by
|
|
5
|
+
path, never in the skill or your defaults. Without a profile you can still
|
|
6
|
+
preview; a publishable master needs one.
|
|
7
|
+
|
|
8
|
+
Order of operations for a packaged episode:
|
|
9
|
+
|
|
10
|
+
1. **Validate the profile's assets.** `video-edit-cli asset inspect --input <file>`
|
|
11
|
+
for each intro/outro/music/font/image the profile references; loading the
|
|
12
|
+
profile also fails on missing files. Fix or report missing assets before
|
|
13
|
+
rendering.
|
|
14
|
+
2. **Master render.** `video-edit-cli render master --plan <plan> --profile
|
|
15
|
+
<profile.yaml> --profile-name <name> --output <ws>/renders/<name>.mp4`
|
|
16
|
+
compiles the approved plan at the profile canvas/codec, mixes profile music
|
|
17
|
+
with speech-keyed ducking when declared, and normalizes loudness to the
|
|
18
|
+
profile targets. It writes the same boundary manifest as preview renders —
|
|
19
|
+
review cuts on the master too if timing changed.
|
|
20
|
+
3. **Subtitles.** `video-edit-cli subtitles create --manifest <render manifest>
|
|
21
|
+
--transcript <transcript.json> --output-srt … --output-vtt …` maps transcript
|
|
22
|
+
words through the kept ranges into output time (removed ranges drop their
|
|
23
|
+
words). Transcripts must carry the plan's source id — pass `--source-id` at
|
|
24
|
+
`transcript create` time. Attach with `subtitles render` (`--mode mux`
|
|
25
|
+
default; `burn` requires an ffmpeg build with libass and fails cleanly
|
|
26
|
+
otherwise).
|
|
27
|
+
4. **Validate the deliverable.** `video-edit-cli output validate --input <file>
|
|
28
|
+
--profile <profile.yaml> --profile-name <name> --expect-duration <s>
|
|
29
|
+
[--expect-subtitles --subtitles <srt>]` checks streams, canvas, frame rate,
|
|
30
|
+
duration, loudness/true peak, and subtitle timing. The command reports
|
|
31
|
+
`passed` with an issues list — the deliverable is not done until `passed`
|
|
32
|
+
is true or each issue is explicitly accepted by the user.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Transcription
|
|
2
|
+
|
|
3
|
+
For dialogue media the transcript is the primary editing surface — but not the
|
|
4
|
+
only one: reactions, gestures, camera usability, and continuity still need
|
|
5
|
+
targeted visual inspection (frames, filmstrips, previews).
|
|
6
|
+
|
|
7
|
+
Workflow:
|
|
8
|
+
|
|
9
|
+
1. `video-edit-cli transcript create --input <audio-or-video> --output <ws>/analysis/transcript.json`
|
|
10
|
+
runs the local backend (default `mlx-whisper`; requires the `mlx` extra) and
|
|
11
|
+
writes the authoritative word-level JSON. Pass `--source-id` so the transcript
|
|
12
|
+
records which workspace source it describes. Transcribing the extracted
|
|
13
|
+
canonical WAV is faster than the full video.
|
|
14
|
+
2. `transcript pack` derives a compact `[start-end] text` view sized for your
|
|
15
|
+
context. Read the packed view; treat the JSON as the source of truth for
|
|
16
|
+
times.
|
|
17
|
+
3. `transcript search --query "<phrase>"` returns word-aligned start/end times
|
|
18
|
+
plus segment context. Use it to locate passages precisely instead of scanning.
|
|
19
|
+
|
|
20
|
+
Rules:
|
|
21
|
+
|
|
22
|
+
- Every editorial time you use must come from transcript JSON times or direct
|
|
23
|
+
media inspection — never estimate timestamps from memory of the packed view's
|
|
24
|
+
prose.
|
|
25
|
+
- Transcript evidence is insufficient when the decision depends on what is
|
|
26
|
+
visible (reactions, demonstrations, camera choice) or on sound that is not
|
|
27
|
+
speech (music, noise, overlaps). Inspect the range visually/aurally before
|
|
28
|
+
deciding.
|
|
29
|
+
- If transcription fails or the backend is unavailable, fall back to waveform +
|
|
30
|
+
filmstrip inspection and say so; do not pretend acoustic evidence equals
|
|
31
|
+
semantic understanding.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Vertical / short-form deliverables
|
|
2
|
+
|
|
3
|
+
Applies when a vertical or short-form clip is requested. You choose the moment
|
|
4
|
+
— from the transcript and targeted inspection — and the tools execute it; no
|
|
5
|
+
command picks highlights.
|
|
6
|
+
|
|
7
|
+
1. **Choose the range yourself.** Find candidate moments in the transcript
|
|
8
|
+
(hooks, self-contained arguments), confirm visually with filmstrips, and pick
|
|
9
|
+
exact word-aligned in/out times.
|
|
10
|
+
2. **Frame explicitly.** Inspect a frame to decide the crop, then check it with
|
|
11
|
+
`video-edit-cli reframe preview --input <src> --start … --end …
|
|
12
|
+
--crop x:y:w:h --canvas 1080x1920`. Iterate until the speaker sits correctly
|
|
13
|
+
in the vertical frame.
|
|
14
|
+
3. **Derive the plan.** `video-edit-cli short create-plan --input <src>
|
|
15
|
+
--start … --end … --canvas 1080x1920 --crop … --reason "…"
|
|
16
|
+
--output <ws>/plans/short-1.json` writes a normal, editable edit plan with
|
|
17
|
+
`output_canvas` set; refine it like any plan (split clips, adjust times).
|
|
18
|
+
4. **Render and caption.** `render preview` honors the plan's canvas. Create
|
|
19
|
+
captions with `subtitles create` against the short's render manifest and
|
|
20
|
+
attach with `subtitles render`. Vertical viewers rely on captions — include
|
|
21
|
+
them unless told otherwise.
|
|
22
|
+
5. **Validate.** `output validate --expect-duration … --expect-subtitles`
|
|
23
|
+
plus a filmstrip of the result to confirm framing survived.
|
|
24
|
+
|
|
25
|
+
Completion: the short matches the requested canvas and duration, captions map
|
|
26
|
+
correctly to the excerpt, and your summary states why this range was chosen.
|