Thanks for your interest. OpenCut is an active project with ~450 core modules, ~90 route blueprints, and 1,200+ API routes. This guide gets you oriented fast.
- No emojis in commit messages or code. Enforced.
- No
Co-Authored-By: Claudelines. Enforced. - No
--no-verifyon commits. Hooks exist for a reason. - Rewrite, don't tack on. If a module grows > 600 lines, consider decomposing.
- Version everything.
scripts/sync_version.pykeeps 19 targets in sync — run--checkin CI.
opencut/
__init__.py version stamp + module doc
server.py Flask app factory, Sentry init, temp_cleanup boot
jobs.py async_job decorator, job registry, SQLite persistence
helpers.py FFmpegCmd builder, run_ffmpeg, get_video_info,
check_disk_space (v1.3+), deferred temp cleanup worker
security.py CSRF, path validation, rate_limit primitives, safe_*
checks.py check_X_available() one-liners (40+ entries)
errors.py OpenCutError taxonomy + safe_error()
utils/config.py CaptionConfig, SilenceConfig, etc. dataclasses
core/ ~450 single-responsibility feature modules
routes/ ~90 Flask blueprints — wave_a/b/c/d/e/f for recent adds
export/ OTIO, Premiere XML, AAF, OTIOZ, SRT/VTT/ASS writers
extension/com.opencut.panel/ CEP (Adobe) panel — HTML/JS/ExtendScript
extension/com.opencut.uxp/ UXP panel (Premiere 25.6+)
installer/src/OpenCut.Installer/ Windows WPF installer (C#, .NET 9)
tests/ pytest suite; tests/fuzz/ for Atheris harness
scripts/ sync_version, sbom, misc dev helpers
routes/wave_a_routes.py through wave_h_routes.py are delivery batch labels, not
permanent taxonomy. Each wave file holds features that were added in a release cycle
before a proper semantic home was decided. When touching a wave file, prefer migrating
the endpoint to a purpose-named blueprint (e.g. audio_processing_routes.py) rather
than adding more routes to the wave file. New features should never land in a wave
file — create a semantic blueprint instead.
git clone https://github.com/SysAdminDoc/OpenCut.git
cd OpenCut
python -m venv .venv
.venv/Scripts/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e ".[ai]" # backend + AI extras (CPU)
pre-commit install # ruff + trailing-ws + yaml/json checks
python -m opencut.server # starts at http://localhost:5679CEP panel development:
reg add "HKCU\Software\Adobe\CSXS.11" /v PlayerDebugMode /t REG_SZ /d 1 /fOpen Chrome at http://localhost:7474 after launching Premiere with the panel visible.
- New async route →
@require_csrf→@async_job("job_type")on the route; worker body receives(job_id, filepath, data). Add the rule to_ALLOWED_QUEUE_ENDPOINTSinjobs_routes.py. - New optional dep → add a
check_X_available()entry inopencut/checks.py. Gate imports inside the function. Never hard-fail if the dep is missing — return a 503MISSING_DEPENDENCYwith an install hint. - Heavy optional imports (cv2, torch, numpy, librosa, PIL) → always import them inside the function that needs them, never at module top-level in a route file. Top-level heavy imports add latency to every test collection and cold-start even when the feature isn't used.
- Dataclass results → make them subscriptable via
__getitem__+keys()so routes canreturn dict(result)to Flask'sjsonifywithout a.to_dict()detour. Seecore/neural_interp.InterpResultfor the canonical shape. - FFmpeg subprocess → use
run_ffmpeg(cmd, job_id=job_id)(v1.24+). Thejob_idparameter is how cancel actually kills the child process. Without it, you get the legacy non-cancellable path. - Rate limiting → apply
@rate_limit_category("gpu_heavy" | "cpu_heavy" | "io_bound" | "light")on the route. Use@gpu_exclusiveon the inner worker body for GPU model loads. - Deprecating a route → wrap with
@deprecated_route(remove_in="2.0.0", replacement="/new/path", reason="...", sunset_date="2026-10-01"). The OpenAPI spec, response headers, and server logs pick it up automatically. - Governance / auth changes → update
SECURITY.md+ bump the supported-versions table.
Single-line title ≤ 70 chars, descriptive body. Example:
v1.24.0: subprocess tracking + disk monitor + request correlation
helpers.run_ffmpeg now accepts job_id=... and auto-registers the Popen
with the job subsystem, closing the v1.14.0 audit finding "158
untracked subprocess calls" that couldn't be interrupted on cancel.
...
Version-bump commits touch opencut/__init__.py + 16 other targets. Always run python scripts/sync_version.py --set X.Y.Z — don't hand-edit.
- Run
python -m ruff check --select E,F,I --ignore E501 opencut/before pushing. CI blocks on this. - Ship a test for any new behaviour.
tests/test_route_smoke.pyhas the smoke harness;tests/fuzz/has the Atheris entry points. - Update
CHANGELOG.mdwith a bullet under the relevant version. - Update
CLAUDE.mdif your change introduces a new pattern / gotcha / file location that future sessions should know about. CLAUDE.md is deliberately verbose — it's the onboarding document for maintainers returning after months away. - Don't commit
content_calendar.*— those are marketing-local files and shouldn't land upstream.
python scripts/sync_version.py --set X.Y.Zand verify with--check.python -m ruff check --select E,F,I --ignore E501 opencut/→All checks passed!python -c "from opencut.server import create_app; create_app()"→ smoke boot.CHANGELOG.md+CLAUDE.md+ROADMAP-NEXT.mdupdated.python scripts/sbom.pyto refresh the SBOM (optional but nice).- Tag:
git tag -a vX.Y.Z -m "OpenCut vX.Y.Z"— GitHub Actions build workflow picks it up and publishes installers.
- Bugs / security: SECURITY.md.
- Architecture / "where does X live": read
CLAUDE.md— it documents every non-obvious invariant + gotcha in the codebase. - Feature roadmap:
ROADMAP.md(long-range 302-feature plan) andROADMAP-NEXT.md(active quarter plan).