mcp-kdenlive 0.1.0__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.
- mcp_kdenlive-0.1.0/.gitignore +12 -0
- mcp_kdenlive-0.1.0/LICENSE +21 -0
- mcp_kdenlive-0.1.0/PKG-INFO +154 -0
- mcp_kdenlive-0.1.0/README.md +126 -0
- mcp_kdenlive-0.1.0/docs/architecture.md +30 -0
- mcp_kdenlive-0.1.0/docs/clients.md +96 -0
- mcp_kdenlive-0.1.0/docs/compatibility.md +93 -0
- mcp_kdenlive-0.1.0/docs/governance.md +81 -0
- mcp_kdenlive-0.1.0/docs/incident-response.md +78 -0
- mcp_kdenlive-0.1.0/docs/packaging.md +80 -0
- mcp_kdenlive-0.1.0/docs/registry.md +45 -0
- mcp_kdenlive-0.1.0/docs/releasing.md +64 -0
- mcp_kdenlive-0.1.0/docs/research/integration-surfaces.md +164 -0
- mcp_kdenlive-0.1.0/docs/security.md +83 -0
- mcp_kdenlive-0.1.0/docs/supply-chain.md +62 -0
- mcp_kdenlive-0.1.0/docs/tools.md +335 -0
- mcp_kdenlive-0.1.0/docs/user-guide.md +106 -0
- mcp_kdenlive-0.1.0/docs/versioning.md +100 -0
- mcp_kdenlive-0.1.0/pyproject.toml +95 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/__init__.py +10 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/__main__.py +3 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/cli.py +64 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/create.py +508 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/edits.py +398 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/environment.py +338 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/errors.py +17 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/jobs.py +319 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/kdenlive_doc.py +188 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/media.py +553 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/policy.py +113 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/process.py +139 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/project.py +514 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/py.typed +0 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/render.py +577 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/safexml.py +87 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/server.py +668 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/templates/kdenlive-26.08-empty.kdenlive +1377 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/timecode.py +101 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/timeline_edit.py +638 -0
- mcp_kdenlive-0.1.0/src/mcp_kdenlive/writer.py +351 -0
- mcp_kdenlive-0.1.0/tests/conftest.py +86 -0
- mcp_kdenlive-0.1.0/tests/fixtures/PROVENANCE.md +41 -0
- mcp_kdenlive-0.1.0/tests/fixtures/compat.json +421 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/generated-montage.kdenlive +2100 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/kd26-ntsc-timeline.kdenlive +1692 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/kd26-ntsc.kdenlive +1531 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/kd26-subtitle.kdenlive +1710 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/kd26-subtitle.kdenlive.ass +22 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/media/ntsc.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/media/pal clip /303/251.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/kd26/media/tone.wav +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/profiles/atsc_1080p_25 +11 -0
- mcp_kdenlive-0.1.0/tests/fixtures/profiles/atsc_720p_2997 +11 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/av.kdenlive +275 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/blue.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/blue.mpg +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/blue.png +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/clip-ids.kdenlive +1671 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/clip-ids.resaved-26.08.2.kdenlive +2785 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/green.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/green.mpg +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/green.png +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/missing-proxy.kdenlive +676 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/mono.flac +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/red.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/red.mpg +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/red.png +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/stereo.flac +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-keyframes.kdenlive +476 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-keyframes.resaved-26.08.2.kdenlive +1583 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-missing.kdenlive +320 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-mix.kdenlive +322 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-nesting-effects.kdenlive +796 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-nesting-effects.resaved-26.08.2.kdenlive +1938 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-nesting.kdenlive +730 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/test-nesting.resaved-26.08.2.kdenlive +1849 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/yellow.mp4 +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/yellow.mpg +0 -0
- mcp_kdenlive-0.1.0/tests/fixtures/upstream/yellow.png +0 -0
- mcp_kdenlive-0.1.0/tests/interface_snapshot.json +270 -0
- mcp_kdenlive-0.1.0/tests/test_cli.py +38 -0
- mcp_kdenlive-0.1.0/tests/test_compat.py +131 -0
- mcp_kdenlive-0.1.0/tests/test_create.py +182 -0
- mcp_kdenlive-0.1.0/tests/test_edits.py +190 -0
- mcp_kdenlive-0.1.0/tests/test_environment.py +156 -0
- mcp_kdenlive-0.1.0/tests/test_integration_environment.py +19 -0
- mcp_kdenlive-0.1.0/tests/test_interface.py +113 -0
- mcp_kdenlive-0.1.0/tests/test_media.py +294 -0
- mcp_kdenlive-0.1.0/tests/test_packaging.py +56 -0
- mcp_kdenlive-0.1.0/tests/test_process.py +67 -0
- mcp_kdenlive-0.1.0/tests/test_project.py +239 -0
- mcp_kdenlive-0.1.0/tests/test_render.py +547 -0
- mcp_kdenlive-0.1.0/tests/test_safexml.py +45 -0
- mcp_kdenlive-0.1.0/tests/test_security.py +252 -0
- mcp_kdenlive-0.1.0/tests/test_server.py +194 -0
- mcp_kdenlive-0.1.0/tests/test_timecode.py +62 -0
- mcp_kdenlive-0.1.0/tests/test_timeline_edit.py +261 -0
- mcp_kdenlive-0.1.0/tests/test_workflows.py +73 -0
- mcp_kdenlive-0.1.0/tests/test_writer.py +214 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Manoah BERNIER
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mcp-kdenlive
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local-first MCP server to inspect, edit and render Kdenlive projects.
|
|
5
|
+
Project-URL: Homepage, https://github.com/mhbxyz/kdenlive-mcp
|
|
6
|
+
Project-URL: Issues, https://github.com/mhbxyz/kdenlive-mcp/issues
|
|
7
|
+
Project-URL: Source, https://github.com/mhbxyz/kdenlive-mcp
|
|
8
|
+
Author: Manoah BERNIER
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: kdenlive,llm,mcp,mlt,model-context-protocol,video-editing
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Multimedia :: Video :: Non-Linear Editor
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: mcp<3,>=2.3
|
|
26
|
+
Requires-Dist: pydantic<3,>=2.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# kdenlive-mcp
|
|
30
|
+
|
|
31
|
+
<!-- mcp-name: io.github.mhbxyz/kdenlive-mcp -->
|
|
32
|
+
|
|
33
|
+
Local-first, client-agnostic [MCP](https://modelcontextprotocol.io) server for
|
|
34
|
+
[Kdenlive](https://kdenlive.org) on Linux.
|
|
35
|
+
|
|
36
|
+
Inspect, edit and render Kdenlive projects from an AI assistant, locally on Linux: timelines,
|
|
37
|
+
media diagnostics, safe project copies, clip edits and rendering with Kdenlive presets.
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
pipx install mcp-kdenlive # NOT "kdenlive-mcp": that PyPI name is an unrelated project
|
|
41
|
+
kdenlive-mcp diagnose
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Start here: [docs/user-guide.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/user-guide.md)** (install, client setup, safety, upgrade,
|
|
45
|
+
troubleshooting). The available tools are listed in [docs/tools.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/tools.md), and the
|
|
46
|
+
planned work in the [roadmap](https://github.com/mhbxyz/kdenlive-mcp/issues/1).
|
|
47
|
+
|
|
48
|
+
## Requirements
|
|
49
|
+
|
|
50
|
+
- Linux
|
|
51
|
+
- Python 3.11 or newer
|
|
52
|
+
- Kdenlive, MLT (`melt`) and FFmpeg (`ffprobe`), installed separately from your distribution.
|
|
53
|
+
The Python package does not install them.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
pipx install mcp-kdenlive
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The PyPI distribution is **`mcp-kdenlive`**. The PyPI name `kdenlive-mcp` belongs to an
|
|
62
|
+
unrelated project, so `pipx install kdenlive-mcp` installs something else. See
|
|
63
|
+
[docs/packaging.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/packaging.md) for virtual environments, upgrades and artifact checks.
|
|
64
|
+
|
|
65
|
+
### From source
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
git clone https://github.com/mhbxyz/kdenlive-mcp.git
|
|
69
|
+
cd kdenlive-mcp
|
|
70
|
+
uv sync # or: python -m venv .venv && .venv/bin/pip install -e .
|
|
71
|
+
uv run kdenlive-mcp --version
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Check your environment
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
uv run kdenlive-mcp diagnose # human-readable, exit status 1 if something required is missing
|
|
78
|
+
uv run kdenlive-mcp diagnose --json # machine-readable
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The same report is available to MCP clients through the `diagnose_environment` tool.
|
|
82
|
+
|
|
83
|
+
Programs are looked up on `PATH`. Override their location with these environment variables:
|
|
84
|
+
|
|
85
|
+
| Variable | Program |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `KDENLIVE_MCP_KDENLIVE` | `kdenlive` (for example an AppImage path) |
|
|
88
|
+
| `KDENLIVE_MCP_MELT` | `melt` |
|
|
89
|
+
| `KDENLIVE_MCP_FFPROBE` | `ffprobe` |
|
|
90
|
+
| `KDENLIVE_MCP_FFMPEG` | `ffmpeg` (optional) |
|
|
91
|
+
| `KDENLIVE_MCP_PROBE_TIMEOUT` | Seconds allowed for each version probe (default 10) |
|
|
92
|
+
| `KDENLIVE_MCP_ALLOWED_ROOTS` | `:`-separated absolute directories; every read and write must stay inside them (**recommended**, see [docs/security.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/security.md)) |
|
|
93
|
+
| `KDENLIVE_MCP_MAX_RENDERS` | Concurrent background renders (default 1, max 4) |
|
|
94
|
+
|
|
95
|
+
Flatpak and Snap builds of Kdenlive do not expose `kdenlive`, `melt` or `ffprobe` on `PATH`.
|
|
96
|
+
Point the variables above to executables or wrapper scripts.
|
|
97
|
+
|
|
98
|
+
## Start the server
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
uv run --directory /path/to/kdenlive-mcp kdenlive-mcp # same as: kdenlive-mcp serve
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Tested clients (Claude Code, Codex CLI, OpenCode, Grok Build CLI) and copyable
|
|
105
|
+
configurations are listed in [docs/clients.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/clients.md). A typical configuration:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"kdenlive": {
|
|
111
|
+
"command": "uv",
|
|
112
|
+
"args": ["run", "--directory", "/path/to/kdenlive-mcp", "kdenlive-mcp"],
|
|
113
|
+
"env": { "KDENLIVE_MCP_KDENLIVE": "/usr/bin/kdenlive" }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
MCP clients often start servers with a reduced environment. If tools are reported missing
|
|
120
|
+
from a client but not from your shell, pass `PATH` or the `KDENLIVE_MCP_*` variables
|
|
121
|
+
explicitly.
|
|
122
|
+
|
|
123
|
+
To try the server with the official MCP Inspector:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
npx @modelcontextprotocol/inspector --cli uv run --directory "$PWD" kdenlive-mcp --method tools/list
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
uv sync
|
|
133
|
+
uv run pytest # unit + protocol tests; integration tests skip when tools are missing
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Architecture: domain modules (`environment.py`, `process.py`) do not depend on MCP.
|
|
137
|
+
`server.py` is the only MCP transport layer.
|
|
138
|
+
|
|
139
|
+
Documentation:
|
|
140
|
+
|
|
141
|
+
- [User guide](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/user-guide.md)
|
|
142
|
+
- [Releasing (maintainers)](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/releasing.md)
|
|
143
|
+
- [Contributing](https://github.com/mhbxyz/kdenlive-mcp/blob/main/CONTRIBUTING.md)
|
|
144
|
+
- [Tools](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/tools.md)
|
|
145
|
+
- [Clients](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/clients.md)
|
|
146
|
+
- [Compatibility](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/compatibility.md)
|
|
147
|
+
- [Versioning](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/versioning.md)
|
|
148
|
+
- [Security model](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/security.md)
|
|
149
|
+
- [Security policy (reporting vulnerabilities)](https://github.com/mhbxyz/kdenlive-mcp/blob/main/SECURITY.md)
|
|
150
|
+
- [Incident response](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/incident-response.md)
|
|
151
|
+
- [Packaging](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/packaging.md)
|
|
152
|
+
- [MCP Registry](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/registry.md)
|
|
153
|
+
- [Changelog](https://github.com/mhbxyz/kdenlive-mcp/blob/main/CHANGELOG.md)
|
|
154
|
+
- [Research](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/research/integration-surfaces.md)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# kdenlive-mcp
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: io.github.mhbxyz/kdenlive-mcp -->
|
|
4
|
+
|
|
5
|
+
Local-first, client-agnostic [MCP](https://modelcontextprotocol.io) server for
|
|
6
|
+
[Kdenlive](https://kdenlive.org) on Linux.
|
|
7
|
+
|
|
8
|
+
Inspect, edit and render Kdenlive projects from an AI assistant, locally on Linux: timelines,
|
|
9
|
+
media diagnostics, safe project copies, clip edits and rendering with Kdenlive presets.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pipx install mcp-kdenlive # NOT "kdenlive-mcp": that PyPI name is an unrelated project
|
|
13
|
+
kdenlive-mcp diagnose
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Start here: [docs/user-guide.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/user-guide.md)** (install, client setup, safety, upgrade,
|
|
17
|
+
troubleshooting). The available tools are listed in [docs/tools.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/tools.md), and the
|
|
18
|
+
planned work in the [roadmap](https://github.com/mhbxyz/kdenlive-mcp/issues/1).
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Linux
|
|
23
|
+
- Python 3.11 or newer
|
|
24
|
+
- Kdenlive, MLT (`melt`) and FFmpeg (`ffprobe`), installed separately from your distribution.
|
|
25
|
+
The Python package does not install them.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pipx install mcp-kdenlive
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The PyPI distribution is **`mcp-kdenlive`**. The PyPI name `kdenlive-mcp` belongs to an
|
|
34
|
+
unrelated project, so `pipx install kdenlive-mcp` installs something else. See
|
|
35
|
+
[docs/packaging.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/packaging.md) for virtual environments, upgrades and artifact checks.
|
|
36
|
+
|
|
37
|
+
### From source
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
git clone https://github.com/mhbxyz/kdenlive-mcp.git
|
|
41
|
+
cd kdenlive-mcp
|
|
42
|
+
uv sync # or: python -m venv .venv && .venv/bin/pip install -e .
|
|
43
|
+
uv run kdenlive-mcp --version
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Check your environment
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
uv run kdenlive-mcp diagnose # human-readable, exit status 1 if something required is missing
|
|
50
|
+
uv run kdenlive-mcp diagnose --json # machine-readable
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The same report is available to MCP clients through the `diagnose_environment` tool.
|
|
54
|
+
|
|
55
|
+
Programs are looked up on `PATH`. Override their location with these environment variables:
|
|
56
|
+
|
|
57
|
+
| Variable | Program |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `KDENLIVE_MCP_KDENLIVE` | `kdenlive` (for example an AppImage path) |
|
|
60
|
+
| `KDENLIVE_MCP_MELT` | `melt` |
|
|
61
|
+
| `KDENLIVE_MCP_FFPROBE` | `ffprobe` |
|
|
62
|
+
| `KDENLIVE_MCP_FFMPEG` | `ffmpeg` (optional) |
|
|
63
|
+
| `KDENLIVE_MCP_PROBE_TIMEOUT` | Seconds allowed for each version probe (default 10) |
|
|
64
|
+
| `KDENLIVE_MCP_ALLOWED_ROOTS` | `:`-separated absolute directories; every read and write must stay inside them (**recommended**, see [docs/security.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/security.md)) |
|
|
65
|
+
| `KDENLIVE_MCP_MAX_RENDERS` | Concurrent background renders (default 1, max 4) |
|
|
66
|
+
|
|
67
|
+
Flatpak and Snap builds of Kdenlive do not expose `kdenlive`, `melt` or `ffprobe` on `PATH`.
|
|
68
|
+
Point the variables above to executables or wrapper scripts.
|
|
69
|
+
|
|
70
|
+
## Start the server
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
uv run --directory /path/to/kdenlive-mcp kdenlive-mcp # same as: kdenlive-mcp serve
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Tested clients (Claude Code, Codex CLI, OpenCode, Grok Build CLI) and copyable
|
|
77
|
+
configurations are listed in [docs/clients.md](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/clients.md). A typical configuration:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"kdenlive": {
|
|
83
|
+
"command": "uv",
|
|
84
|
+
"args": ["run", "--directory", "/path/to/kdenlive-mcp", "kdenlive-mcp"],
|
|
85
|
+
"env": { "KDENLIVE_MCP_KDENLIVE": "/usr/bin/kdenlive" }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
MCP clients often start servers with a reduced environment. If tools are reported missing
|
|
92
|
+
from a client but not from your shell, pass `PATH` or the `KDENLIVE_MCP_*` variables
|
|
93
|
+
explicitly.
|
|
94
|
+
|
|
95
|
+
To try the server with the official MCP Inspector:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
npx @modelcontextprotocol/inspector --cli uv run --directory "$PWD" kdenlive-mcp --method tools/list
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Development
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
uv sync
|
|
105
|
+
uv run pytest # unit + protocol tests; integration tests skip when tools are missing
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Architecture: domain modules (`environment.py`, `process.py`) do not depend on MCP.
|
|
109
|
+
`server.py` is the only MCP transport layer.
|
|
110
|
+
|
|
111
|
+
Documentation:
|
|
112
|
+
|
|
113
|
+
- [User guide](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/user-guide.md)
|
|
114
|
+
- [Releasing (maintainers)](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/releasing.md)
|
|
115
|
+
- [Contributing](https://github.com/mhbxyz/kdenlive-mcp/blob/main/CONTRIBUTING.md)
|
|
116
|
+
- [Tools](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/tools.md)
|
|
117
|
+
- [Clients](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/clients.md)
|
|
118
|
+
- [Compatibility](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/compatibility.md)
|
|
119
|
+
- [Versioning](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/versioning.md)
|
|
120
|
+
- [Security model](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/security.md)
|
|
121
|
+
- [Security policy (reporting vulnerabilities)](https://github.com/mhbxyz/kdenlive-mcp/blob/main/SECURITY.md)
|
|
122
|
+
- [Incident response](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/incident-response.md)
|
|
123
|
+
- [Packaging](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/packaging.md)
|
|
124
|
+
- [MCP Registry](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/registry.md)
|
|
125
|
+
- [Changelog](https://github.com/mhbxyz/kdenlive-mcp/blob/main/CHANGELOG.md)
|
|
126
|
+
- [Research](https://github.com/mhbxyz/kdenlive-mcp/blob/main/docs/research/integration-surfaces.md)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Architecture and technology choices
|
|
2
|
+
|
|
3
|
+
## Runtime and SDK
|
|
4
|
+
|
|
5
|
+
| Choice | Decision | Why |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Language | Python ≥ 3.11 | Decided in #1/#24; rich XML, subprocess and packaging tooling, `pipx` installs. |
|
|
8
|
+
| MCP SDK | Official [`mcp`](https://pypi.org/project/mcp/) Python SDK, `>=2.3,<3` | Maintained by the Model Context Protocol project. v2 provides `MCPServer`, typed structured output and an in-process `Client` for tests. |
|
|
9
|
+
| Transport | stdio only | Local-first; no listener. Remote access is future work (#22). |
|
|
10
|
+
| Data models | pydantic v2 (already required by `mcp`) | JSON Schema for tool outputs, validation of inputs. |
|
|
11
|
+
|
|
12
|
+
The SDK negotiates the protocol version with each client. Both 2026-07-28 clients (modern SDK
|
|
13
|
+
`Client`) and 2025-era clients using the `initialize` handshake (`2025-06-18`) are covered by
|
|
14
|
+
tests. The package version is not the protocol version.
|
|
15
|
+
|
|
16
|
+
## Layers
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
cli.py argument parsing, logging to stderr, starts the server
|
|
20
|
+
server.py MCP transport: tool registration, annotations, schemas (only module importing mcp)
|
|
21
|
+
environment.py domain: locate and probe external programs
|
|
22
|
+
process.py domain: safe subprocess execution (argument lists, process groups, timeouts)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Rules:
|
|
26
|
+
|
|
27
|
+
- **Dependency direction:** domain modules never import `server.py` or `mcp`.
|
|
28
|
+
- **No shell:** subprocesses always use argument lists, closed stdin, a timeout, and a process-group kill on timeout.
|
|
29
|
+
- **Clean stdout:** stdout belongs to the protocol. Diagnostics use `logging` on stderr.
|
|
30
|
+
- **Read-only first:** tools that only read declare `readOnlyHint`.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# MCP client compatibility
|
|
2
|
+
|
|
3
|
+
The server speaks standard MCP over **stdio**. It uses no vendor-specific extensions, and
|
|
4
|
+
every tool result carries both `structuredContent` and the same data as JSON text, for
|
|
5
|
+
clients that ignore structured output.
|
|
6
|
+
|
|
7
|
+
## Tested matrix
|
|
8
|
+
|
|
9
|
+
Tested on 2026-11-08, Linux (CachyOS, KDE Plasma), server `0.1.0.dev0`. Each client ran the
|
|
10
|
+
same headless scenario:
|
|
11
|
+
|
|
12
|
+
1. list the server's tools;
|
|
13
|
+
2. `inspect_project` on `tests/fixtures/kd26/kd26-ntsc-timeline.kdenlive`, then report the frame rate and duration;
|
|
14
|
+
3. `get_timeline`, then report the V1 clip's `start`, `end` and `source_out`;
|
|
15
|
+
4. `inspect_project` with a relative path, then report the error code.
|
|
16
|
+
|
|
17
|
+
Expected answers: `30000/1001`, `60 frames`, `0 / 60 / 59`, `[invalid_path]`.
|
|
18
|
+
|
|
19
|
+
| Client (product) | Version | Model used | Config method tested | Result |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| Claude Code (Anthropic CLI) | 2.1.319 | claude-opus-5-5 | `claude -p … --mcp-config mcp.json --strict-mcp-config --allowedTools mcp__kdenlive__…` | ✅ all 4 steps |
|
|
22
|
+
| Codex CLI (OpenAI) | codex-cli 0.165.0 | gpt-6.1-terra | `codex exec -c 'mcp_servers.kdenlive.command="…"' -c 'mcp_servers.kdenlive.args=[]'` | ✅ all 4 steps; the error is shown as a failed tool call |
|
|
23
|
+
| OpenCode | 1.19.4 | user's default (not recorded) | project `opencode.json` with an `mcp.kdenlive` `local` entry, `opencode run` | ✅ all 4 steps |
|
|
24
|
+
| Grok Build CLI (xAI) | 1.0.77 stable | grok-4.6-build | `grok mcp add -s user …`, then `grok -p … --allow "mcp__<name>__*"` | ✅ all 4 steps; handshake on protocol 2025-11-25 |
|
|
25
|
+
| MCP Inspector CLI | 2.14.0 (npx) | — | `npx @modelcontextprotocol/inspector --cli <command> --method tools/list` | ✅ discovery and schemas |
|
|
26
|
+
| Official MCP Python SDK `Client` | mcp 2.3.0 | — | automated tests (in-process and real stdio subprocess) | ✅ in CI |
|
|
27
|
+
| Raw JSON-RPC client using the 2025-06-18 `initialize` handshake | — | — | automated test (`tests/test_server.py`) | ✅ in CI; stdout is JSON-RPC only |
|
|
28
|
+
|
|
29
|
+
**Grok scope:** Grok refuses project-scoped (`./.grok/config.toml`) stdio servers in an
|
|
30
|
+
untrusted folder ("folder untrusted"). Use `-s user`, or trust the project in Grok.
|
|
31
|
+
|
|
32
|
+
### Not verified
|
|
33
|
+
|
|
34
|
+
- **Other versions of these clients:** older or newer versions, and the desktop or IDE variants of Claude, Codex and Grok, were not tested.
|
|
35
|
+
- **Cloud-hosted clients** (web chat products, cloud agents): they cannot start a local stdio process. They would need a local bridge or a remote transport, which this server does not provide (see #22). Local file access must never be assumed there.
|
|
36
|
+
- **Transports:** no HTTP or SSE transport exists. Only stdio is supported.
|
|
37
|
+
|
|
38
|
+
## Copyable configurations
|
|
39
|
+
|
|
40
|
+
Replace `/path/to/kdenlive-mcp` with the absolute path of the `kdenlive-mcp` executable
|
|
41
|
+
(`command -v kdenlive-mcp` after `pipx install mcp-kdenlive`), or use the `uv run` form for a
|
|
42
|
+
source checkout. No secrets are required.
|
|
43
|
+
|
|
44
|
+
**Claude Code**, `mcp.json` (or `claude mcp add kdenlive -- /path/to/kdenlive-mcp`):
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{ "mcpServers": { "kdenlive": { "command": "/path/to/kdenlive-mcp", "args": [] } } }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Codex CLI**, `~/.codex/config.toml`:
|
|
51
|
+
|
|
52
|
+
```toml
|
|
53
|
+
[mcp_servers.kdenlive]
|
|
54
|
+
command = "/path/to/kdenlive-mcp"
|
|
55
|
+
args = []
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**OpenCode**, `opencode.json` (project) or the global config:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{ "$schema": "https://opencode.ai/config.json",
|
|
62
|
+
"mcp": { "kdenlive": { "type": "local", "command": ["/path/to/kdenlive-mcp"], "enabled": true } } }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Grok Build CLI:**
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
grok mcp add kdenlive /path/to/kdenlive-mcp # user scope
|
|
69
|
+
grok mcp doctor kdenlive # expect: handshake OK, 5 tools discovered
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**With uv, no install**: command `uvx`, args `["mcp-kdenlive"]`. The package also provides an
|
|
73
|
+
`mcp-kdenlive` command, so this works; it is also how the MCP Registry entry describes it.
|
|
74
|
+
|
|
75
|
+
**From a source checkout** (any client): command `uv`, args
|
|
76
|
+
`["run", "--directory", "/path/to/repo", "kdenlive-mcp"]`.
|
|
77
|
+
|
|
78
|
+
## Smoke test without an AI client
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npx @modelcontextprotocol/inspector --cli /path/to/kdenlive-mcp --method tools/list
|
|
82
|
+
npx @modelcontextprotocol/inspector --cli /path/to/kdenlive-mcp --method tools/call \
|
|
83
|
+
--tool-name diagnose_environment
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Environment and PATH issues
|
|
87
|
+
|
|
88
|
+
- **Reduced environment:** clients start the server with their own, often reduced, environment. GUI-launched clients may not inherit your shell's `PATH`. Use absolute paths for the server command. If `diagnose_environment` reports Kdenlive, melt or ffprobe as missing only from the client, set `KDENLIVE_MCP_KDENLIVE`, `KDENLIVE_MCP_MELT` and `KDENLIVE_MCP_FFPROBE` in the client's `env` for the server.
|
|
89
|
+
- **Clean stdout:** the server writes only protocol messages to stdout. Use `--log-level DEBUG` to get diagnostics on stderr; most clients show them in their MCP logs.
|
|
90
|
+
- **Absolute paths:** paths passed to tools must be absolute. The server's working directory is whatever the client chose and carries no meaning.
|
|
91
|
+
|
|
92
|
+
## Optional protocol features
|
|
93
|
+
|
|
94
|
+
- **Tools only:** the server exposes tools only. No resources, prompts, sampling, elicitation or roots are required.
|
|
95
|
+
- **Text fallback:** clients without structured-output support read the JSON text content; a test checks it is identical to `structuredContent`.
|
|
96
|
+
- **Annotations:** tool annotations (`readOnlyHint`, …) are advisory and safe to ignore.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Compatibility
|
|
2
|
+
|
|
3
|
+
## Support status (v0.1)
|
|
4
|
+
|
|
5
|
+
Statuses are defined in [docs/versioning.md](versioning.md#external-software-support).
|
|
6
|
+
|
|
7
|
+
| Component | tested | supported | untested | unsupported |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| Kdenlive | 26.08.2 (everything); 23.08.5 (reading, editing, melt rendering) | 23.04 – 26.08 for reading and editing (document version 1.1) | other versions | `kdenlive --render` on 23.08 (refused with `[unsupported_kdenlive]`); editing documents older than 1.1 |
|
|
10
|
+
| MLT | 7.42.0, 7.22.0 | 7.x | — | — |
|
|
11
|
+
| FFmpeg / ffprobe | n9.0.2, 6.1.1 | ≥ 6 | older | — |
|
|
12
|
+
| Python | 3.11, 3.12, 3.13, 3.14 | — | 3.15+ | ≤ 3.10 |
|
|
13
|
+
| Linux | CachyOS (rolling), Ubuntu 24.04 (CI) | other distributions | Flatpak/Snap Kdenlive through wrappers | — |
|
|
14
|
+
| macOS, Windows | — | — | — | not supported |
|
|
15
|
+
| MCP clients | see [docs/clients.md](clients.md) | standard stdio MCP clients | desktop/IDE variants | cloud-only clients without a local bridge |
|
|
16
|
+
|
|
17
|
+
## Tested versions
|
|
18
|
+
|
|
19
|
+
| Environment | Kdenlive | MLT | FFmpeg | Python | What is exercised |
|
|
20
|
+
|---|---|---|---|---|---|
|
|
21
|
+
| Local reference (CachyOS, 2026-11-08) | 26.08.2 | 7.42.0 | n9.0.2 | 3.11–3.14 | everything (see below) |
|
|
22
|
+
| CI `Integration` job (Ubuntu 24.04 packages) | 23.08.5 | 7.22.0 | 6.1.1 | 3.13 | real-tool tests: diagnostics, ffprobe probing, creation and edits with melt, melt rendering of every fixture. `kdenlive --render` is absent in 23.08, so the server refuses with `[unsupported_kdenlive]`, which is also tested. |
|
|
23
|
+
| CI test matrix | — | — | — | 3.11, 3.12, 3.13, 3.14 | everything that needs no external program, on all fixtures |
|
|
24
|
+
|
|
25
|
+
Project documents read: Kdenlive document version **1.1** (Kdenlive ≥ 23.04, written by
|
|
26
|
+
23.04–26.08.2 in the fixtures) and **1.04** (Kdenlive 22.x, read-only and best effort). Editing
|
|
27
|
+
requires 1.1. Other Kdenlive versions are **untested**.
|
|
28
|
+
|
|
29
|
+
### What was verified with Kdenlive 26.08.2 itself
|
|
30
|
+
|
|
31
|
+
Verified locally with `research/lab/verify_roundtrip.py`: the project opens with no dialog, and after
|
|
32
|
+
Kdenlive's own *Save As*, tracks, clips, bin media, internal transitions and groups are identical.
|
|
33
|
+
|
|
34
|
+
| Project | Opens + round-trips in Kdenlive | `kdenlive --render` | melt render |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| Created by `create_project` (29.97/25 fps, AV and audio-only) | ✅ | ✅ | ✅ |
|
|
37
|
+
| Copy moved to another folder (`save_project_copy`) | ✅ | ✅ | ✅ |
|
|
38
|
+
| Media and named tracks added (`add_media_to_bin`, `add_track`) | ✅ | — | ✅ |
|
|
39
|
+
| Montage: insert, split, grouped move, trim, remove | ✅ | ✅ | ✅ |
|
|
40
|
+
| Kdenlive-made project with subtitles | ✅ | ❌ Kdenlive crashes (SIGSEGV), reproduced without this server (#16) | ✅ |
|
|
41
|
+
|
|
42
|
+
## Fixture corpus
|
|
43
|
+
|
|
44
|
+
Fixtures live in `tests/fixtures/`. Provenance is in `tests/fixtures/PROVENANCE.md`. The
|
|
45
|
+
expected reading of each fixture is in `tests/fixtures/compat.json`.
|
|
46
|
+
|
|
47
|
+
| Feature | Fixtures |
|
|
48
|
+
|---|---|
|
|
49
|
+
| 29.97 fps (30000/1001) | `kd26/*` |
|
|
50
|
+
| Audio and video tracks, AV groups, gaps | `kd26/kd26-ntsc-timeline`, `kd26/generated-montage`, `upstream/clip-ids*` |
|
|
51
|
+
| Split / trim / sub-range / named tracks / 6 tracks | `kd26/generated-montage` |
|
|
52
|
+
| Unicode media, track names and subtitle text | `kd26/*` |
|
|
53
|
+
| Subtitles (ASS) | `kd26/kd26-subtitle` |
|
|
54
|
+
| Effects, keyframes | `upstream/test-keyframes*`, `upstream/test-nesting-effects*` |
|
|
55
|
+
| Multiple and nested sequences | `upstream/test-nesting*` |
|
|
56
|
+
| Same-track mixes, document 1.04 | `upstream/test-mix`, `upstream/av` |
|
|
57
|
+
| Missing effect asset (LUT), missing proxy | `upstream/test-missing`, `upstream/missing-proxy` |
|
|
58
|
+
| Empty timeline | `kd26/kd26-ntsc` |
|
|
59
|
+
| Titles | **not covered yet**: creating one requires the Kdenlive title editor (#15) |
|
|
60
|
+
|
|
61
|
+
`tests/test_compat.py` checks:
|
|
62
|
+
|
|
63
|
+
- **Every fixture:** it reads exactly as recorded (version, frame rate, sequences, duration, clips, tracks, missing items).
|
|
64
|
+
- **Every editable fixture:** it survives a no-op save, with canonical XML identical.
|
|
65
|
+
- **Every complete fixture, with real tools:** melt renders it with the expected number of frames (Kdenlive 26.08 stores one extra frame, which is tolerated).
|
|
66
|
+
- **Kdenlive 26.08.2 fixtures, where Kdenlive has command-line rendering:** `kdenlive --render` renders them; the subtitle crash is an expected failure.
|
|
67
|
+
|
|
68
|
+
### Regenerating
|
|
69
|
+
|
|
70
|
+
- **Synthetic media:** `uv run python scripts/make_fixtures.py media DIR`. FFmpeg `lavfi` sources, bit-exact flags, no metadata. Bytes may differ across FFmpeg versions; the committed media are the reference.
|
|
71
|
+
- **Montage:** `uv run python scripts/make_fixtures.py montage`. It is rebuilt with this package's own editing functions, so review the diff when the editing code changes.
|
|
72
|
+
- **Kdenlive-made projects:** recreate them with the research lab (`research/lab/README.md`) and sanitize them as described in `PROVENANCE.md`.
|
|
73
|
+
|
|
74
|
+
## Adding a Kdenlive version to the matrix
|
|
75
|
+
|
|
76
|
+
1. **Install the version** (distribution, AppImage, …) and point `KDENLIVE_MCP_KDENLIVE` and `KDENLIVE_MCP_MELT` at it.
|
|
77
|
+
2. **Run the suite:** `uv run kdenlive-mcp diagnose`, then `uv run pytest -m integration`.
|
|
78
|
+
3. **Run the lab check** on the generated fixtures: `uv run python research/lab/verify_roundtrip.py tests/fixtures/kd26/*.kdenlive`, with `KD_ARGS`/`PATH` pointing at that Kdenlive.
|
|
79
|
+
4. **Add fixtures it wrote:** open or re-save a few fixtures in it (lab or GUI), sanitize them, add them under `tests/fixtures/<version>/`, and record them in `compat.json` and `PROVENANCE.md`.
|
|
80
|
+
5. **Update the tables** above with what passed and what did not. Record a failure as a limitation with evidence; never claim support it does not have.
|
|
81
|
+
|
|
82
|
+
## Manual GUI checks
|
|
83
|
+
|
|
84
|
+
CI cannot open Kdenlive's interface. The lab automates *open → save → compare* locally, but
|
|
85
|
+
interactive editing must be checked by hand. The checklists are kept in the issues (#8, #10, #11)
|
|
86
|
+
and in the release notes as known limitations. For every new Kdenlive version, open each
|
|
87
|
+
`kd26/*` fixture and run through this checklist:
|
|
88
|
+
|
|
89
|
+
- [ ] Opens without a dialog; bin thumbnails appear; the profile in *Project Settings* matches `compat.json`.
|
|
90
|
+
- [ ] Timeline matches `get_timeline`: tracks and names, clip positions, gaps, groups (moving one half moves the other).
|
|
91
|
+
- [ ] Trim, move, undo and redo work; save, close, reopen keeps the edits.
|
|
92
|
+
- [ ] GUI render of `generated-montage` has the expected length and cuts.
|
|
93
|
+
- [ ] `kd26-subtitle` shows the subtitle "Bonjour é ✓" at 00:00:02.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Repository governance and release authority
|
|
2
|
+
|
|
3
|
+
## Who can do what
|
|
4
|
+
|
|
5
|
+
| Action | Who | Enforced by |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Merge to `main` | anyone with write access, **through a pull request only**, squash merge, after the 8 required CI checks pass | ruleset *main: CI required, no force push* |
|
|
8
|
+
| Push directly to `main`, force-push, delete `main` | nobody | same ruleset (no bypass actors) |
|
|
9
|
+
| Create a release tag `v*` | repository administrators (today: the owner, `mhbxyz`) | ruleset *release tags v\*: only admins create* (admin bypass) |
|
|
10
|
+
| Move or delete a release tag | nobody, administrators included | ruleset *release tags v\*: immutable (no bypass)* |
|
|
11
|
+
| Publish to TestPyPI / PyPI | the `release.yml` workflow, only for `v*` tags, through the `testpypi` / `pypi` environments | environment deployment policy (tags `v*` only) + PyPI Trusted Publisher bound to `mhbxyz/kdenlive-mcp`, `release.yml`, environment name |
|
|
12
|
+
| Change security settings, rulesets, environments, publishers | repository owner | GitHub permissions; PyPI account ownership |
|
|
13
|
+
| Run CI for an outside contributor's PR | after a maintainer approves the run | Actions setting: approval required for all external contributors |
|
|
14
|
+
|
|
15
|
+
### Required status checks on `main`
|
|
16
|
+
|
|
17
|
+
- `Lint and type check`
|
|
18
|
+
- `Dependency audit`
|
|
19
|
+
- `Tests (Python 3.11)`, `Tests (Python 3.12)`, `Tests (Python 3.13)`, `Tests (Python 3.14)`
|
|
20
|
+
- `Build and smoke-test artifacts`
|
|
21
|
+
- `Integration (distribution Kdenlive/MLT/FFmpeg)`
|
|
22
|
+
|
|
23
|
+
CodeQL runs too but is not required.
|
|
24
|
+
|
|
25
|
+
## Why no human approval is required (and how to harden later)
|
|
26
|
+
|
|
27
|
+
The owner asked for an autonomous workflow: an agent opens a PR, waits for CI and merges it,
|
|
28
|
+
then tags and publishes releases. Required approvals would block this. GitHub does not let a PR
|
|
29
|
+
author approve their own PR, and the agent acts with the owner's account. So:
|
|
30
|
+
|
|
31
|
+
- **Pull requests:** they require **0 approvals**.
|
|
32
|
+
- **Environments:** they have **no required reviewers and no wait timer**.
|
|
33
|
+
|
|
34
|
+
What still protects the project:
|
|
35
|
+
|
|
36
|
+
- every change goes through a PR with green CI;
|
|
37
|
+
- `main` history cannot be rewritten;
|
|
38
|
+
- release tags are admin-only and immutable;
|
|
39
|
+
- publishing happens only from tags, in tag-restricted environments, with OIDC (no tokens).
|
|
40
|
+
|
|
41
|
+
To harden later, for example when a second maintainer joins:
|
|
42
|
+
|
|
43
|
+
1. **Code-owner review:** in the `main` ruleset, set `required_approving_review_count: 1` and `require_code_owner_review: true`. `.github/CODEOWNERS` already lists owners.
|
|
44
|
+
2. **Approval before publishing:** add required reviewers (and *prevent self-review*) to the `pypi` environment.
|
|
45
|
+
3. **Up-to-date branches:** enable `strict_required_status_checks_policy` so PRs must be current with `main` before merging.
|
|
46
|
+
|
|
47
|
+
## Untrusted pull requests
|
|
48
|
+
|
|
49
|
+
- **No privileged triggers:** workflows do not use `pull_request_target` and expose no secrets to PRs. `GITHUB_TOKEN` defaults to read-only, and Actions cannot approve PRs.
|
|
50
|
+
- **Approval for outside contributors:** fork PRs from outside contributors wait for a maintainer to approve the CI run. Review changes to `.github/`, `pyproject.toml`, `uv.lock` and `scripts/` carefully before approving: those files decide what CI and releases execute.
|
|
51
|
+
- **Publishing stays out of reach:** the release workflow does not run on PRs, and the `pypi` environment refuses non-tag refs.
|
|
52
|
+
|
|
53
|
+
## Administrator bypass and emergency recovery
|
|
54
|
+
|
|
55
|
+
- **No bypass on `main`:** the rulesets give no bypass on `main`, nor on moving or deleting tags. Administrators can only bypass the tag *creation* restriction.
|
|
56
|
+
- **Emergency** (CI broken by an external outage while a security fix must ship):
|
|
57
|
+
1. temporarily set the `main` ruleset enforcement to *disabled* (Settings → Rules → Rulesets), in a commit-sized window;
|
|
58
|
+
2. merge the fix;
|
|
59
|
+
3. re-enable the ruleset immediately;
|
|
60
|
+
4. record what happened in the PR and, for security fixes, in the advisory.
|
|
61
|
+
- **A wrong release tag** is never moved: publish a new version (see `docs/versioning.md` and `docs/incident-response.md`).
|
|
62
|
+
|
|
63
|
+
## Periodic access review (every quarter, and after any incident)
|
|
64
|
+
|
|
65
|
+
- [ ] Collaborators and their roles (Settings → Collaborators); remove unused access.
|
|
66
|
+
- [ ] Deploy keys, GitHub Apps and installed integrations; remove unknown ones.
|
|
67
|
+
- [ ] PyPI and TestPyPI: project owners, maintainers and trusted publishers (`release.yml`, environments `pypi` and `testpypi` only).
|
|
68
|
+
- [ ] Rulesets and environments still match this document (`gh api repos/mhbxyz/kdenlive-mcp/rulesets`).
|
|
69
|
+
- [ ] Security features still enabled: Dependabot, secret scanning, push protection, private vulnerability reporting, CodeQL.
|
|
70
|
+
|
|
71
|
+
## Verification log
|
|
72
|
+
|
|
73
|
+
Verified on 2026-11-08:
|
|
74
|
+
|
|
75
|
+
- **Direct push to `main`:** rejected (`GH013: Changes must be made through a pull request; 8 of 8 required status checks are expected`), and `main` was unchanged.
|
|
76
|
+
- **Effective rules on `main`** (`GET /rules/branches/main`): deletion, non_fast_forward, required_linear_history, pull_request, required_status_checks.
|
|
77
|
+
- **Environments:** `testpypi` and `pypi` have deployment policy `v*` (tag) and no reviewers.
|
|
78
|
+
- **Tag immutability, exercised with `v0.1.0rc1` (#29):** `git push -f` moving the tag was rejected (`GH013 … Cannot update this protected ref`), and the tag is unchanged.
|
|
79
|
+
- **Tag creation by an admin:** creating `v0.1.0rc1` succeeded through the admin bypass; the push output reported the bypassed creation rule.
|
|
80
|
+
|
|
81
|
+
Not changed: repository visibility, collaborators, third-party access.
|