Repository navigation
Releases
v0.33.1
What's Changed
- Release v0.33.1: Windows-safe anonymize test and complete v0.33.0 docs by @renezander030 in #173
Full Changelog: v0.33.0...v0.33.1
v0.33.0
What's Changed
- fix(text-style): apply --font-size, --color, --align, --x, --y without a preset by @abdullahmalik853-web in #166
- feat: add zero-dep ByteDance CapCut cloud subtitle translation by @datnt-97 in #169
- fix(translate): harden CapCut cloud translation from #169 by @renezander030 in #170
- fix(store): leave the CLI's own process chain out of the editor-open guard by @renezander030 in #171
- Release v0.33.0: caption coverage and cache, delivery gates, draft-change diff, shareable fixtures by @renezander030 in #172
New Contributors
- @abdullahmalik853-web made their first contribution in #166
Full Changelog: v0.32.0...v0.33.0
v0.32.0
What's Changed
- Include the fake CLI in Python source distributions by @renezander030 in #160
- docs: More from René block (agent tools) in README and README.zh-CN by @renezander030 in #161
- chore(deps-dev): bump @biomejs/biome from 2.5.15 to 2.6.2 in the dev-dependencies group by @dependabot[bot] in #162
- docs(readme): play the captioned output example inline by @renezander030 in #164
- Release v0.32.0: validate timing, translation and subtitle inputs by @renezander030 in #165
Full Changelog: v0.31.1...v0.32.0
v0.31.1
What's Changed
- Release v0.31.1: ffmpeg on the runners for the packed-tarball smoke by @renezander030 in #159
Full Changelog: v0.31.0...v0.31.1
v0.30.0 — per-command help, journal-checked undo, whisper.cpp word timings
Added
capcut <command> --help,capcut <command> -handcapcut help <command>print that command's usage, options, global options, output, prerequisites and exit codes, rendered from the same registry asdescribeand the command reference. Before, none of the 87 commands printed its own help: 79 read--helpas an argument and failed (add-text --help: "No draft found at: --help"), and 8 ran instead (doctor --helpran the checks).capcut helpalone, or an unknown command, prints the full help.restore --listreportsintegrityper step:intact(the snapshot still matches thebefore_sha256the write journal recorded),changed(it was rewritten after the CLI saved it), orunverified(no journal entry).restoreandrestore --step Nresults carry the same field.caption --wordsreads whisper.cpp full JSON (whisper-cli -ojf,transcription[].tokens[]) and reportswords_format: "whisper-cpp". Words are built from the tokens as incaption --audio; a segment whose tokens cannot be split into words stays one entry with its own timing.test/fixtures/jianying-9-0-0-windows/— a real JianYing 9.0.0 (Windows) project captured after the app opened a tool-written draft: the plaintextdraft_info.jsonprimary alongside thedraft_content.json/template-2.tmp/draft_meta_info.jsonmirrors the app rewrote into encrypted blobs, plus the materialisedTimelines/layout. A regression test pins that the encrypted mirrors are reported as unparseable rather than breaking canonical selection, anddocs/version-support.mdgains a JianYing 9.0.0 (Windows) row (evidence: reported; storage shape fixture-backed). The write guard is deliberately unchanged — one machine's capture is not a round-trip claim.
Changed
- With
--karaokeor--word-reveal,captionruns whisper.cpp with-ojfand times each word from its tokens instead of splitting each segment evenly. A token that starts with a space opens a word and any other token (a sub-word piece, punctuation) continues it; in Chinese and Japanese every token is its own word.[_BEG_]/[_TT_n]tokens are skipped, a word stamped with zero length runs to the next word's start, and a segment whose tokens do not spell its text keeps the even split. Plain-ojoutput parses as before. translatedefaults toclaude-haiku-5-5(wasclaude-haiku-4-5-20251001), with a 16,000-token response budget and low effort.
Fixed
restoreno longer puts back the app's own save state after the app saved the project (#151). History snapshots were a second name (hard link) for<draft>.bak, which CapCut 9.5 rewrites in place when it saves; each snapshot is now its own file.restoreandrestore --step Ncheck the file against the write journal first and refuse one that changed since the CLI wrote it withrefused [backup-changed]/refused [snapshot-changed]; the.bakrefusal points at--step 1when that snapshot is intact, and--force-writerestores the file as it is. Snapshots written by earlier versions that still share bytes with a rewritten.baklist aschanged.
v0.29.0 — aligner word timings, reviewed batch plans, render fidelity and lint checks
v0.29.0
Added
caption --words <file.json|->builds captions from word timings produced by an external aligner, so Whisper does not have to be installed. The format is detected automatically: Whisper / whisper.cppsegments[].words[], WhisperXword_segments[], or a plain{word|text|char, start, end}array with times in seconds,start_ms/end_msorstart_time/end_time(per-character forced-aligner output). The result reportswords_format,words_skippedandsource_words. Entries without timing are skipped; entries that end before they start or go back in time are refused withrefused [words-invalid]naming the entry. Grouping, CJK joining without spaces,--script,--karaokeand--word-revealbehave exactly as with Whisper words.--wordscannot be combined with--audio,--from-segment,--audio-stream,--ffmpeg-cmdor--whisper-*.batch <project> --plan <plan.json> < ops.jsonlvalidates the operations under dry-run without touching the draft and writes a reviewable plan:project,draft_sha256, the normalizedoperations,operations_sha256(over key-sorted JSON) and a per-operationpreview.batch <project> --apply-plan <plan.json>reads no stdin and applies the plan through the normal transactional batch. It refuses withrefused [plan-draft-changed]when the draft changed since the plan was written,refused [plan-tampered]when the operations no longer match their hash, andrefused [plan-project-mismatch]when the plan names another project. Without--continue-on-errora failing operation writes no plan.render(including--dry-run) reports afidelitycensus of what the proxy leaves out compared with the app:faithful,expected_duration_us, thecheckedcategories, and per dropped category a count, up to 20 segment ids and a hint (missing media, closed main-track gaps, uncomposited overlay tracks, unburned text, stickers, transitions, effects, filters, masks, keyframes, text/video animations, blend modes, chroma key, matting).render --strictrefuses withrefused [render-unfaithful]before anything is written.- After a real render,
renderprobes the written file with ffprobe (--ffprobe-cmdselects the binary) and reportsverification:{ verified, duration_us, expected_duration_us, drift_us, tolerance_us, within_tolerance }, with a tolerance of one frame at the render fps. When ffprobe is missing or cannot read the file it reportsverified: falsewith a reason.render --verifyexits non-zero on drift beyond tolerance or an unverifiable file; the file stays on disk and the JSON result is still printed. tts --lexicon <file.json>applies pronunciation rules ({"rules":[{"text","say","case_sensitive"?}]}or a bare array) to the text handed to the TTS engine only: longest match first, at word boundaries for rule edges that are word characters (SQLnever fires insideMySQLite; CJK rules match anywhere). Malformed lexicons refuse withrefused [lexicon-invalid], and equal-length rules that say different things at the same position refuse withrefused [lexicon-ambiguous], both before any engine runs. The result reportslexicon: { rules, applied, spoken_text }with offsets in UTF-16 code units into the trimmed text. Works with--textand--text-file.lintreportssegment-overlap(error) when two segments on the same non-text track (video, audio, sticker, effect, filter …) overlap, naming the track, both segment ids and the overlap in µs.lint --fixrepairs overlaps of at most one frame at the draft's fps (the independent-rounding overlap) by ending the earlier segment where the next begins, keeping its source duration in proportion to speed. Wider overlaps are reported, not fixed. Text tracks keepcaption-overlap.lintreportssegment-offscreen(warning) for video, photo, sticker and text segments that cannot be seen: the clip's box lies entirely outside the canvas (material size fitted intocanvas_config, rotation allowed for), a scale axis is 0, or opacity is 0. Segments whose position, scale or alpha is keyframed are not judged on that property. No--fix.- Every undo-history snapshot now records what made it:
.capcut-cli-history/<draft>.journal.jsonlgets{ index, time, command, argv, before_sha256, after_sha256 }per write (library callers recordcommand: null), trimmed together with the snapshots.restore --listshowscommand,argvandtimeper step; older snapshots without a journal line list with nulls. A torn or unreadable journal never breaks a write or a restore. - Whisper-free caption routes are documented in
docs/quickstart.zh-CN.md(不装 Whisper 的字幕路线) andexamples/short-video-narration.md: the app's own auto captions followed byrestyle/export-srt,import-srt, andcaption --words.
Changed
doctor's Whisper hint namescaption --wordsandimport-srtas routes that work without Whisper. The check's status is unchanged.lint --frame-grid --fixderives repaired source durations through the same helper as the new overlap repair: at speed 1 nothing changes; on clips at other speeds whose source duration matched target × speed (within 1%), the source duration now follows the snapped target duration instead of being left as it was.
This coordinated release comprises npm capcut-cli@0.29.0 and the Wasm component attached here with its checksum, license, and third-party notices. The Python client is unchanged (PyPI capcut==0.1.3).
Validation: 1,210 CLI tests pass with one platform-specific skip, and all 13 CI jobs pass. The packed tarball passes the release smoke test.
Merged in #142. All 13 checks pass on the tagged source: CI.
v0.28.0 — active timelines, app-created projects and client fixes
v0.28.0
Added
-
--active-timelineexplicitly follows a validatedTimelines/project.jsonpointer on app builds without a verified storage fixture (#50). Invalid, deleted, symlinked or conflicting selected timelines are refused; normal defaults and write guards remain unchanged. Writes keep root and active IDs and preserve other timelines. -
compile --into <project>populates an existing empty project created in CapCut (#52). It preserves project identity, per-document app markers and unknown settings, stages content-correct media, and commits imported-media registration with timeline writes. Failed copies and commits clean up only newly owned assets; the shared store index is never rewritten.--check,--planand--dry-runvalidate both spec and destination without writing. Nested layouts require active selection. Desktop acceptance on these opt-in paths remains unverified. -
describe --compactemits a small command discovery index with names, summaries, usage, and write status.describe --command <name>returns complete contracts for selected commands; repeat the flag for several names. The full v2 command contract remains the default. Python client v0.1.3 forwards these options throughcapcut.describe(compact=True, command="compile").
Fixed
- Python client v0.1.3 parses quoted Windows
CAPCUT_CLIpaths without retaining surrounding quotes or losing backslashes. Escaped quotes, trailing backslashes, and empty arguments follow Windows argv quoting; malformed quotes fail before spawning a process. POSIX command quoting and shell-free execution remain unchanged. Python client regression tests now run on Linux, macOS, and Windows, including Python 3.9 and 3.14.
This coordinated release comprises npm capcut-cli@0.28.0, PyPI capcut==0.1.3, and the Wasm component attached here with its checksum, license, and third-party notices.
Validation: 1,134 CLI tests pass with one platform-specific skip, 19 Python tests pass, and all 13 CI jobs pass. Packed npm installation, real FFmpeg compilation into an app-created shell, Python wheel integration, and twine check pass.
The new opt-in CapCut paths still require a desktop open/save/close/reopen acceptance check; issues #50 and #52 remain open.
Merged in #139. All 13 checks pass on the tagged source: CI.
v0.27.0
v0.27.0 — 2026-10-03
Added
relink --dir <folder> --recursivesearches nested media folders. Duplicate basenames are reported inambiguousand left unchanged; prefix remapping matches whole path components, and directory symlinks are not followed.
Fixed
replace-mediastages the requested bytes even when a different file with the same basename already exists. Occupied hash filenames are checked by content; dry runs create no asset directories or files, and directories/non-media segments are rejected before mutation.- Replacement and relink refresh changed media's
local_material_idlinks and imported-media entries when a readabledraft_meta_info.jsonexists. Sidecar and timeline writes share conflict checks, backups, and rollback; existing and unrelated import entries are preserved. Bare timelines still useregister --materials --applyto create registration metadata. compilederives target durations from rounded start and end boundaries, keeping adjacent fractional-second clips contiguous across text, video, audio, photos, and timed operations.- Compile operation payloads are checked with the same builders used by real writes before creating output. Failed builds remove only the output directory created by that invocation; successful builds register in the project index after the draft is saved.
servebinds a job ID to its effective command payload and execution settings. Identical submissions still deduplicate; reusing an ID for a different job returns a failure without executing the conflicting job.- Queue project locks resolve project roots, relative paths, timeline files, and symlink aliases so concurrent writers to the same project serialize.
- Queue input and limits reject malformed or non-finite values. Combined child output is checked again at exit before reading it, so a fast process cannot bypass the configured capture threshold. Overflow results omit captured output; the threshold is polled during execution and is not a hard disk quota.
import-timelineresolves relative media references against the OTIO document's directory and decodes localfile:URLs, including escaped spaces. Remote URLs and inaccessible references remain placeholders.
Install: npm install -g capcut-cli@0.27.0
The optional capability-free WebAssembly component and its checksums and license notices are attached below. It provides read-only inspection, linting, and diff operations through a compatible host.
v0.26.1 — active timelines, compile fixes, and fixture redaction
Fixes
fixtureredacts JSON-escaped Windows home paths, including embedded JSON, and automatically checks every generated bundle for recognizable residual private values. Failed checks return a nonzero exit status and are recorded inSANITIZE_REPORT.json(#134).compilehandles ratio-only and explicit-dimension canvases consistently. Material and sidecar durations use the full probed source duration; segments keep their requested lengths and source in-points. Invalid speed-adjusted source ranges are refused before creating a draft (#133).- On the fixture-backed CapCut 8.7.0 Windows layout, the CLI follows the validated active timeline pointer and synchronizes its readable mirrors and root copies while preserving document IDs and other timelines. Assets and metadata stay at the project root;
sync-timelinesrepairs in the active → root direction (#50).
Install
npm install -g capcut-cli@0.26.1
capcut --versionVerification and compatibility
All 1,017 tests passed locally. CI passed on Node 18/20/22 and Windows/macOS/Linux, including the capability-free Wasm component. The packed npm release was installed separately and checked against the three fixes.
The active-timeline change is scoped to the evidenced Windows 8.7.0 layout. Other builds retain their existing behavior. A patched CapCut desktop open/close confirmation remains pending in #50; file-level tests do not establish desktop compatibility.
See the end-to-end verification guide and changelog.
v0.26.0
Highlights
- Frame-grid linting and repair with
lint --frame-grid --fix. - Character-level Chinese/Japanese script alignment and a
--min-script-matchwrite gate. - Multi-stream transcription through
caption --audio-stream. - Boundary-safe ripple removal and partial-timeline shifting.
- Automatic FFmpeg filter scripts for large proxy renders.
- Nested OTIO timeline import.
- CRF or target-bitrate render controls.
- Editable progressive captions with
caption --word-reveal. - Atomic project-wide text styling with
restyle --preset.
Also included: richer draft-store diagnostics in doctor, a complete narrated-short workflow, and the new dependency-free Python client.
Install
npm install -g capcut-cli@0.26.0
pip install capcut==0.1.1See CHANGELOG.md for full behavior and compatibility details.