@clipwright/mcp-server 0.35.0 → 0.37.0
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.
- package/README.md +12 -10
- package/SKILL.md +381 -1015
- package/dist/format.js +3 -2
- package/dist/format.js.map +1 -1
- package/dist/server.d.ts +22 -0
- package/dist/server.js +61 -9
- package/dist/server.js.map +1 -1
- package/package.json +4 -5
- package/CHANGELOG.md +0 -1500
package/CHANGELOG.md
DELETED
|
@@ -1,1500 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
The four client packages — `@clipwright/core`, `@clipwright/sdk`,
|
|
4
|
-
`@clipwright/cli` and `@clipwright/mcp-server` — are released together and always
|
|
5
|
-
share one version, so each section below covers all four. The format follows
|
|
6
|
-
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The HTTP API reports its
|
|
7
|
-
contract version in the `X-Clipwright-Contract` response header and in the
|
|
8
|
-
`contract_version` field of a quote. Entries marked **Breaking:** require a change
|
|
9
|
-
on the client side. Entries marked *Server-side* changed the API itself: every
|
|
10
|
-
client version sees them from the day the API was deployed, not from the package
|
|
11
|
-
release they are listed under.
|
|
12
|
-
|
|
13
|
-
Entries marked *Dashboard:* changed the web app (the dashboard or a public page of the site)
|
|
14
|
-
and no package. This file is also the public changelog at /changelog, so they are listed here:
|
|
15
|
-
a customer reading it should not miss what appeared in the product. Like *Server-side* entries,
|
|
16
|
-
they are live from the day the web app was deployed, not from the package release they are
|
|
17
|
-
listed under.
|
|
18
|
-
|
|
19
|
-
## [Unreleased]
|
|
20
|
-
|
|
21
|
-
## [0.35.0] - 2026-10-30
|
|
22
|
-
|
|
23
|
-
### Changed
|
|
24
|
-
|
|
25
|
-
- The texts an agent reads describe the `parts-v1` tariff (#933). The `call` field says the call adds production
|
|
26
|
-
seconds and that a live-avatar still has its own price; the templates description and the remake plan's tariff
|
|
27
|
-
note drop the retired per-second rate. The MCP server's SKILL.md and the CLI README point to `list_prices` and the
|
|
28
|
-
quotes instead of fixed faceless prices, and the `quote_ugc` example shows `price_lines` for 12 s.
|
|
29
|
-
- *Dashboard:* /pricing lists only the presenter a request can get, and prints single images and clips as price
|
|
30
|
-
ranges per resolution without model names (#800). Two comparison pages are rewritten from the other products'
|
|
31
|
-
sites as read on 2026-10-30.
|
|
32
|
-
|
|
33
|
-
- *Server-side:* `make_ugc` is priced by its parts, one tariff `parts-v1` for short and long videos (#800): 12 credits
|
|
34
|
-
for every second a presenter take fills on HeyGen (22 on OmniHuman), plus 1 for every second of the finished video,
|
|
35
|
-
plus 400 for each live-avatar still of a call, at least 50 for a delivered video. A plain 35 s video costs 455
|
|
36
|
-
instead of 1 050. The quote itemizes it in `price_lines` and names `minimum_credits`; the terms are frozen at
|
|
37
|
-
admission, so a run admitted before keeps its own.
|
|
38
|
-
- *Server-side:* `analyze_reference` costs 70 credits (#927): held at the start and charged once the analysis
|
|
39
|
-
succeeds; a failed analysis costs nothing, and starting it again on the same asset answers the same analysis for
|
|
40
|
-
free. The analysis carries `credits_reserved`, `credits_charged` and `balance_after_credits`.
|
|
41
|
-
- *Server-side:* single generations are priced at ×2.5 of their cheapest route instead of ×2: an image from 6 credits,
|
|
42
|
-
a clip from 6 credits a second. `seedance-2.0-mini` is rendered by one route only.
|
|
43
|
-
- *Server-side:* `make_faceless` is priced by its parts, tariff `faceless-parts-v1` (#800): 7 credits for each picture
|
|
44
|
-
we generate, the opening clip's still included, 49 for the opening clip and 1 for every second of the delivered
|
|
45
|
-
video, at least 50. Your own pictures are not charged. The quote is the most a selection is charged: 212 at 30 s,
|
|
46
|
-
356 at 90 s, instead of 350 and 420. `faceless_billing` names `images` and `imageCredits`; a run admitted before
|
|
47
|
-
keeps its tariff.
|
|
48
|
-
- *Server-side:* edits and personal actors are repriced at ×2.5 of their cost (#800): a revision's new picture 7, clip
|
|
49
|
-
49, clip with a new picture 56, render 13, and a shot candidate the same unit prices; an actor's portrait 4 and each
|
|
50
|
-
other format 8 at `medium`, 12 and 18 at `high`. Runs admitted before keep their snapshot.
|
|
51
|
-
|
|
52
|
-
### Added
|
|
53
|
-
|
|
54
|
-
- *Server-side:* `POST /v1/reference-analyses/quote`, the `quote_analysis` tool and `ClipwrightClient.quoteAnalysis()`
|
|
55
|
-
price an analysis before it starts (#927).
|
|
56
|
-
- *Server-side:* every settled run carries `balance_after_credits`, the account's balance read in the transaction
|
|
57
|
-
that settled it (#927).
|
|
58
|
-
|
|
59
|
-
- *Server-side:* `GET /v1/public/prices` lists the price of every action in credits, without a key: one entry per tool
|
|
60
|
-
and variant, its price as lines of credits per unit plus a minimum, or a formula; free tools are listed at 0. No price
|
|
61
|
-
changed (#927).
|
|
62
|
-
- The `list_prices` tool and `ClipwrightClient.listPrices()` read that list, and the description of every paid tool
|
|
63
|
-
ends with its price line, built from the same list.
|
|
64
|
-
- `@clipwright/core` exports `PRICE_LIST`, `priceLine` and `pricesResponse`, with the constants the list reads:
|
|
65
|
-
`CREDITS_PER_SECOND`, `ACTOR_UNIT_CREDITS`, `EDIT_UNIT_PRICES`, `EDIT_RENDER_PRICE`, `EDIT_ZERO_UNIT_PRICE` and the
|
|
66
|
-
numbers of the faceless tariff.
|
|
67
|
-
|
|
68
|
-
- *Server-side:* `GET /openapi.json` serves an OpenAPI 3.1 description of the REST API without a key: every public
|
|
69
|
-
route with its request and response schemas, the error envelope and `warnings[]`. The API's own tests check
|
|
70
|
-
their real responses against it.
|
|
71
|
-
- `@clipwright/core/openapi` exports `buildOpenApiDocument()` and the route marking `OPENAPI_ROUTES`;
|
|
72
|
-
`@clipwright/core` exports `ENDPOINT_NOTES`, `healthResponse` and `publicSkillsResponse`.
|
|
73
|
-
- `make_ugc` takes `voice_pace` (0.7–1.2): `eleven_flash_v2_5` and `eleven_turbo_v2_5` get it as their speed,
|
|
74
|
-
`gemini-3.8-flash-tts` as a "speaking rapidly" or "speaking slowly" style with a warning. `eleven_v4` has no speed
|
|
75
|
-
setting: it gets no speed, and a `voice_pace` other than 1 is named in `warnings[]` (#890).
|
|
76
|
-
- `list_voices` gives each English voice on `eleven_v4` its measured pace, `words_per_second`. On that model the voice
|
|
77
|
-
sets the pace, so pick the voice nearest a reference presenter's pace (#890).
|
|
78
|
-
- *Server-side:* all ElevenLabs speech goes to `eleven_v4`, now the model of every preset, catalog voice and raw
|
|
79
|
-
`voice_id`. `tts_model: "eleven_v3"` is still accepted: the run speaks `eleven_v4` and `warnings[]` says so.
|
|
80
|
-
`eleven_v4` gives no pause for a `<break>` tag, so the tag is cut with a warning on the default path too.
|
|
81
|
-
- `make_ugc` takes `pause_trim`, targets in seconds per gap class: after synthesis a pause longer than its target is cut
|
|
82
|
-
down to it inside silence only, with a crossfade, and word timings move with the audio. A joint that would click is
|
|
83
|
-
kept and named in `warnings[]`.
|
|
84
|
-
- *Server-side:* a reference analysis measures the presenter's voice from the words it already transcribes: pace,
|
|
85
|
-
pauses in three layers, hinge pauses, pitch and loudness range, in the profile's new `voice` section.
|
|
86
|
-
`plan_reference_remake` sets `voice_pace` from it on a model with a speed. On `eleven_v4` it sets none and, when
|
|
87
|
-
the voice is more than 5% off the presenter, names the measured voices nearer the presenter's pace (#890).
|
|
88
|
-
- `@clipwright/core` exports `referenceVoice`, the schema of that section, and `narrationPaceFromVoice`.
|
|
89
|
-
|
|
90
|
-
- *Dashboard:* a public `/captions` page plays every caption style on the same presenter and the same words, each
|
|
91
|
-
with the description `tools/list` gives it; the `caption_style` description links to the page.
|
|
92
|
-
- `SKILL.md` names every caption style and tells the agent to ask whether the user wants captions, to offer three
|
|
93
|
-
or four fitting styles with the gallery link, and to take the style closest to a reference video's captions.
|
|
94
|
-
- *Server-side:* `hormozi` now matches the canonical look: Montserrat Black uppercase, white with a thick black outline,
|
|
95
|
-
one yellow (`#FFD93D`) keyword per cue, up to three words. The previous look (condensed Oswald, orange keyword, no
|
|
96
|
-
outline) is the new style `accent`. `hormozi` stays the default; there are 24 styles.
|
|
97
|
-
- *Server-side:* `make_ugc` takes `edit_sounds: true` on a run with `inserts` or `layout_windows`: a low sound plays on
|
|
98
|
-
every cut, to or from an insert, at a full-frame template's cut in or out and at a layout window's in and out, with
|
|
99
|
-
its peak on the cut. `template_sounds.edit` picks it from `swell_hit` (default), `whoosh_deep`, `whoosh_low`,
|
|
100
|
-
`boom_low`, `sub_drop`, `riser_boom` and `riser_hit`. A cut that already plays a template's whoosh or flash gets no
|
|
101
|
-
second sound. Without the field a run plays no edit sounds, as before; `edit_sounds` with nothing to cut, with
|
|
102
|
-
`template_sounds: false`, or `template_sounds.edit` without `edit_sounds`, is refused 400 by its path before any
|
|
103
|
-
hold. The price does not change.
|
|
104
|
-
- *Server-side:* new template sounds: a `pop` (`plop`) when a `tag` or a `callout` pops in, a `hangup` (`phone`) just
|
|
105
|
-
before an answered `phone_call` leaves, and `money` (`cash_register`, `coins`) when a `stat` with a currency sign in
|
|
106
|
-
its prefix or suffix counts up. `answer` adds `pickup`, `whoosh` adds `slide_quick` and `flash` adds `swish`.
|
|
107
|
-
`list_template_sounds` lists them. A run frozen before them keeps its sounds.
|
|
108
|
-
- *Server-side:* `make_ugc` takes `framing`, presenter sizes on their words: `close` (1.18 times larger about the face)
|
|
109
|
-
or `medium`, each a hard cut that settles over 8 frames, or with `transition: "flash"` a warm light leak over the cut.
|
|
110
|
-
It needs long-form qualification, works without captions, refuses overlap with inserts, layout windows and other framing,
|
|
111
|
-
and names in `warnings[]` a framing wholly under full-frame templates. With `edit_sounds`, each framing cut plays the
|
|
112
|
-
edit sound. `plan_reference_remake` turns a `punch_in` camera into a close framing and a flash into a speaking beat
|
|
113
|
-
into a flashed one.
|
|
114
|
-
- `create_actor` takes `from_actor_id` with `framing: "wide"`, `holding` (one or two objects, each with words, an
|
|
115
|
-
optional image asset of the object and a hand) or `setting`: it derives a new personal actor from a library actor or
|
|
116
|
-
your own, with the same face checked against the source. A face that does not match costs nothing. The price is the
|
|
117
|
-
usual per-image units. *Server-side:* the fields are open only where `CLIPWRIGHT_ACTOR_VIEWS` is on; elsewhere they
|
|
118
|
-
are refused 400 `rejected_field`. A wide derived actor's 9:16 is listed with `framing: "wide"`, and `make_ugc`
|
|
119
|
-
renders it as a wide view. `@clipwright/core` exports `storedActorSource`, `storedHoldingItem`,
|
|
120
|
-
`createActorDispositions`, `createActorRejectedFields` and `isActorViewsEnabled`.
|
|
121
|
-
|
|
122
|
-
### Changed
|
|
123
|
-
|
|
124
|
-
- *Server-side:* the template sound library is re-recorded from CC0 sounds the owner chose by ear: 25 of the 31 files
|
|
125
|
-
play a new recording under the same name; the rings, `glitch`, `switch_heavy` and `paper_swipe` stay as they were.
|
|
126
|
-
Every source is named in `THIRD_PARTY_NOTICES`.
|
|
127
|
-
|
|
128
|
-
## [0.34.0] - 2026-10-24
|
|
129
|
-
|
|
130
|
-
### Added
|
|
131
|
-
|
|
132
|
-
- `@clipwright/core` exports `PUBLIC_MCP_URL`, the hosted MCP server address `https://mcp.clipwright.io/mcp`.
|
|
133
|
-
- *Dashboard:* a public `/mcp` page answers "Yes, Clipwright has an MCP server": the hosted address with the
|
|
134
|
-
`claude mcp add` command (sign in, no key), the local package with a key, and the tool list. `llms.txt` names the
|
|
135
|
-
hosted MCP address, the `/mcp` page and the CLI. The home page and `/pricing` carry schema.org data with the price
|
|
136
|
-
of the cheapest credit pack, and the sitemap dates the comparison pages by the day their facts were checked.
|
|
137
|
-
|
|
138
|
-
- *Server-side:* video assets. An MP4 in h264 or hevc up to 120 seconds and 100 MB comes from an own `generate_video`
|
|
139
|
-
run, a public url (`{ url, kind: "video" }`), a presigned PUT (`{ put: { media_type, bytes, sha256 } }`, also for
|
|
140
|
-
pictures) or `POST /v1/assets/bytes` up to 32 MB. A url or a PUT answers `202` with `state: "processing"` or
|
|
141
|
-
`"awaiting_upload"`; the worker task `ingest-asset-media` measures frames, fps, codec and `pix_fmt` from the bytes
|
|
142
|
-
and publishes the asset, and `GET /v1/assets/{id}` says `ready` or `failed` with the reason. Clips are kept for
|
|
143
|
-
assembly and are no generation reference.
|
|
144
|
-
- MCP: `create_asset` takes `put` and a url clip; on stdio a local MP4 `path` is uploaded through a PUT.
|
|
145
|
-
- `generate_video` and `quote_video` take an optional `camera`: `static`, `push_in`, `pull_back` or `pan`. It
|
|
146
|
-
becomes the first line of the prompt the model gets and does not change the price.
|
|
147
|
-
- `GET /v1/generations/models` lists `duration_values` for a model that takes only some lengths inside its
|
|
148
|
-
`duration_s` range; the schema and the quote refuse the others. The resolution `360p` is part of the contract.
|
|
149
|
-
- New clip models: `kling-3.0` at 720p in 9:16 and 16:9, 3 to 15 seconds, and `gemini-omni-flash-1.1` at 720p in both
|
|
150
|
-
formats and 360p 16:9, for 4, 6, 8 or 10 seconds. `seedance-2.5` adds 480p 9:16 and 720p 16:9.
|
|
151
|
-
- *Server-side:* a clip refused for a real face in its input picture, or turned away as rate-limited before it was
|
|
152
|
-
accepted, is made by a second provider at the same quote where that row was measured there. A clip is always
|
|
153
|
-
delivered without an audio track.
|
|
154
|
-
- *Dashboard:* the Assets page. It lists the account's pictures and clips in a grid of small, medium or large tiles,
|
|
155
|
-
with filters by role and kind, a name search and the usage of the 2,000 assets and 20 GB. A selected asset opens on
|
|
156
|
-
the right: rename it, change its role, copy its `asset_id`, open the file or delete it. Pictures up to 10 MB and MP4
|
|
157
|
-
clips up to 32 MB upload from the page; a clip shows as processing until it is checked.
|
|
158
|
-
- *Server-side:* each asset gets a preview of at most 512 pixels on the long side, made by the worker after the asset
|
|
159
|
-
is saved and caught up hourly. The Assets page shows the preview, never the original, in its grid. The API does not
|
|
160
|
-
return the preview yet.
|
|
161
|
-
- *Server-side:* more clip formats. `seedance-2.0` adds 480p in 9:16 and 16:9 at 18 credits a second and 720p 16:9;
|
|
162
|
-
`seedance-2.0-fast` adds 480p in both formats and 720p 16:9; `seedance-2.0-mini` and `seedance-2.5` add 480p 16:9.
|
|
163
|
-
The 480p clip of `seedance-2.0`, `-mini` and `-fast` is 496×864 or 864×496, and `warnings[]` says so.
|
|
164
|
-
- A `make_ugc` image insert can name `asset_id` instead of `media_url`, exactly one of the two. The quote and the run
|
|
165
|
-
accept only a ready PNG or JPEG asset of the same account, with a `media_type` that matches it. A foreign, deleted
|
|
166
|
-
or unfinished asset answers `400 reference_not_usable` before any credits are reserved. The worker reads the
|
|
167
|
-
file admission recorded and checks its sha256, so a later delete does not change a started run.
|
|
168
|
-
- `get_run` in the MCP server returns `created_actor` on a succeeded `create_actor` run, so an agent sees the
|
|
169
|
-
`actor_id` to pass to `make_ugc`.
|
|
170
|
-
- `make_ugc` takes `overlays`: pictures anchored to words like inserts, drawn over the presenter in a corner or as a
|
|
171
|
-
band across the top or bottom, entering with `cut`, `fade`, `slide` or `tilt_in`. At most two show at once, and two
|
|
172
|
-
on screen together need positions that share no corner. Captions move to the middle or the bottom of the frame when
|
|
173
|
-
an overlay meets them, never up over the face, and hide when neither place is free. An overlay steps aside while a full-frame insert is on screen, and one wholly under inserts is refused.
|
|
174
|
-
- `make_ugc` takes `layout_windows`: `split` puts the presenter in the top half and the picture in the bottom half with
|
|
175
|
-
captions on the seam (9:16 only); `card` shows the picture in a centred card, and `blur_presenter` blurs the
|
|
176
|
-
presenter behind it. Windows may not overlap one another or an insert.
|
|
177
|
-
- Inserts take `transition`: `cut`, `wipe`, `flash` or `zoom`. It plays inside the insert's own frames and never moves
|
|
178
|
-
its start or end. A `caption_emphasis` item takes `punch_in: true` to zoom into the presenter while the quote is
|
|
179
|
-
spoken.
|
|
180
|
-
- *Server-side:* overlays and layout windows follow the insert rules: `script`, long-form qualification, 1080p and
|
|
181
|
-
`broll_policy=anyone`, exactly one of `media_url` and `asset_id`, and ids unique across inserts, overlays and
|
|
182
|
-
windows. A script with overlays or windows alone runs as long form. They change
|
|
183
|
-
neither the presenter's slots nor the price: a blurred or covered presenter is billed face time. A run whose
|
|
184
|
-
composition is off, skipped or failed names undrawn overlays, windows, transitions and punch-in in `warnings[]`.
|
|
185
|
-
- `make_ugc` inserts, overlays and layout windows take `media_type: "video"`, by `media_url` or by the `asset_id` of an
|
|
186
|
-
MP4 asset. The clip plays muted from its first frame and is cut by time where its words end, so a variable frame
|
|
187
|
-
rate does not shift it. A clip shorter than its words holds its last frame, and `warnings[]` names the insert or
|
|
188
|
-
layer: in the quote for an `asset_id` the slow speech edge may outlast, otherwise on the run. H.264 and HEVC in 8 bits
|
|
189
|
-
without HDR are accepted.
|
|
190
|
-
- *Server-side:* a 10-bit video asset answers `400 reference_not_usable` before any credits are reserved. A
|
|
191
|
-
`media_url` clip, and the colour transfer of an asset clip, are measured by the worker before the first paid call:
|
|
192
|
-
another codec, 10 bits or more, or a PQ or HLG transfer fails the run uncharged with `media_source_rejected` naming
|
|
193
|
-
the insert or layer. A video `segments` item is still refused. Customer video costs nothing: the same script with a
|
|
194
|
-
picture or a clip quotes and bills the same face seconds.
|
|
195
|
-
- *Server-side:* graphic templates on `make_ugc`. `templates[]` takes up to 12 items
|
|
196
|
-
`{ id, kind, anchor, cover_words?, placement?, transition?, data }` of three kinds: `tag` (a gradient pill, also
|
|
197
|
-
over an insert), `lower_third` (a name and role bar) and `end_card` (a site pill with an optional call to action);
|
|
198
|
-
captions are hidden under the last two and under a tag without `position`, which sits in the caption spot. Each kind
|
|
199
|
-
takes `size` small, medium (the default) or large, and long text shrinks to fit. Templates are accepted on any
|
|
200
|
-
`script` run without `segments` and never change its tariff or price: a plain run is billed 30 credits a second of
|
|
201
|
-
finished video, and a run with inserts, overlays or layout windows is billed long-form-v1 (#840). Text over its
|
|
202
|
-
limit (a wide CJK character counts 2), emoji, letters the run's fonts cannot draw, overlapping footprints and the
|
|
203
|
-
other refusals answer 400 with a path before any hold. `@clipwright/core` exports the catalog (`TEMPLATE_KINDS`)
|
|
204
|
-
and `@clipwright/mcp-server` offers a slim template item with the catalog in its description.
|
|
205
|
-
- *Server-side:* full-frame templates and template pictures. `title_card` (a hook card: a title in up to two lines on
|
|
206
|
-
a white card, an optional logo picture shown whole and a gradient chip) and `quote` (up to four lines, an author and
|
|
207
|
-
an optional round photo) fill the frame; `stat` counts a number up from zero, on a full frame or over the presenter.
|
|
208
|
-
A full-frame template hides captions, overlays and over-presenter templates while it shows, takes a `wipe`, `flash`
|
|
209
|
-
or `zoom` drawn over the live presenter, and on a long-form run the presenter under it is still billed as face time.
|
|
210
|
-
`logo` and `photo` take `{ asset_id }`: pinned at admission under the template id and slot, a video or another
|
|
211
|
-
account's asset is refused 400 `reference_not_usable` before any hold, and a photo cut to its circle is named in
|
|
212
|
-
`warnings[]`. On a plain run a template picture needs explicit `broll_policy=anyone`, like a layer (#840).
|
|
213
|
-
- *Server-side:* templates on a plain script run (#840). A `script` run without inserts, overlays or layout windows
|
|
214
|
-
takes `templates`, `template_theme` and `template_sounds` at 30 credits a second, with no minimum and no face
|
|
215
|
-
seconds. The templates are drawn over its one take; if they cannot be drawn, the video is delivered at the same
|
|
216
|
-
price and `warnings[]` says `templates was not drawn: <reason>`.
|
|
217
|
-
- Quotes carry `tariff`: `ugc-per-second-v1` on a plain run, or long form's `pricingVersion` (`long-form-v1`). The
|
|
218
|
-
field is an optional string, so older clients and stored quotes still parse; templates never change it.
|
|
219
|
-
- *Server-side:* the `callout` template and template looks. `callout` draws an arrow or a ring onto a point given
|
|
220
|
-
as `target { x, y }` in percent of the frame, pulses twice and rests, with an optional label pill below the point,
|
|
221
|
-
or above it when there is no room or the face is below; the point may sit anywhere, the face rule covers the label.
|
|
222
|
-
A run-level `template_theme { preset?, accent? }` picks `clean_light` (the default when absent) or `bold_dark`, and
|
|
223
|
-
`accent` takes a `#RRGGBB` colour for the pills and accent text. A customer accent under 3:1 against the colours it
|
|
224
|
-
meets is refused 400 at `template_theme.accent` before any hold, never shifted. The look freezes into the timeline,
|
|
225
|
-
so a resumed run draws what it was admitted with, and footprints come from the frozen kind version.
|
|
226
|
-
- *Server-side:* three interactive templates with inner quotes. `checklist` draws 2–4 rows of switches or check boxes
|
|
227
|
-
that a cursor clicks in turn; `phone_call` rings an incoming call on a neutral phone at the side and answers it; and
|
|
228
|
-
`compare` sweeps an after picture in over a before picture on a diagonal, full frame. An inner quote
|
|
229
|
-
(`clicks[].quote`, `answer_at`, `reveal_at`) names words inside the template's own: the click, answer or reveal lands
|
|
230
|
-
on their first word, and a click without one is spread evenly. A quote missing from the script, outside the item's
|
|
231
|
-
words, out of the script's order, or on words an insert or full-frame template covers is refused 400 by its path
|
|
232
|
-
before any hold. `compare` takes two pictures, pinned apart as `before` and `after`. Templates still change no price.
|
|
233
|
-
- *Server-side:* three more templates and three more looks. `notification` drops a phone notification (an icon, the
|
|
234
|
-
app, a title and a body line) into the band above the face, holds it at least 1.2 s and takes it away before its
|
|
235
|
-
span ends; `progress` completes 2–5 steps in turn, each on its `advance_at` quote (exactly one per step) or spread
|
|
236
|
-
evenly; `rating` fills five stars in turn up to a score in halves. `advance_at` is refused like the other inner
|
|
237
|
-
quotes, and a list of the wrong length too. `template_theme.preset` adds `neon`, `paper` and `mono`, and a customer
|
|
238
|
-
accent is checked against each look's own colours.
|
|
239
|
-
- *Server-side:* templates play sounds, well under the voice, from a library of 31 bundled with the composition: a
|
|
240
|
-
checklist click and its switch landing, a phone ringing until it is answered and the answer, a notification dropping
|
|
241
|
-
in, each progress step and rating star, a compare reveal, and a full-frame wipe, zoom or flash. A run plays the
|
|
242
|
-
defaults; `template_sounds: { beat: name }` swaps a beat's sound and `template_sounds: false` plays none. An unknown
|
|
243
|
-
beat or name, or `template_sounds` without templates, is refused 400 by its path before any hold. `GET
|
|
244
|
-
/v1/template-sounds` and the MCP tool `list_template_sounds` list each beat, its default and its names, free. A run
|
|
245
|
-
frozen before this plays none. Sounds change no price. `@clipwright/sdk` adds `listTemplateSounds()`.
|
|
246
|
-
|
|
247
|
-
### Changed
|
|
248
|
-
|
|
249
|
-
- *Server-side:* in `mono` the callout's ring and arrow have a white outline, so they read over a dark suit.
|
|
250
|
-
- *Server-side:* a template beat spoken before its template has entered (a checklist click before its rows and cursor are
|
|
251
|
-
in, or an answer, step or reveal during the enter) moves to the first frame after the enter, the beats after it keep
|
|
252
|
-
6 frames apart, and `warnings[]` names each move. Runs already rendered keep their frames.
|
|
253
|
-
- *Server-side:* captions and the light template look are blue, with no purple: the two-tier and pill captions and the
|
|
254
|
-
`punch` keyword use the reference's periwinkle-to-sky blue, `clean_light` follows it, `bold_dark` sits on a neutral
|
|
255
|
-
near-black ground, `checklist` switches are green when on and red when off in every look, and the `phone_call` screen
|
|
256
|
-
is the device's own teal-to-blue.
|
|
257
|
-
- *Server-side:* a template no longer moves captions. While it meets their band it hides them, as the checklist and
|
|
258
|
-
the phone do; a small one elsewhere, such as a notification at the top, leaves them on screen.
|
|
259
|
-
- *Server-side:* `generate_image` and `generate_video` cost less. A `seedream-5.0-flash` image costs 5 credits instead
|
|
260
|
-
of 12 and a `flare` image 6 instead of 18; a second of `seedance-2.0-mini` at 720p costs 10 instead of 50,
|
|
261
|
-
`seedance-2.0` at 1080p 91 instead of 250, `kling-3.0` 17 instead of 50 and `gemini-omni-flash-1.1` 19 instead of 55.
|
|
262
|
-
A run already admitted keeps its quoted price.
|
|
263
|
-
- *Server-side:* a second of `seedance-2.5` at 480p costs 25 credits instead of 34.
|
|
264
|
-
- *Server-side:* every delivered video is encoded once, at a quality setting chosen by eye on text frames, so a
|
|
265
|
-
35-second 1080×1920 video is about 11 MB instead of 27 MB. The resolution is unchanged (#845).
|
|
266
|
-
|
|
267
|
-
### Fixed
|
|
268
|
-
|
|
269
|
-
- *Server-side:* a dropped connection while the worker checks on an ordered `make_ugc` clip no longer fails the run
|
|
270
|
-
and charges for it. The worker checks again until its wait deadline, and a run that stays cut off ends with no charge.
|
|
271
|
-
|
|
272
|
-
## [0.33.0] - 2026-10-20
|
|
273
|
-
|
|
274
|
-
### Added
|
|
275
|
-
|
|
276
|
-
- *Server-side:* `POST /v1/uploads/import` downloads a public https PNG or JPEG (up to 10 MB, 20 seconds, up to 3
|
|
277
|
-
redirects) and returns an `upload_id`; private and link-local addresses are refused, and downloads are limited to 30
|
|
278
|
-
attempts per hour per account.
|
|
279
|
-
- *Server-side:* `POST /v1/uploads/intents` returns a presigned PUT url for a local PNG or JPEG; the `upload_id`
|
|
280
|
-
becomes usable once the PUT lands, and `GET /v1/uploads/{id}` confirms it. Before the PUT, generations answer
|
|
281
|
-
`upload_not_finished`.
|
|
282
|
-
- MCP: `upload_image` takes `url`, and the new `create_upload` and `get_upload` tools work on the hosted server, so a
|
|
283
|
-
remote agent can pass its own picture as `first_frame` or a reference.
|
|
284
|
-
- *Server-side:* account assets, switched on since 2026-10-20. `POST /v1/assets` saves a picture from an own
|
|
285
|
-
`generate_image` run, an upload, a public https url or base64, kept until the customer deletes it, and
|
|
286
|
-
`{ asset_id }` works in `references` of both generations and in `first_frame` and `last_frame` of `generate_video`. `GET /v1/assets`,
|
|
287
|
-
`GET /v1/assets/{id}`, `POST /v1/assets/{id}` and `DELETE /v1/assets/{id}` list, read, rename and delete them; an
|
|
288
|
-
account keeps up to 2000 assets and 20 GB and makes up to 100 new ones a day. Free.
|
|
289
|
-
- MCP: `create_asset`, `list_assets`, `get_asset`, `update_asset` and `delete_asset`; SDK: `createAsset`,
|
|
290
|
-
`createAssetFromBytes`, `listAssets`, `getAsset`, `updateAsset` and `deleteAsset`.
|
|
291
|
-
|
|
292
|
-
### Changed
|
|
293
|
-
|
|
294
|
-
- MCP: on the hosted server, `upload_image` with a `path` now points to `upload_image({url})` and `create_upload`
|
|
295
|
-
instead of `quote_ugc`.
|
|
296
|
-
- The n8n workflow `n8n/clipwright-ugc.json` carries sticky notes: an overview with setup and requirements, and one
|
|
297
|
-
note per step, as n8n's template gallery asks. Its whole path, render included, ran on n8n Cloud on 2026-10-20.
|
|
298
|
-
|
|
299
|
-
### Fixed
|
|
300
|
-
|
|
301
|
-
- SDK, CLI and MCP no longer retry `url_import_disabled` and `assets_disabled`: both mean the feature is switched off,
|
|
302
|
-
and a repeat gets the same answer.
|
|
303
|
-
- `upload_not_finished` tells the agent to PUT the file to its `put_url`, confirm it with `get_upload`, and repeat
|
|
304
|
-
the call.
|
|
305
|
-
- *Server-side:* a generation whose `first_frame` or `last_frame` names an unknown source fails before any vendor
|
|
306
|
-
call, at zero credits, instead of running without the frame.
|
|
307
|
-
|
|
308
|
-
## [0.32.0] - 2026-10-20
|
|
309
|
-
|
|
310
|
-
### Added
|
|
311
|
-
|
|
312
|
-
- The public repository ships an n8n workflow, `n8n/clipwright-ugc.json`, built on n8n's own MCP Client node with
|
|
313
|
-
an API key; no community node is needed. It quotes a script, stops when the quote is above `max_credits`, starts the
|
|
314
|
-
render and polls `get_run` every 15 seconds until the run ends. The quote and polling steps ran in n8n 2.43.8; the
|
|
315
|
-
render step and n8n's OAuth credential have not been tried. Setup is in the `@clipwright/mcp-server` README.
|
|
316
|
-
- The public repository is a Claude Code and Cursor plugin marketplace: `claude plugin marketplace add
|
|
317
|
-
seocombat/clipwright-mcp`, then `claude plugin install clipwright@clipwright`. The plugin connects the hosted server
|
|
318
|
-
at `https://mcp.clipwright.io/mcp`, which signs in with OAuth, and adds a skill that quotes before it spends credits.
|
|
319
|
-
- `SKILL.md` in `@clipwright/mcp-server` carries OpenClaw frontmatter: it needs `node` and `npx` and reads
|
|
320
|
-
`CLIPWRIGHT_API_KEY`. The skill is on ClawHub as `seocombat/clipwright`.
|
|
321
|
-
- The four packages name their source repository, `seocombat/clipwright-mcp`, in `package.json`.
|
|
322
|
-
- `@clipwright/core` exports `facelessMaxGeneratedImages` and `FACELESS_PUBLIC_MAX_GENERATED_IMAGES` (31): how many
|
|
323
|
-
pictures a faceless video may generate, one per two selected seconds plus four.
|
|
324
|
-
- *Server-side:* single generations are on since 2026-10-19: `quote_image`, `generate_image`, `quote_video` and
|
|
325
|
-
`generate_video` no longer answer `generations_disabled`. The 0.31.0 entry announced them as pending.
|
|
326
|
-
- *Dashboard:* credits come in three one-time packs: 1,000 for $10, 2,750 for $25 and 6,000 for $50. The dashboard
|
|
327
|
-
has one buy button per pack, and a payment buys one pack.
|
|
328
|
-
- *Dashboard:* the landing page is rebuilt. It starts with installing Clipwright in your agent, then shows the kinds
|
|
329
|
-
of video an agent can make with their prices, a quickstart, a real run, actors and voices, and the three packs.
|
|
330
|
-
|
|
331
|
-
## [0.31.0] - 2026-10-19
|
|
332
|
-
|
|
333
|
-
### Added
|
|
334
|
-
|
|
335
|
-
- *Server-side:* the remote MCP server at `https://mcp.clipwright.io/mcp` signs in with OAuth 2.1 and needs no API key.
|
|
336
|
-
A client registers itself, either with a metadata document or with dynamic registration. You approve it at
|
|
337
|
-
app.clipwright.io, and its token carries `mcp:read`, or `mcp:write` for tools that spend credits. Headless agents
|
|
338
|
-
sign in with a device code as the client `clipwright-agent`.
|
|
339
|
-
- *Dashboard:* the API keys page lists your connected apps and revokes them, effective on the app's next request.
|
|
340
|
-
Signing in and signing up return you to the page that sent you there.
|
|
341
|
-
- `@clipwright/mcp-server` exports `createServer(client, { fileAccess })`, so the same tools can be served over HTTP;
|
|
342
|
-
with `fileAccess: "refuse"`, `upload_image` refuses a local `path`. `ClipwrightClient` in the SDK takes an explicit
|
|
343
|
-
`clientId` (it then ignores `CLIPWRIGHT_CLIENT_ID` and `~/.clipwright`) and an `apiKey` function called per
|
|
344
|
-
request. *Server-side:* a new error code, `insufficient_scope` (403).
|
|
345
|
-
- *Server-side (activation pending):* new jobs admitted with required output marking verify signed provenance and a separate
|
|
346
|
-
hidden watermark before delivering generated MP4/PNG/JPEG files; unverifiable required output is withheld with zero charge
|
|
347
|
-
for the failed delivery. Optional `visible_ai_label` defaults to true for newly marked presenter videos, including long form;
|
|
348
|
-
false hides only the visible label. Required machine marking stays enabled, and original uploads and historical files remain
|
|
349
|
-
unchanged. Public contract version: `2026-10-18`. Marking is closed and the P2 video profile remains inactive pending native
|
|
350
|
-
qualification; this entry does not announce deployment or activation.
|
|
351
|
-
- *Server-side (activation pending):* single paid generations. `generate_image` makes one image and `generate_video`
|
|
352
|
-
makes one silent clip from a prompt, with optional reference images or a first frame. MCP tools: `list_generation_models`,
|
|
353
|
-
`quote_image`, `generate_image`, `quote_video` and `generate_video`. SDK methods: `listGenerationModels`, `quoteImage`,
|
|
354
|
-
`generateImage`, `quoteVideo` and `generateVideo`. An image costs one unit; a clip is priced per requested second. A
|
|
355
|
-
failed generation costs nothing. The routes answer `generations_disabled` until the feature is switched on; this entry
|
|
356
|
-
does not announce activation.
|
|
357
|
-
|
|
358
|
-
- *Server-side:* upload responses and the upload list include `content_digest`, the SHA-256 of the original bytes, alongside
|
|
359
|
-
`upload_id`. CLI `upload --json` prints both for direct workflow asset binding; the default still prints the URL.
|
|
360
|
-
SDK and MCP preserve the metadata, and the workflow docs show how to copy it without a digest lookup.
|
|
361
|
-
Hand-built TypeScript `UploadResponse` values, including mocks, must supply the new required digest.
|
|
362
|
-
- Edit rules for long videos in `@clipwright/core`. The rules gain `cover_min_frames`, the shortest picture over a
|
|
363
|
-
presenter take and the shortest presenter gap between two such pictures; it is `null` where it does not apply, and
|
|
364
|
-
read as `null` when absent. `upload_aspect` may be `{ mode: "exact", epsilon }`, and `max_generated_per_revision`
|
|
365
|
-
may be 0. *Server-side:* `GET /v1/runs/{id}/shots` of a long video carries these rules; the video stays view-only.
|
|
366
|
-
- **Breaking:** `SKILLS` gains `revise_long_form`, the revision of a long video that a later release opens. Code with
|
|
367
|
-
an exhaustive `Record<Skill, …>` or `switch` over skills must add it. No run of this skill exists yet.
|
|
368
|
-
- *Server-side:* four workflow methods now render: `ugc-product-intro`, `ugc-faq-answer`, `faceless-explainer` and
|
|
369
|
-
`product-image-story`. `plan-run` in the CLI, `run_workflow_plan` in MCP and `runWorkflowPlan` in the SDK buy the
|
|
370
|
-
quoted plan, charged like the video type the method makes. `website-proof-demo` and `kinetic-launch` still only
|
|
371
|
-
plan.
|
|
372
|
-
- *Dashboard:* the quickstart names the four workflow methods, and the Workflows section of the docs shows the CLI
|
|
373
|
-
steps from a method's example to a finished run, and how to add your own product photos.
|
|
374
|
-
- *Dashboard:* a link to clipwright.io shared in a chat, a social post or a directory shows a preview picture: the
|
|
375
|
-
Clipwright mark and name.
|
|
376
|
-
|
|
377
|
-
### Changed
|
|
378
|
-
|
|
379
|
-
- *Dashboard:* a long video's button says **View** instead of **Edit**, because the editor only shows long videos for
|
|
380
|
-
now. The button appears only while the API shows long videos.
|
|
381
|
-
|
|
382
|
-
### Fixed
|
|
383
|
-
|
|
384
|
-
- The SDK reads server responses tolerantly: a field that a newer server adds to a quote, the generation models list,
|
|
385
|
-
a run or a workflow answer no longer makes `ClipwrightResponseError` throw in an installed client. A response
|
|
386
|
-
missing a required field still fails.
|
|
387
|
-
- *Server-side:* UGC output evidence accepts the measured AAC-LC tail beyond the last video frame, up to two
|
|
388
|
-
AAC frames at the measured sample rate. It retains the container duration and existing billing behavior.
|
|
389
|
-
- *Server-side:* a short UGC video is charged for its picture, not for the audio that runs past the last frame.
|
|
390
|
-
An 8.96-second video whose AAC track ends 0.04 s later was charged for 10 seconds; it is now charged for 9.
|
|
391
|
-
`duration_seconds` still reports the file's full length.
|
|
392
|
-
- *Server-side:* UGC workflow quotes explicitly warn that duration and credits are estimates, so the final charge
|
|
393
|
-
may differ. Short UGC keeps measured-duration rounding; long-form keeps its separate frozen face-time tariff.
|
|
394
|
-
SDK, CLI and MCP retain the advice in the native quote warnings. Billing calculations are unchanged.
|
|
395
|
-
- UGC workflow outcomes expose the measured final-file format, duration and
|
|
396
|
-
digest after verified delivery. Missing or damaged evidence stays explicit;
|
|
397
|
-
the native video result and settlement remain available.
|
|
398
|
-
- *Server-side:* generated scenes in `product-image-story` use up to two distinct original product photos as
|
|
399
|
-
references, including the opener image. The first anchors shape; extra originals keep their image placements.
|
|
400
|
-
Plan readiness and the quote disclose the selection and possible visual differences. Older paid checkpoints
|
|
401
|
-
reuse their existing scenes with a warning when product-photo conditioning cannot be verified. Revisions and
|
|
402
|
-
candidates retain that known limitation through later edits.
|
|
403
|
-
- The examples of `ugc-product-intro` and `ugc-faq-answer` named the actor `actor_male`, which does not exist, so a
|
|
404
|
-
plan built from either example was refused at the quote with `actor_unavailable`. They name `actor_marcus` now. Both
|
|
405
|
-
cards get a new `content_digest`; a plan pinned to the old one needs a new revision.
|
|
406
|
-
|
|
407
|
-
## [0.30.0] - 2026-10-17
|
|
408
|
-
|
|
409
|
-
### Added
|
|
410
|
-
|
|
411
|
-
- Upload list: `listUploads` in the SDK and `uploads` in the CLI read the account's uploads that a revision still
|
|
412
|
-
takes, newest first and one per picture. Each comes with a freshly signed url and `usable_until`, its creation plus
|
|
413
|
-
30 days of storage less a two-hour margin. Free. *Server-side:* `GET /v1/uploads`.
|
|
414
|
-
- *Dashboard:* the editor's **Edit shot** dialog makes a new picture or clip for one shot and shows it beside the one in
|
|
415
|
-
the video; you keep it or discard it. A result costs its price once it is made, kept or discarded; nothing if it fails.
|
|
416
|
-
**Replace with a file** and the **Uploads** tab place your own picture in a shot at no cost, and **Generated assets**
|
|
417
|
-
lists what you made for the video.
|
|
418
|
-
- *Dashboard:* long videos open in the editor to view. Each presenter take and each inserted picture or clip is a shot
|
|
419
|
-
you can select and play, with the words said over it; a take also shows how many seconds of the video have the face
|
|
420
|
-
on screen. Editing long videos comes later. *Server-side:* `GET /v1/runs/{id}/shots` answers a delivered long-form
|
|
421
|
-
run with `planned: true` and the new `editable.state` `view_only`; a draft save of such a run gets 409
|
|
422
|
-
`run_not_editable`.
|
|
423
|
-
|
|
424
|
-
### Fixed
|
|
425
|
-
|
|
426
|
-
- *Server-side:* uploads made before 2026-10-05T19:49Z are no longer listed or taken by a revision. The storage rule of
|
|
427
|
-
that time deleted their files after 7 days, so a revision that named one failed at no charge.
|
|
428
|
-
|
|
429
|
-
## [0.29.0] - 2026-10-16
|
|
430
|
-
|
|
431
|
-
### Added
|
|
432
|
-
|
|
433
|
-
- Workflow plans: a method from the public workflow catalog becomes a plan that you prepare, save, approve and
|
|
434
|
-
quote for free, and then start as one paid UGC or faceless run with an explicit idempotency key. `listWorkflows`,
|
|
435
|
-
`getWorkflow`, `createWorkflowPlan`, `getWorkflowPlan`, `saveWorkflowPlan`, `approveWorkflowPlan`,
|
|
436
|
-
`quoteWorkflowPlan` and `runWorkflowPlan` in the SDK; `workflows`, `workflow-show`, `plan-create`, `plan-show`,
|
|
437
|
-
`plan-save`, `plan-approve`, `plan-quote` and `plan-run` in the CLI; the MCP tools `list_workflows`, `get_workflow`,
|
|
438
|
-
`prepare_workflow_plan`, `get_workflow_plan`, `approve_workflow_plan`, `quote_workflow_plan` and
|
|
439
|
-
`run_workflow_plan`. Approval and the paid start are separate explicit calls; nothing quotes, approves or starts on
|
|
440
|
-
its own. A method starts only once it is enabled on the server; until then its availability says why. `getRun` of a
|
|
441
|
-
workflow run carries the purchased plan revision and its receipt. *Dashboard:* the videos list labels a workflow
|
|
442
|
-
run with its plan, method and revision. (clipwright#631)
|
|
443
|
-
- *Dashboard:* the editor of a faceless video edits its draft: move a cut by dragging it or with the keys, set a shot's
|
|
444
|
-
start, end or length, start or end it on a word, remove a picture, and regenerate a picture or describe a new one.
|
|
445
|
-
The draft saves itself. "Copy as API call" copies the revision as `curl` and as the MCP `revise_run` call, and
|
|
446
|
-
"Render new version" shows the quote and starts the revision, which the header then follows to "Version ready".
|
|
447
|
-
An answer that does not come is held in the browser, so a retry starts no second revision. (clipwright#604)
|
|
448
|
-
- A shot of a faceless video can get a candidate: one picture or clip made for that shot, to keep or discard in a
|
|
449
|
-
revision. `quoteCandidate`, `createCandidate` and `listCandidates` in the SDK, `candidate-quote`, `candidate` and
|
|
450
|
-
`candidates` in the CLI, and the MCP tools `quote_candidate` and `create_candidate`. The quote charges nothing. A
|
|
451
|
-
delivered candidate is charged its one unit whether it is kept or discarded; one that fails is charged nothing,
|
|
452
|
-
even when its paid work was already done. An identical request returns the same run; `take` (`--take` in the CLI)
|
|
453
|
-
makes another candidate on purpose. `candidate` prints the quote and starts nothing without `--yes`. While shot
|
|
454
|
-
candidates are closed on the server, every call answers `editing_disabled`. (clipwright#604)
|
|
455
|
-
|
|
456
|
-
### Changed
|
|
457
|
-
|
|
458
|
-
- **Breaking:** `ApiFailure` gains the kinds `workflow_invalid`, `workflow_conflict` and `workflow_not_ready`, for
|
|
459
|
-
TypeScript callers that switch on the kind. Each keeps every issue and warning of the refusal. (clipwright#631)
|
|
460
|
-
- The agent report of `edit_ceiling_reached` and `edit_invalid` names a paid edit and the request, not a revision and
|
|
461
|
-
a document, since shot candidates are refused with the same codes. *Dashboard:* the docs page lists the prices of a
|
|
462
|
-
shot candidate. (clipwright#604)
|
|
463
|
-
|
|
464
|
-
## [0.28.0] - 2026-10-15
|
|
465
|
-
|
|
466
|
-
The revision of a faceless video is paid and open: `quoteRevision` and `startRevision` in the SDK, `revise-quote` and
|
|
467
|
-
`revise` in the CLI, and the MCP tools `quote_revision` and `revise_run`, which make the server list 17 tools. Three
|
|
468
|
-
failure kinds are new: `editing_closed`, `edit_ceiling_reached` and `edit_invalid`.
|
|
469
|
-
|
|
470
|
-
### Added
|
|
471
|
-
|
|
472
|
-
- A finished faceless video can be revised: `quoteRevision` and `startRevision` in the SDK, `revise-quote` and
|
|
473
|
-
`revise` in the CLI, and the MCP tools `quote_revision` and `revise_run`. A revision is a new run made from the
|
|
474
|
-
edited document, or from shots named to be generated anew. The quote charges nothing. An identical request returns
|
|
475
|
-
the same run; `attempt` (`--retry` in the CLI) starts a second revision on purpose. A revision that delivers is
|
|
476
|
-
charged its quoted total; one that fails is charged nothing, even when its paid work was already done. While paid
|
|
477
|
-
edits are closed on the server, both calls answer `editing_disabled`. (clipwright#604)
|
|
478
|
-
|
|
479
|
-
### Changed
|
|
480
|
-
|
|
481
|
-
- **Breaking:** `@clipwright/core`, for TypeScript callers: the union `ApiFailure` has three more members,
|
|
482
|
-
`editing_closed`, `edit_ceiling_reached` and `edit_invalid`. A `switch` over `failure.kind` that is checked for
|
|
483
|
-
exhaustiveness does not compile until it handles them. Code that does not switch on the kind is not affected.
|
|
484
|
-
(clipwright#604)
|
|
485
|
-
- The refusals of the revision routes have failure kinds of their own: `editing_closed` for the 503s
|
|
486
|
-
`editing_disabled`, `editing_not_priced` and `editing_window_not_set`, which are no longer retried as server errors;
|
|
487
|
-
`edit_ceiling_reached` with the limit, the count and the runs counted; `edit_invalid` with the issues of the
|
|
488
|
-
document. They were `server_error` and a `client_error` without their fields. (clipwright#604)
|
|
489
|
-
- *Dashboard:* `/videos` lists faceless videos as well as UGC videos. A faceless video has no still frame, so its
|
|
490
|
-
tile says that no preview was recorded, and a click plays it like any other tile. "Get video link" on the Balance
|
|
491
|
-
page now gives the link of a faceless video, where it used to answer "No video for this run.". (clipwright#604)
|
|
492
|
-
- *Dashboard:* a revision is labelled with the run it revises on the Balance page and on `/videos`, and the docs page
|
|
493
|
-
lists the prices of a revision. (clipwright#604)
|
|
494
|
-
|
|
495
|
-
## [0.27.0] - 2026-10-13
|
|
496
|
-
|
|
497
|
-
The shots of a finished video can be read, and the draft of an edit can be kept: `getRunShots`, `getRunEdit` and
|
|
498
|
-
`saveRunEdit` in the SDK, `shots`, `edit-show` and `edit-save` in the CLI, and the MCP tool `get_run_shots`. A draft
|
|
499
|
-
charges nothing and renders nothing, and no call makes a video from it yet.
|
|
500
|
-
|
|
501
|
-
### Added
|
|
502
|
-
|
|
503
|
-
- *Server-side:* the API reads the shots of a run and keeps the draft of an edit. `GET /v1/runs/{id}/shots` returns
|
|
504
|
-
each shot of a finished video: its span in frames, its kind, the words it covers, its description and a signed link
|
|
505
|
-
to its source picture or clip. A run with no shots to show answers `planned: false` with the reason, which is an
|
|
506
|
-
answer and not an error. `GET` and `POST /v1/runs/{id}/edit` read and save a draft: a document of the wanted
|
|
507
|
-
timeline, stored with a version. A save names the version it was written against and is refused with 409
|
|
508
|
-
`edit_conflict` when the draft has another. The three calls are free. A draft charges nothing and renders
|
|
509
|
-
nothing, and no call makes a video from it. (clipwright#604)
|
|
510
|
-
- `@clipwright/sdk`: `getRunShots(runId)`, `getRunEdit(runId)` and `saveRunEdit(runId, { base_version, document })`.
|
|
511
|
-
The two 409 refusals of a draft arrive as `ClipwrightApiError` with their fields: `failure.version` on
|
|
512
|
-
`edit_conflict`, `failure.state` and `failure.reason` on `run_not_editable`. `saveRunEdit` sends one request and
|
|
513
|
-
never repeats it. (clipwright#604)
|
|
514
|
-
- `@clipwright/cli`: `shots <run>` lists the shots of a run, `edit-show <run>` prints the draft as JSON, and
|
|
515
|
-
`edit-save <run> --file <path>` saves the file `edit-show` printed. A save answered 409 reads the draft once: when
|
|
516
|
-
the draft already holds the file's document one version later, an earlier send went through and the save is
|
|
517
|
-
reported as done; otherwise the command reports the conflict and the stored version. (clipwright#604)
|
|
518
|
-
- `@clipwright/mcp-server`: the tool `get_run_shots`, read-only. The MCP server now lists fifteen tools. The draft
|
|
519
|
-
of an edit has no tool: it is read and saved over REST, the SDK and the CLI. (clipwright#604)
|
|
520
|
-
- `@clipwright/core` exports the contract of these calls, also on the subpath `@clipwright/core/edit`: `runShots`,
|
|
521
|
-
`runEdit` and `saveRunEdit`, which the API emits and takes, and `runShotsRead` and `runEditRead`, which a client
|
|
522
|
-
parses a response with. The read schemas take as plain strings the names a later API may add: a kind of shot, an
|
|
523
|
-
action, a line, the code of an issue. The document of a draft keeps the keys a client does not know.
|
|
524
|
-
`parseApiFailure` returns the kinds `edit_conflict` and `run_not_editable` for the two 409 bodies, and
|
|
525
|
-
`agentFailureReport` carries `version`, `state` and `reason`. (clipwright#604)
|
|
526
|
-
|
|
527
|
-
### Changed
|
|
528
|
-
|
|
529
|
-
- **Breaking:** `@clipwright/core`, for TypeScript callers: the union `ApiFailure` has two more members,
|
|
530
|
-
`edit_conflict` and `run_not_editable`. A `switch` over `failure.kind` that is checked for exhaustiveness does not
|
|
531
|
-
compile until it handles them, and a 409 body with either code no longer parses as `client_error`. Code that
|
|
532
|
-
does not switch on the kind is not affected. (clipwright#604)
|
|
533
|
-
- `@clipwright/sdk`: a `ClipwrightResponseError` of a call that starts no run now reads "No run was created and no
|
|
534
|
-
credits were spent, and a retry creates no run and spends none." in place of "Nothing was created; retrying is
|
|
535
|
-
safe.". The old sentence was false of `setActorDefaults` and would be of `saveRunEdit`: such a call may have
|
|
536
|
-
stored what it was sent. (clipwright#604)
|
|
537
|
-
- *Dashboard:* the table "When a call fails" of the API docs lists the two refusals of a draft, and its row of
|
|
538
|
-
ordinary refusals names status 422, which an upload that is not a readable image is answered with.
|
|
539
|
-
(clipwright#604)
|
|
540
|
-
- *Server-side:* an uploaded image is kept for 30 days instead of 7, as long as the media of a finished run. The
|
|
541
|
-
link returned by `POST /v1/uploads` is still valid for 24 hours; upload the same file again to get a fresh one.
|
|
542
|
-
`@clipwright/core` states the period as `UPLOAD_OBJECT_RETENTION_DAYS`, now 30. (clipwright#607)
|
|
543
|
-
|
|
544
|
-
## [0.26.1] - 2026-10-09
|
|
545
|
-
|
|
546
|
-
A metadata patch: the npm description of `@clipwright/mcp-server` no longer carries a catalog claim token.
|
|
547
|
-
|
|
548
|
-
### Changed
|
|
549
|
-
|
|
550
|
-
- `@clipwright/mcp-server`: the package description on npm returns to its text before 0.26.0. That release appended
|
|
551
|
-
a one-time token, which a catalog read to confirm who owns its listing of the server. The catalog has confirmed it,
|
|
552
|
-
so the token is gone. No tool, flag or behavior changed. (clipwright#570)
|
|
553
|
-
|
|
554
|
-
## [0.26.0] - 2026-10-09
|
|
555
|
-
|
|
556
|
-
`make_faceless` takes a narration voice by name: `list_voices` with `skill=make_faceless` lists seventeen voices in
|
|
557
|
-
six languages. The MCP tools `make_faceless` and `quote_faceless` refuse a key they do not declare, and the MCP
|
|
558
|
-
server requires a patched `@modelcontextprotocol/sdk`.
|
|
559
|
-
|
|
560
|
-
### Changed
|
|
561
|
-
|
|
562
|
-
- *Dashboard:* a guide at `/guides/ai-ugc-ads` says what UGC ads and AI UGC ads are, and what the rules of the
|
|
563
|
-
United States, the European Union and the large platforms ask of them. Every source is listed with its date.
|
|
564
|
-
(clipwright#569)
|
|
565
|
-
- *Server-side:* a faceless video file carries its AI disclosure: the statement is embedded in the MP4 and stored in
|
|
566
|
-
the object metadata beside `ai-generated: true` and `generator: clipwright`. When the tag cannot be embedded, the
|
|
567
|
-
video is still delivered and the run says so, with the cause, in `warnings[]`. Faceless files delivered on or before
|
|
568
|
-
2026-10-04 may carry the storage flag alone. (clipwright#489)
|
|
569
|
-
- `@clipwright/core` exports `aiDisclosureObjectMetadata(text, embedded?)`, the builder of that object metadata, and
|
|
570
|
-
`AI_DISCLOSURE_EMBEDDED_METADATA_KEY`. `AI_DISCLOSURE_OBJECT_METADATA` stays the metadata of a video with a
|
|
571
|
-
presenter. (clipwright#489)
|
|
572
|
-
- *Dashboard:* The AI Disclosure page describes one marking for both kinds of video and names the date before which
|
|
573
|
-
a faceless file may carry less. (clipwright#489)
|
|
574
|
-
- *Server-side:* a finished faceless video is delivered even when our own check of the picture objects. The run ends
|
|
575
|
-
`succeeded`, is charged by the delivered duration, and says in `warnings[]` what the check could not confirm and at
|
|
576
|
-
which second: the captions, a scene change, text in the caption area with captions off, or that the check did not
|
|
577
|
-
run. Such a run used to wait for an operator, and the customer got no video. A file that is not the video we
|
|
578
|
-
rendered (wrong length, size or sound) is still refused without a charge. (clipwright#498)
|
|
579
|
-
- *Server-side:* the narration of a faceless video is levelled to -16 LUFS, and quiet and loud phrases are brought
|
|
580
|
-
closer together. It used to keep the level of the speech vendor: about 4 LU quieter, with phrases up to 5 dB apart,
|
|
581
|
-
so a later phrase could sound much louder than the opening. Timing is unchanged. (clipwright#333)
|
|
582
|
-
- *Server-side:* pictures in a faceless video change faster and less evenly: about every two and a half seconds on
|
|
583
|
-
average, where they used to hold for three to four, and a short phrase gets a short shot of its own. A video uses
|
|
584
|
-
more generated pictures, so it takes longer to make; the price is unchanged. (clipwright#519)
|
|
585
|
-
- *Server-side:* a faceless shot that covers two phrases shows one scene. It used to ask for both scenes in one
|
|
586
|
-
picture, which could come back as two pictures stacked in one frame. (clipwright#517)
|
|
587
|
-
- *Server-side:* the step that writes the scene descriptions of a faceless video is told to ask for readable words
|
|
588
|
-
and figures only when the script says them. It used to invent some, such as figures on a blackboard that
|
|
589
|
-
contradicted the narration. This makes invented writing rarer, not impossible; the writing in a finished picture
|
|
590
|
-
is compared with the script by the check of generated pictures described further down. (clipwright#516)
|
|
591
|
-
- *Server-side:* a faceless video file is smaller and closer to the rendered picture. A local render of one
|
|
592
|
-
43-second video with the new settings came to 29 MB at about 5 Mbit/s, where the old settings gave 75 MB at 14.
|
|
593
|
-
Resolution, frame rate, colour and audio are unchanged. (clipwright#518)
|
|
594
|
-
- *Server-side:* a faceless video whose opening clip shows text is delivered, with a `warnings[]` line saying so. It
|
|
595
|
-
used to fail with `opening_clip_rejected: the generated opening clip shows text`, or wait for an operator when the
|
|
596
|
-
frame held a lot of text, so a scene set in a shop or a café often could not be made: the image model draws signs
|
|
597
|
-
and price tags on its own. An opening clip that ends on a fade or is one flat colour still fails without a charge.
|
|
598
|
-
(clipwright#524)
|
|
599
|
-
- *Server-side:* a faceless video may run up to a quarter past `duration_seconds`, never past 90 seconds. It used to
|
|
600
|
-
fail with `voice_outside_selected_duration` when its narration ran more than 5 seconds over, and one script is
|
|
601
|
-
spoken at a different length from run to run, so a script that fitted once could fail the next time. A video more
|
|
602
|
-
than 5 seconds longer than selected says so in `warnings[]`, with both lengths. The price is unchanged: seconds
|
|
603
|
-
past the selection are free. A script is still accepted when its estimated length is 21 seconds to
|
|
604
|
-
`duration_seconds` plus 5, at most 90. (clipwright#529)
|
|
605
|
-
- `@clipwright/core`: `facelessMaxOutputFrames(selected)` returns a quarter past the selection, and the new
|
|
606
|
-
`facelessMaxEstimateFrames(selected)` returns the selection plus 5 seconds, the bound a script estimate must fit.
|
|
607
|
-
(clipwright#529)
|
|
608
|
-
- *Server-side:* a faceless video is ready sooner. After the first picture the others are generated three at a time,
|
|
609
|
-
beside the opening clip, where they used to be made one after another. The price and the result are unchanged.
|
|
610
|
-
(clipwright#520)
|
|
611
|
-
- *Server-side:* at most two faceless videos of one account are made at once; a third waits its turn and is not
|
|
612
|
-
refused. Faceless runs had no such limit. Each line also has a limit across all accounts now, so when many accounts
|
|
613
|
-
render at once a run may wait behind theirs instead of failing at a vendor. Three videos with a presenter per
|
|
614
|
-
account, as before. (clipwright#534)
|
|
615
|
-
- `@clipwright/core` exports `MAX_CONCURRENT_FACELESS_PER_ACCOUNT`. (clipwright#534)
|
|
616
|
-
- *Server-side:* captions of a faceless video break at the script's punctuation. A caption line used to be filled to
|
|
617
|
-
the width of the frame, so it could end one word into the next sentence: "NEXT MORNING A SIGN SOLD", then "OUT BY
|
|
618
|
-
NOON". A line now ends at a sentence mark, crosses a comma only with whole clauses, and a clause too long for one
|
|
619
|
-
line is split into parts of similar width instead of a full line and a leftover word. An abbreviation written with a
|
|
620
|
-
full stop before a capital or a figure ("Dr. Smith", "No. 1") still reads as a sentence end and can leave a one-word
|
|
621
|
-
line. (clipwright#535)
|
|
622
|
-
- *Server-side:* a video with a presenter (`make_ugc` or long-form) comes in a smaller file that is closer to the
|
|
623
|
-
rendered picture. A local render of one 69-second long-form video with the new settings came to 45 MB, where the
|
|
624
|
-
old settings gave 54 MB. Resolution, frame rate, colour and audio are unchanged. (clipwright#526)
|
|
625
|
-
- *Server-side:* a character who appears in several scenes of a faceless video is now described the same way in every
|
|
626
|
-
scene that shows them. The step that writes the scenes fixes one description of every recurring person or animal
|
|
627
|
-
(apparent age, build, hair, clothing), and the picture of each such scene is asked for with it. A secondary character
|
|
628
|
-
used to be a different person in every scene; only the main character, shown in the first picture, stayed the same.
|
|
629
|
-
Faces can still differ a little between scenes. (clipwright#532)
|
|
630
|
-
- `make_faceless` takes `voice`, the narration voice by name: `voice` on `quote_faceless` and `make_faceless`,
|
|
631
|
-
`--voice` on `quote-faceless` and `make-faceless`. `list_voices` with `skill=make_faceless` (`--skill
|
|
632
|
-
make_faceless` on `voices`) lists seventeen narration voices for it, in English, Russian, Spanish, Portuguese,
|
|
633
|
-
French and Italian, each with a language and a gender. Every listed voice now names the one skill that speaks it
|
|
634
|
-
in `skill`. Without `voice` the narration is read as before, by `narrator_en_wise_lady`. An unknown name,
|
|
635
|
-
a `make_ugc` voice and `voice_id` are refused before any charge, and `make_ugc` refuses a faceless voice the same
|
|
636
|
-
way, naming the skill that speaks it. A named voice whose language is written in another alphabet than the
|
|
637
|
-
script adds a line to `warnings[]` of the quote and of the run: the voice may mispronounce the text, and the
|
|
638
|
-
video may come out longer than its length limit and fail. A brief written in the other alphabet, with no letter
|
|
639
|
-
of the voice's, adds that line as a condition, since a brief may ask for the narration's language in words. The faceless voices have
|
|
640
|
-
no audio sample yet. (clipwright#530)
|
|
641
|
-
- **Breaking:** `@clipwright/mcp-server`: `make_faceless` and `quote_faceless` refuse a key they do not declare,
|
|
642
|
-
`voice_id` first of all, before any request is sent. Such a key used to be dropped silently. (clipwright#530)
|
|
643
|
-
- *Server-side:* `GET /v1/voices` without `skill` returns the `make_ugc` voices only, the same list as before, to
|
|
644
|
-
every client version; `skill=make_ugc` returns it too. The faceless voices come only with `skill=make_faceless`,
|
|
645
|
-
as `kind: "faceless_voice"`. (clipwright#530)
|
|
646
|
-
- `@clipwright/core` exports `FACELESS_VOICES`, `FACELESS_VOICE_NAMES`, `DEFAULT_FACELESS_VOICE`,
|
|
647
|
-
`FACELESS_SPEECH_MODEL`, `isFacelessVoiceName`, `buildFacelessVoiceWarnings`, `VOICE_SKILLS`,
|
|
648
|
-
`FACELESS_REJECTED_FIELDS` and `offeredFacelessInput`; `@clipwright/core/voice-admission` exports
|
|
649
|
-
`serverFacelessInput` and `facelessVoiceRefusal`. (clipwright#530)
|
|
650
|
-
- *Server-side:* a generated picture of a faceless video can be checked before the video is assembled: for writing that
|
|
651
|
-
neither the script nor the run's `character_details` contain, and for a frame cut into several pictures. The check
|
|
652
|
-
sits behind a server switch, which was turned on after its first production run had been read; that run, of eighteen
|
|
653
|
-
pictures, took a minute and a half longer than the same video unchecked. A picture
|
|
654
|
-
with either is drawn once more when the run has time and budget for it, and the cleaner of the two is used. What
|
|
655
|
-
remains is named in `warnings[]` with the seconds it is on screen, one line for each thing found; a finding by itself
|
|
656
|
-
does not fail the run. A picture whose check cannot run in its time or within the run's budget is used as it is, and
|
|
657
|
-
one `warnings[]` line says how many pictures went unchecked. The check is a paid step like the others: when its cost
|
|
658
|
-
cannot be established, the run waits for an operator. Scene pictures are also asked for no writing unless the scene
|
|
659
|
-
quotes the script, which removed invented signs and figures from 10 of 10 test pictures. A customer's own image is
|
|
660
|
-
not checked. Writing on a `character_reference` picture is not known to the check: a generated picture that repeats
|
|
661
|
-
it is reported when the writing has a figure or more than two words. (clipwright#516, clipwright#517)
|
|
662
|
-
- *Server-side:* the narration of a faceless video is delivered in two identical channels instead of one. It sounds the
|
|
663
|
-
same, and a loudness meter now reads the -16 LUFS the narration is levelled to; a meter that measured the single
|
|
664
|
-
channel read 3 LU lower. The file grows by about 1 %. (clipwright#526)
|
|
665
|
-
|
|
666
|
-
### Security
|
|
667
|
-
|
|
668
|
-
- `@clipwright/mcp-server` requires `@modelcontextprotocol/sdk` 1.31.0 or newer. Earlier versions let an OAuth client
|
|
669
|
-
send credentials to an authorization server chosen by the MCP server (GHSA-6qxp-vccf-f47h). The server speaks stdio
|
|
670
|
-
and uses no OAuth; a fresh install of 0.25.0 already resolves to a patched version. (clipwright#510)
|
|
671
|
-
|
|
672
|
-
### Fixed
|
|
673
|
-
|
|
674
|
-
- *Server-side:* a faceless video whose opening clip has to end in the middle of a phrase keeps the words a
|
|
675
|
-
`scene_images` picture is anchored to on that picture: the narration starts later, by under three seconds, so the
|
|
676
|
-
clip ends before those words. When no such start exists, the video is still delivered, and `warnings[]` names the image and
|
|
677
|
-
the anchored words spoken while the opening clip was on screen. It used to say nothing. (clipwright#521)
|
|
678
|
-
- *Server-side:* a faceless narration that comes out longer than the video may run is spoken once more, a little
|
|
679
|
-
faster. The run used to fail with `voice_outside_selected_duration` after the story and the speech were made, and
|
|
680
|
-
one script is spoken at a different length from run to run, so a script that fitted once could fail the next time.
|
|
681
|
-
A script that would not fit even at the fastest speech still fails, without a charge. (clipwright#529)
|
|
682
|
-
- *Server-side:* a faceless run no longer stops for review when one picture takes the image service about two minutes.
|
|
683
|
-
Such a picture is rare, about two in a hundred, but a video has eighteen or more, and since the pictures are made
|
|
684
|
-
three at a time (clipwright#520) one slow picture was enough to hold the whole run for an operator. A picture now has
|
|
685
|
-
four minutes before the run gives up on it. (clipwright#544)
|
|
686
|
-
- *Server-side:* two faceless videos made at the same time are much less likely to stop for review. To record what a
|
|
687
|
-
picture cost we ask the image service, which answers only a few such questions a minute; with two videos in work it
|
|
688
|
-
refused some, and a picture with no recorded cost held the whole run for an operator. A refused question now waits
|
|
689
|
-
as long as the service asks and is put again. Under load a video can take a few minutes longer; the limit itself
|
|
690
|
-
stays, so several videos at once can still meet it. (clipwright#553)
|
|
691
|
-
- *Server-side:* at most two faceless videos are made at once across all accounts; a third waits in the queue and
|
|
692
|
-
starts when one of them is done. Three at once asked the image service for more cost records than it answers, and
|
|
693
|
-
two of the three stopped for review. The limit per account stays at two, so one account's two videos can hold the
|
|
694
|
-
line while another account's video waits. (clipwright#553)
|
|
695
|
-
- *Server-side:* the voice preset `owner_ru_clone` speaks again. The cloned voice behind it was replaced at the
|
|
696
|
-
vendor, and a run that named the preset was refused before any charge. The preset now maps to the new voice, still
|
|
697
|
-
on `eleven_v4`, and `list_voices` links a sample spoken by it. (clipwright#497)
|
|
698
|
-
- *Server-side:* the delivery check of a faceless video no longer mistakes a yellow or amber picture for a caption
|
|
699
|
-
fault. It refused a correct video whose picture glowed behind the captions: a lamp, a sunset, fire, gold. The check
|
|
700
|
-
now compares neighbouring frames, so only yellow that moves with the spoken word counts. (clipwright#496)
|
|
701
|
-
- *Server-side:* a video file keeps one metadata box. The AI disclosure used to be added as a second box next to the
|
|
702
|
-
encoder's own, so a reader that takes the first box saw the encoder's comment and no disclosure. The disclosure now
|
|
703
|
-
replaces that comment in the one box, and the encoder tag stays. (clipwright#493)
|
|
704
|
-
|
|
705
|
-
## [0.25.0] - 2026-10-04
|
|
706
|
-
|
|
707
|
-
The AI disclosure names what each video holds, and the clients show it: `get_run` of the MCP server and
|
|
708
|
-
`clipwright runs <id>` carry `ai_disclosure`. The visible "AI-generated" label is gone, and the clients no longer
|
|
709
|
-
offer `disclosure_overlay`.
|
|
710
|
-
|
|
711
|
-
### Removed
|
|
712
|
-
|
|
713
|
-
- **Breaking:** *Server-side:* `disclosure_overlay` is gone: no video carries the visible "AI-generated" label. Quote
|
|
714
|
-
and run refuse the field with 400 `rejected_field` before any charge, and the refusal says where the disclosure is:
|
|
715
|
-
the run response and the file metadata. Clients up to 0.24.0 still list the field in their input schema; stop
|
|
716
|
-
passing it. Label the publication with the platform's own control. The contract version is `2026-10-04`.
|
|
717
|
-
(clipwright#488)
|
|
718
|
-
|
|
719
|
-
### Changed
|
|
720
|
-
|
|
721
|
-
- *Dashboard:* The Privacy Policy says that we keep the site that referred you and any marker in the link that
|
|
722
|
-
brought you to sign-up, and that a notification of each sign-up, with the email address, reaches us through
|
|
723
|
-
Telegram. (clipwright#482)
|
|
724
|
-
- *Server-side:* `ai_disclosure` of a faceless run names what that video holds: "This video was generated with AI:
|
|
725
|
-
the voice, the opening clip and the images are synthetic." A faceless run with `scene_images` says instead that the
|
|
726
|
-
voice and the opening clip are synthetic, and so is every image its author did not supply. Until now a faceless run
|
|
727
|
-
carried the sentence of a video with a presenter, about an actor and lip sync it does not have. A run with a
|
|
728
|
-
presenter keeps its sentence. (clipwright#488)
|
|
729
|
-
- `get_run` of the MCP server returns `ai_disclosure` with a finished video, and `clipwright runs <id>` prints it
|
|
730
|
-
under the video link. Until now neither showed the statement. (clipwright#488)
|
|
731
|
-
- *Server-side:* a run accepted with `disclosure_overlay: true` before the label was removed and composed after it
|
|
732
|
-
says so in `warnings[]`. (clipwright#488)
|
|
733
|
-
- `@clipwright/core` exports `aiDisclosureText(skill, input)` and the two faceless sentences,
|
|
734
|
-
`FACELESS_AI_DISCLOSURE_TEXT` and `FACELESS_OWN_IMAGES_AI_DISCLOSURE_TEXT`. `AI_DISCLOSURE_TEXT` stays the sentence
|
|
735
|
-
of a video with a presenter. (clipwright#488)
|
|
736
|
-
- *Dashboard:* The AI Disclosure page gives the three wordings of the statement, says that a faceless file carries a
|
|
737
|
-
storage flag alone, and no longer describes a visible label. (clipwright#488)
|
|
738
|
-
|
|
739
|
-
## [0.24.0] - 2026-10-03
|
|
740
|
-
|
|
741
|
-
A second speech model, `gemini-3.8-flash-tts`, with thirty voices of its own and a sample of each in English and
|
|
742
|
-
Russian. Nothing changes unless you name the model or one of its voices. The CLI and the MCP server accept the new
|
|
743
|
-
`tts_model` value from this release on.
|
|
744
|
-
|
|
745
|
-
### Added
|
|
746
|
-
|
|
747
|
-
- `tts_model` accepts `gemini-3.8-flash-tts`, a speech model of a second vendor. Nothing changes unless you name it:
|
|
748
|
-
every default stays as it was, and Russian speech without `tts_model` still uses `eleven_v4`. The model speaks only
|
|
749
|
-
its own voices: without `voice`, `kore` for a female actor and `charon` otherwise. It reads Russian stress marks,
|
|
750
|
-
and it gets the text with `<break time="…" />` tags cut, which the response names in a warning. Its script limit is
|
|
751
|
-
5,000 characters. The price per finished second is the same as on every other model. (clipwright#453)
|
|
752
|
-
- `voice` accepts the thirty voices of `gemini-3.8-flash-tts` by name: `kore`, `puck`, `zephyr` and the rest, as
|
|
753
|
-
`list_voices` returns them. Naming one selects that model without `tts_model`, and the quote names the model.
|
|
754
|
-
`clipwright voices` prints the model on the line of such a voice. (clipwright#453)
|
|
755
|
-
- *Server-side:* `list_voices` returns those thirty voices after the presets as entries of kind `model_voice`. Each
|
|
756
|
-
names one model in `model` and `supported_models`, has no `language`, and carries `gender` only where it is known:
|
|
757
|
-
`kore` is female and `charon` is male. The filters `model=gemini-3.8-flash-tts`, `language=ru` and `language=en`
|
|
758
|
-
find them; any other language does not. (clipwright#453)
|
|
759
|
-
- *Server-side:* each of those thirty voices carries `preview_url`, a short sample spoken by that voice on its model.
|
|
760
|
-
The sample is in English; a request filtered by `language=ru` gets the Russian one. `clipwright voices` prints the
|
|
761
|
-
link under the voice, as it does for every other voice with a sample. (clipwright#453)
|
|
762
|
-
- *Server-side:* with `gemini-3.8-flash-tts` the API refuses a preset or catalog `voice`, `voice_id`, `captions=true`,
|
|
763
|
-
`segments` and `inserts` before any charge: the model does not speak the preset and catalog voices and returns no
|
|
764
|
-
word timings. It refuses the same when a voice names the model instead of `tts_model`, and it refuses one of the
|
|
765
|
-
model's voices next to any other `tts_model`. Each refusal names what to pass instead. `list_voices` lists the
|
|
766
|
-
model in `models[]` with the languages `en` and `ru`; no preset or catalog voice names it in `supported_models`.
|
|
767
|
-
(clipwright#453)
|
|
768
|
-
- *Server-side:* a warning about stress marks on `eleven_flash_v2_5` or `eleven_turbo_v2_5` names only the models
|
|
769
|
-
that speak the voice of the run: with an explicit `voice` or `voice_id` these are `eleven_v3` and `eleven_v4`.
|
|
770
|
-
(clipwright#453)
|
|
771
|
-
- *Server-side:* the quote and the reserve for a Russian script on `gemini-3.8-flash-tts` assume 2.2 words per second,
|
|
772
|
-
the pace measured on its two default voices: 153 Russian words are quoted at 70 seconds and 2,100 credits. A script
|
|
773
|
-
in Latin letters on this model is quoted at 2.6 words per second, as on every other model. The charge follows the
|
|
774
|
-
measured duration. (clipwright#453)
|
|
775
|
-
- *Dashboard:* the Privacy Policy, the Cookie Policy and the AI disclosure page name the speech provider of a run
|
|
776
|
-
that chooses this model. (clipwright#453)
|
|
777
|
-
|
|
778
|
-
## [0.23.0] - 2026-10-02
|
|
779
|
-
|
|
780
|
-
Russian speech moves to `eleven_v4`: the server names it by default, and the client texts say which voices speak it.
|
|
781
|
-
Clients older than 0.22.0 fail on the new model name.
|
|
782
|
-
|
|
783
|
-
### Changed
|
|
784
|
-
|
|
785
|
-
- **Breaking:** *Server-side:* Russian speech uses `eleven_v4` when you name no `tts_model`. That covers the presets
|
|
786
|
-
`owner_ru_clone` and `daria_ru_female`, the catalog voices named `ru_*`, and a raw `voice_id` whose script is mostly
|
|
787
|
-
Cyrillic. Every other voice stays on `eleven_v3`, and an explicit `tts_model` always wins. Clients older than 0.22.0
|
|
788
|
-
read the model as one of three fixed values and fail on a response that names `eleven_v4`: `list_voices` fails
|
|
789
|
-
whenever the listing holds a Russian voice, as the unfiltered one always does, and `quote` fails for those Russian
|
|
790
|
-
voices. Upgrade to 0.22.0 or later. The contract version is `2026-10-02`. (clipwright#452)
|
|
791
|
-
- **Breaking:** `resolveTtsModel` in `@clipwright/core` requires `script`, the whole spoken text of the run: a raw
|
|
792
|
-
`voice_id` takes its model from it. (clipwright#452)
|
|
793
|
-
- *Server-side:* a script, or the line of one actor segment, that holds nothing but `<break time="…" />` tags is
|
|
794
|
-
refused before any charge on `eleven_v4`. The model gets the text with those tags cut, and nothing would be left
|
|
795
|
-
to say. (clipwright#452)
|
|
796
|
-
- *Server-side:* the warnings for a model that misreads stress marks name both models that read them, `eleven_v4`
|
|
797
|
-
and `eleven_v3`, instead of advising `eleven_v3` alone. (clipwright#452)
|
|
798
|
-
- *Server-side:* the quote and the reserve for a Russian script on `eleven_v4` assume 2.18 words per second, the
|
|
799
|
-
measured pace, instead of 2.3. `duration_estimate_sec` and `credits_estimate` come out about 5% higher: 153 Russian
|
|
800
|
-
words are quoted at 70 seconds and 2,100 credits instead of 67 seconds and 2,010. The charge still follows the
|
|
801
|
-
measured duration. A Russian script on an explicit `eleven_v3` and every other language are quoted as before.
|
|
802
|
-
(clipwright#452)
|
|
803
|
-
- *Server-side:* the long-form qualification ceiling (`segments` or `inserts`) moves from 300 to 327 seconds of
|
|
804
|
-
estimated output, for every run. A Russian script on an `eleven_v4` voice passes up to 713 words, against the 691
|
|
805
|
-
that passed while Russian voices spoke `eleven_v3`. A Russian script on an explicit `eleven_v3` passes up to 753
|
|
806
|
-
words and an English one up to 851. A longer script is refused before any charge. (clipwright#452)
|
|
807
|
-
- The `tts_model` and `script` descriptions say which voices speak `eleven_v4` by default, name both models that read
|
|
808
|
-
stress marks, and say that break tags are not counted toward the `eleven_v4` script limit. (clipwright#452)
|
|
809
|
-
|
|
810
|
-
### Fixed
|
|
811
|
-
|
|
812
|
-
- `SKILL.md` and the CLI README no longer say that every preset and catalog voice speaks `eleven_v3`, and no longer
|
|
813
|
-
advise keeping Russian scripts on `eleven_v3`. They name the voices that speak `eleven_v4` when you name no model:
|
|
814
|
-
the presets `owner_ru_clone` and `daria_ru_female`, the catalog voices named `ru_*`, and a raw `voice_id` with a
|
|
815
|
-
mostly Cyrillic script. They name both models that read stress marks, `eleven_v4` and `eleven_v3`, and say that
|
|
816
|
-
`eleven_v4` gives no pause for a `<break time="…" />` tag and gets the text with the tag cut. `SKILL.md` lists the
|
|
817
|
-
5,000-character script limit of `eleven_v4`. The behavior is the one the entries above describe; only these texts
|
|
818
|
-
were out of date. (clipwright#452)
|
|
819
|
-
- The `--tts-model` help of `clipwright make` says that an omitted flag means the voice's default model. It said
|
|
820
|
-
"the preset's model", which was wrong for a catalog voice and for `--voice-id`. (clipwright#452)
|
|
821
|
-
|
|
822
|
-
## [0.22.0] - 2026-10-01
|
|
823
|
-
|
|
824
|
-
A new speech model: `tts_model` accepts `eleven_v4`, and the clients no longer fail on a model they do not know.
|
|
825
|
-
|
|
826
|
-
### Added
|
|
827
|
-
|
|
828
|
-
- *Server-side:* a new sign-up gets a one-time trial of 420 credits, enough for one 90-second faceless video. An
|
|
829
|
-
account gets one trial at most. (clipwright#58)
|
|
830
|
-
- `tts_model` accepts `eleven_v4`, with a script limit of 5,000 characters. No voice speaks it by default: presets,
|
|
831
|
-
catalog voices and a raw `voice_id` stay on `eleven_v3` until you name it. It reads stress marks as `eleven_v3`
|
|
832
|
-
does. It gives no pause for a `<break time="…" />` tag, so the tag is cut from the text and `warnings[]` says so
|
|
833
|
-
in the quote and on the run. `list_voices` reports its languages. (clipwright#452)
|
|
834
|
-
|
|
835
|
-
### Changed
|
|
836
|
-
|
|
837
|
-
- The clients read `tts_model` in a quote and `model` in `list_voices` as text, not as one of a fixed list. A client
|
|
838
|
-
released before a new speech model no longer fails on a response that names it. (clipwright#452)
|
|
839
|
-
|
|
840
|
-
## [0.21.1] - 2026-09-27
|
|
841
|
-
|
|
842
|
-
A wording patch: the clients now describe the faceless length the way the API delivers it.
|
|
843
|
-
|
|
844
|
-
### Fixed
|
|
845
|
-
|
|
846
|
-
- The `make_faceless` tool description, the `make-faceless` CLI help, the `.mcpb` manifest, `SKILL.md` and the
|
|
847
|
-
package READMEs no longer call a faceless video a fixed 30–90 seconds. You select `duration_seconds` from 30 to 90;
|
|
848
|
-
the video ends with its narration and runs from 25 seconds to 5 seconds past the selection, never past 90. The
|
|
849
|
-
behavior is unchanged from 0.21.0; only the text was wrong.
|
|
850
|
-
|
|
851
|
-
### Changed
|
|
852
|
-
|
|
853
|
-
- *Dashboard:* The Acceptable Use Policy allows a faceless video to show a recognisable public figure when the story
|
|
854
|
-
is about that person (news, history, biography, commentary). It still may not make them appear to say, do or
|
|
855
|
-
endorse anything they did not. Showing a real person speaking your script still requires that person's consent.
|
|
856
|
-
|
|
857
|
-
## [0.21.0] - 2026-09-27
|
|
858
|
-
|
|
859
|
-
Faceless videos: an agent can now make a video of up to 90 seconds without an on-camera presenter, from a script or
|
|
860
|
-
from a short brief, and see the price before anything is made.
|
|
861
|
-
|
|
862
|
-
### Added
|
|
863
|
-
|
|
864
|
-
- `quote_faceless` and `make_faceless` MCP tools, `quoteFaceless` and `startFaceless` in the SDK, and the
|
|
865
|
-
`quote-faceless` and `make-faceless` CLI commands. The video is narration over an opening animated clip and image
|
|
866
|
-
scenes, with captions on by default. `duration_seconds` (30 to 90) is a target: the video ends with its narration
|
|
867
|
-
and runs from 25 seconds to 5 seconds past `duration_seconds`, never past 90. `quote_faceless` is free;
|
|
868
|
-
`make_faceless` returns a `run_id`, and `get_run` reports progress. The MCP server now lists fourteen tools.
|
|
869
|
-
|
|
870
|
-
### Server-side
|
|
871
|
-
|
|
872
|
-
- A faceless run is charged for the video it delivers, by its actual length, and never more than its quote: seconds
|
|
873
|
-
past `duration_seconds` are free. A failed
|
|
874
|
-
run is charged nothing, including one we stop ourselves because a step did not meet our checks. A run held for
|
|
875
|
-
review keeps its credit hold until it is resolved.
|
|
876
|
-
- Captions drop surrounding punctuation, keep accents and other diacritics, and show numbers as written (`$3.50`,
|
|
877
|
-
`10:30`, `1,000`, `50%`, `-20`).
|
|
878
|
-
- With captions on, the script is checked against the caption font before speech is generated; a character the font
|
|
879
|
-
cannot draw fails the run without a customer charge.
|
|
880
|
-
- Narration uses automatic language detection.
|
|
881
|
-
- Pictures change about every three seconds, between spoken words.
|
|
882
|
-
|
|
883
|
-
### Changed
|
|
884
|
-
|
|
885
|
-
- *Server-side* Voice catalog: `cs_female_jana` is now listed with use case `advertisement` (was `narrative_story`);
|
|
886
|
-
the notice period is 4015 days for `en_female_cassidy` (was 730) and 730 days for `fi_male_jaakko` (was 365).
|
|
887
|
-
`es_male_benjamin` is unchanged and remains available.
|
|
888
|
-
|
|
889
|
-
### Known limits
|
|
890
|
-
|
|
891
|
-
- The voice reads some abbreviations literally: write "1.5 million" rather than "1.5M".
|
|
892
|
-
- A generated picture can come out as a collage of two or three panels, and small character details (glasses,
|
|
893
|
-
for instance) can change between pictures.
|
|
894
|
-
- Narration is not loudness-normalized yet, so a video can play quieter than other clips in the same feed.
|
|
895
|
-
- *Server-side* A faceless run can fail when the opening clip shows a pattern our text check mistakes for lettering
|
|
896
|
-
(a chain, for instance). The run is charged nothing; running it again produces a new video.
|
|
897
|
-
|
|
898
|
-
## [0.20.0] - 2026-09-25
|
|
899
|
-
|
|
900
|
-
The MCP server is ready for directories: it has a name in the official MCP
|
|
901
|
-
Registry, and every tool tells the host whether it only reads or writes.
|
|
902
|
-
|
|
903
|
-
### Added
|
|
904
|
-
|
|
905
|
-
- Every MCP tool now carries a `title` and the `readOnlyHint`/`destructiveHint`
|
|
906
|
-
annotations: quotes, lists and reads are read-only, `delete_actor` is
|
|
907
|
-
destructive, and `make_ugc`, `create_actor`, `upload_image` and
|
|
908
|
-
`set_actor_defaults` write.
|
|
909
|
-
- `@clipwright/mcp-server` declares `mcpName: io.clipwright/mcp` for the official
|
|
910
|
-
MCP Registry.
|
|
911
|
-
|
|
912
|
-
## [0.19.0] - 2026-09-22
|
|
913
|
-
|
|
914
|
-
A paid video that arrived after we stopped waiting can now be collected: the run
|
|
915
|
-
goes back to `queued` and drives the pipeline again. The server side was live
|
|
916
|
-
from the day it was deployed; this release carries the contract change to the
|
|
917
|
-
MCP tool description, which is where an agent reads the promise.
|
|
918
|
-
|
|
919
|
-
### Changed
|
|
920
|
-
|
|
921
|
-
- **Breaking:** `failed` is no longer always final. A run whose paid vendor job
|
|
922
|
-
we still hold can be reopened: it goes back to `queued` and may reach
|
|
923
|
-
`succeeded`. Every reopening is named in `warnings[]`, and one run is reopened
|
|
924
|
-
at most three times. An agent that stops polling the moment it reads `failed`
|
|
925
|
-
will miss a video that was paid for and delivered.
|
|
926
|
-
- *Server-side* A run that lost the video while the vendor was still working on
|
|
927
|
-
it no longer says its paid job "was retained for recovery" when this run's
|
|
928
|
-
terms cannot support recovery. Reading the terms fails soft: when they cannot
|
|
929
|
-
be read at all, the run promises nothing either way.
|
|
930
|
-
- *Server-side* A recovered delivery is written to the ledger under its own
|
|
931
|
-
reason, `run_recovered_delivery`, because the vendor spend was already counted
|
|
932
|
-
on the day the run first failed.
|
|
933
|
-
|
|
934
|
-
### Operations
|
|
935
|
-
|
|
936
|
-
- Migration 0036 adds `recovery_attempt` and `recovery_reopened_at` to `runs`,
|
|
937
|
-
and both are read on the main render path. **Apply the migration before
|
|
938
|
-
deploying any service**: an early deploy fails every `make_ugc` run, not one
|
|
939
|
-
feature. Order forward is migration, api, worker, web; backwards it is worker
|
|
940
|
-
and api first, then drop the columns.
|
|
941
|
-
|
|
942
|
-
## [0.18.0] - 2026-09-21
|
|
943
|
-
|
|
944
|
-
Long-form clips can now show a face for a fifth of their length instead of nearly
|
|
945
|
-
all of it, which is what the face-second meter was priced for.
|
|
946
|
-
|
|
947
|
-
### Added
|
|
948
|
-
|
|
949
|
-
- `cover_words` on an insert says how many spoken words it covers, counted from
|
|
950
|
-
the first word of its anchor. The share of words left uncovered decides the
|
|
951
|
-
share of the clip that shows a face, and it does not move with the speed the
|
|
952
|
-
voice reads at. Word length still varies: at a 560-word script, asking for 19%
|
|
953
|
-
delivered 16 to 22 in nine hundred and ninety-seven simulated runs out of a
|
|
954
|
-
thousand, measured on this profile's voice. A shorter script scatters wider.
|
|
955
|
-
- A quote for a narrated clip carries `estimatedFaceWordShare`: the share of the
|
|
956
|
-
clip that will show a face, known before anything is synthesised.
|
|
957
|
-
|
|
958
|
-
### Changed
|
|
959
|
-
|
|
960
|
-
- **Up to 49 inserts per clip**, not two, and at most six appearances of the
|
|
961
|
-
actor between them. Both are counted from the word indexes you send, so an
|
|
962
|
-
input asking for more is refused before anything is paid for.
|
|
963
|
-
- *Server-side* An insert now ends where its first uncovered word begins rather
|
|
964
|
-
than where its last covered word ends, so the pause between two words belongs
|
|
965
|
-
to the insert. Inserts whose coverage meets are adjacent frame for frame and
|
|
966
|
-
no longer leave a fragment of actor footage between them.
|
|
967
|
-
- *Server-side* The credit hold for a narrated clip reserves the words you leave
|
|
968
|
-
uncovered instead of the whole narration. On a clip that covers four fifths of
|
|
969
|
-
its script the hold falls from 2170 credits to 630. Billing is unchanged: it
|
|
970
|
-
has always used the face intervals actually delivered.
|
|
971
|
-
|
|
972
|
-
## [0.17.0] - 2026-09-16
|
|
973
|
-
|
|
974
|
-
Everything here came out of the second dry run by a tester who had not seen the
|
|
975
|
-
product before.
|
|
976
|
-
|
|
977
|
-
### Added
|
|
978
|
-
|
|
979
|
-
- The MCP server reports money. `make_ugc` carries `credits_reserved` and
|
|
980
|
-
`get_run` carries `credits_charged`, in every state, so an agent no longer has
|
|
981
|
-
to call `get_account` before and after and subtract. The field names come from
|
|
982
|
-
the run schema, so REST and MCP cannot drift apart. (clipwright#209)
|
|
983
|
-
- *Server-side:* in `GET /v1/voices`, each entry of `models` carries
|
|
984
|
-
`vendor_verifies_voices` — whether the vendor's library listing marks any voice
|
|
985
|
-
as verified for that model. It is `false` for `eleven_v3` (measured: none of
|
|
986
|
-
303 live catalog voices), so an empty `verified_models` on that model says
|
|
987
|
-
nothing about the voice. (clipwright#208)
|
|
988
|
-
- *Server-side:* a voice whose gender differs from the actor's is named in
|
|
989
|
-
`warnings`, in the quote and in the run. The combination still runs as asked —
|
|
990
|
-
voicing a man with a female voice is sometimes deliberate — but it is no longer
|
|
991
|
-
silent. (clipwright#210)
|
|
992
|
-
- *Server-side:* an `image` smaller than the output on its short side gets a
|
|
993
|
-
warning that the source is upscaled, with both sizes and the size to send
|
|
994
|
-
instead. The default actor is silent: its size is a property of our own image,
|
|
995
|
-
stated once in the docs. (clipwright#211)
|
|
996
|
-
|
|
997
|
-
### Fixed
|
|
998
|
-
|
|
999
|
-
- *Server-side:* a request body that is not valid JSON answers 400
|
|
1000
|
-
`malformed_body`, not 500. A 500 says the failure is ours, so an agent retries
|
|
1001
|
-
bytes that will never parse; the new message says both what to fix and that a
|
|
1002
|
-
retry fails the same way. (clipwright#212)
|
|
1003
|
-
- *Server-side:* a source we cannot use — private or loopback host, http,
|
|
1004
|
-
unreachable, redirecting, over 10 MB, or not PNG/JPEG/WebP — is refused with
|
|
1005
|
-
400 `unusable_source` before any charge, in the quote and in the run alike.
|
|
1006
|
-
It used to be priced: a loopback url answered 200 and an estimate, while the
|
|
1007
|
-
tool description promised a refusal. (clipwright#213)
|
|
1008
|
-
- *Server-side:* refusals on `script`, `voice`, `voice_id` and `image` are
|
|
1009
|
-
written in the product's words instead of the schema library's, and the
|
|
1010
|
-
description of `script` no longer names a field the API rejects.
|
|
1011
|
-
(clipwright#212)
|
|
1012
|
-
- *Dashboard:* the root of the cabinet host sends a signed-in visitor to their
|
|
1013
|
-
dashboard instead of showing the landing page with a "Sign in" button.
|
|
1014
|
-
(clipwright#214)
|
|
1015
|
-
- *Dashboard:* every tile on `/videos` prints its `run_id` and links to the
|
|
1016
|
-
support form with it. The id used to live only in the preview image's alt
|
|
1017
|
-
text, so tiles without a preview had none at all. (clipwright#215)
|
|
1018
|
-
- *Dashboard:* the REST example on `/quickstart` runs unchanged in any shell: one
|
|
1019
|
-
line, no backslash continuations and no shell substitution. (clipwright#211)
|
|
1020
|
-
|
|
1021
|
-
## [0.16.0] - 2026-09-16
|
|
1022
|
-
|
|
1023
|
-
### Added
|
|
1024
|
-
|
|
1025
|
-
- *Server-side:* a new skill, `create_actor`, builds a personal actor for the
|
|
1026
|
-
account from a description of a fictional adult: a 9:16 portrait with exactly
|
|
1027
|
-
one face, plus the other requested formats edited from it. `POST
|
|
1028
|
-
/v1/skills/create_actor/quote` and `/run` take the description, `gender`,
|
|
1029
|
-
`approximate_age`, `name`, `quality` and `aspect_ratios`; the run reports
|
|
1030
|
-
`created_actor` when it succeeds, and the returned `actor_id` goes to
|
|
1031
|
-
`make_ugc` in the same field a catalog actor does. `GET /v1/actors` lists the
|
|
1032
|
-
account's own actors after the catalog, and `DELETE /v1/actors/{id}` takes one
|
|
1033
|
-
out of the choice. The skill appears in `GET /v1/public/skills` only while
|
|
1034
|
-
generation is switched on; until then quote and run answer 503
|
|
1035
|
-
`actor_generation_disabled` and no run is created. (clipwright#120)
|
|
1036
|
-
- *Server-side:* runs have a new state, `generating`, which only `create_actor`
|
|
1037
|
-
enters. The set of terminal states is unchanged: `succeeded` and `failed`, and
|
|
1038
|
-
nothing else. (clipwright#120)
|
|
1039
|
-
- Personal actors reached the clients. The SDK gained `quoteActor`,
|
|
1040
|
-
`createActor` and `deleteActor`; the CLI gained `quote-actor`, `create-actor`
|
|
1041
|
-
and `delete-actor`; the MCP server gained `quote_actor`, `create_actor` and
|
|
1042
|
-
`delete_actor`, so `tools/list` now returns ten tools instead of seven. The
|
|
1043
|
-
idempotency key of an actor run is built from the actor's own schema: two
|
|
1044
|
-
different descriptions are two different keys, and a repeated call with the
|
|
1045
|
-
same description returns the run already paid for. (clipwright#120)
|
|
1046
|
-
- *Dashboard:* `/actors` shows the account's personal actors next to the
|
|
1047
|
-
catalog and deletes one on confirmation. A deleted actor stops being offered
|
|
1048
|
-
at once; its images are removed by a daily cleanup. (clipwright#120)
|
|
1049
|
-
|
|
1050
|
-
### Changed
|
|
1051
|
-
|
|
1052
|
-
- *Server-side:* a request with `person` and generation switched on gets a
|
|
1053
|
-
warning that points at `create_actor` instead of only saying the field is not
|
|
1054
|
-
honored. (clipwright#120)
|
|
1055
|
-
- *Server-side:* `create_actor` is charged per published image, not per second:
|
|
1056
|
-
the portrait and each extra format cost what the quote showed, a partial
|
|
1057
|
-
result charges only what was published and names the rest in `warnings`, and a
|
|
1058
|
-
failed run costs nothing at all. Refused descriptions and unusable portraits
|
|
1059
|
-
are free. (clipwright#120)
|
|
1060
|
-
|
|
1061
|
-
## [0.15.0] - 2026-09-14
|
|
1062
|
-
|
|
1063
|
-
### Changed
|
|
1064
|
-
|
|
1065
|
-
- *Server-side:* in `GET /v1/voices`, a catalog voice carries `preview_url` and
|
|
1066
|
-
`preview_expires_at` once its sample is recorded: a short clip of that voice on
|
|
1067
|
-
`eleven_v3`, in the voice's own language. The link is signed by us and
|
|
1068
|
-
expires like a preset's. A voice without a recorded sample for its current
|
|
1069
|
-
model and sample text still has neither field, and the list never links to
|
|
1070
|
-
the vendor. The sample texts outside English and Russian are machine
|
|
1071
|
-
translations that no native speaker has checked. (clipwright#164)
|
|
1072
|
-
- *Server-side:* without `voice` or `voice_id`, the voice follows the actor's
|
|
1073
|
-
gender: a woman from `actor_id` speaks `sarah`, a man speaks `george`. The
|
|
1074
|
-
default actor still speaks `george`, and an explicit voice always wins.
|
|
1075
|
-
(clipwright#183)
|
|
1076
|
-
- *Server-side:* a request with `image` and no voice gets a warning that the
|
|
1077
|
-
male `george` voice is used, naming `voice` and `actor_gender` as the fix.
|
|
1078
|
-
`GET /v1/runs/{id}` derives it from the stored input, so runs started before
|
|
1079
|
-
this change show it too. A request with `actor_gender` next to `voice` or
|
|
1080
|
-
`voice_id` gets a warning that the hint changed nothing. (clipwright#183)
|
|
1081
|
-
- *Server-side:* the contract version moved to `2026-09-14`. (clipwright#183)
|
|
1082
|
-
- *Dashboard:* `/actors` says that an actor without a chosen voice speaks the
|
|
1083
|
-
default voice of their gender. (clipwright#183)
|
|
1084
|
-
|
|
1085
|
-
### Added
|
|
1086
|
-
|
|
1087
|
-
- `actor_gender` (`female` or `male`) in the `make_ugc` input: next to `image`
|
|
1088
|
-
it picks the default voice of that gender. It is refused with `actor_id` and
|
|
1089
|
-
without `image`, and the remote fetch killswitch turns it off together with
|
|
1090
|
-
`image`. The REST API accepts it from the day the API is deployed; the MCP
|
|
1091
|
-
tool schema, the SDK types and the CLI flag `--actor-gender` arrive with this
|
|
1092
|
-
release. (clipwright#183)
|
|
1093
|
-
|
|
1094
|
-
- *Dashboard:* `/actors` shows the actor library as a gallery: every published portrait with
|
|
1095
|
-
its `actor_id` to copy, next to gender, approximate age, description and version. A person
|
|
1096
|
-
can pick a face without calling `GET /v1/actors` first. (clipwright#148)
|
|
1097
|
-
- *Dashboard:* `/videos` lists the finished videos of the account. Each one is a still frame
|
|
1098
|
-
taken from the delivered file, with the length of the clip and the day it finished, and a
|
|
1099
|
-
tile with a frame plays the video. Runs that are still going or that failed stay on the
|
|
1100
|
-
Balance page. (clipwright#138)
|
|
1101
|
-
- *Dashboard:* `/changelog` renders this file as a public page, so the release notes are
|
|
1102
|
-
readable without installing a package. (clipwright#102)
|
|
1103
|
-
|
|
1104
|
-
## [0.14.0] - 2026-09-13
|
|
1105
|
-
|
|
1106
|
-
### Changed
|
|
1107
|
-
|
|
1108
|
-
- **Breaking:** *Server-side:* `GET /v1/voices` lists the catalog voices after
|
|
1109
|
-
the five presets, by language and then by rank; a voice retired from the
|
|
1110
|
-
catalog is not listed. Every entry gains `kind` (`preset` or `catalog`) and
|
|
1111
|
-
`supported_models`, the contract models that know the voice's language. A
|
|
1112
|
-
catalog voice also carries `verified_models` and whichever of `locale`,
|
|
1113
|
-
`accent`, `gender`, `age` and `use_case` the catalog has. The response gains
|
|
1114
|
-
`models`: each contract model with its `char_limit` and `languages`. Only a
|
|
1115
|
-
preset carries `preview_url`; a catalog voice has no sample yet. Clients
|
|
1116
|
-
0.11.0 and 0.12.0 cannot read this response and fail in `listVoices()`,
|
|
1117
|
-
`list_voices` and `clipwright voices`: upgrade to 0.13.0 or later. The
|
|
1118
|
-
contract version moved to `2026-09-13.2`. (clipwright#164)
|
|
1119
|
-
- *Server-side:* `GET /v1/voices` takes the filters `language`, `gender`, `age`,
|
|
1120
|
-
`use_case` and `model`. `model` keeps the voices whose language the model
|
|
1121
|
-
knows. A voice without a label matches no value of that filter. An unknown
|
|
1122
|
-
value gets 400 `invalid_request` that names the allowed values, and an
|
|
1123
|
-
unknown query key gets 400 `unknown_field`; neither returns an empty list.
|
|
1124
|
-
(clipwright#164)
|
|
1125
|
-
- `listVoices()` takes the same filters as an object, MCP `list_voices` as
|
|
1126
|
-
arguments, and `clipwright voices` as `--language`, `--gender`, `--age`,
|
|
1127
|
-
`--use-case` and `--model`. `clipwright voices` prints age and use case next
|
|
1128
|
-
to language and gender, and cuts a description longer than 100 characters.
|
|
1129
|
-
(clipwright#164)
|
|
1130
|
-
|
|
1131
|
-
### Added
|
|
1132
|
-
|
|
1133
|
-
- `@clipwright/core` exports `voicesQuery`, `voicesQueryShape`, `VoicesQuery`
|
|
1134
|
-
and `VOICES_QUERY_FIELDS`. `unknownFields` takes an optional list of accepted
|
|
1135
|
-
keys, and `UnknownFieldHit.suggestion` is typed `string`. The subpath
|
|
1136
|
-
`@clipwright/core/voice-listing` exports `listVoices`, `serverVoicesQuery`
|
|
1137
|
-
and `serverVoicesQueryFor`. (clipwright#164)
|
|
1138
|
-
|
|
1139
|
-
## [0.13.0] - 2026-09-13
|
|
1140
|
-
|
|
1141
|
-
### Changed
|
|
1142
|
-
|
|
1143
|
-
- `listVoices()`, MCP `list_voices` and `clipwright voices` accept a voice name
|
|
1144
|
-
outside the five presets, a `gender` other than `female` or `male`, a voice
|
|
1145
|
-
without `language`, and the new optional fields `kind`, `locale`, `accent`,
|
|
1146
|
-
`age`, `use_case`, `supported_models` and `verified_models`, plus a top-level
|
|
1147
|
-
`models` list. Unknown keys are dropped, as before. Until now the first such
|
|
1148
|
-
voice made all three fail. (clipwright#164)
|
|
1149
|
-
- A voice name the client does not know goes to the API, which decides.
|
|
1150
|
-
`clipwright make --voice` checks only the form of the name: letters, digits,
|
|
1151
|
-
`_` and `-`, up to 64 characters. The SDK and MCP `make_ugc` no longer refuse
|
|
1152
|
-
such a name before sending it. In `tools/list`, `voice` is a string with a
|
|
1153
|
-
pattern instead of an enum of preset names. The API itself is unchanged: a
|
|
1154
|
-
name that is not a preset still gets 400 `invalid_request` with the same
|
|
1155
|
-
message, before any charge. (clipwright#164)
|
|
1156
|
-
- In `VoiceCatalogEntry`, `name` and `gender` are typed `string`, and
|
|
1157
|
-
`language` is optional. In `MakeUgcInputArgs`, `voice` is typed `string`.
|
|
1158
|
-
(clipwright#164)
|
|
1159
|
-
- *Server-side:* quote and run accept a voice from the catalog by its name, as
|
|
1160
|
-
well as a preset. A catalog voice speaks `eleven_v3` unless `tts_model` names
|
|
1161
|
-
another model, and its script limit follows that model: 5,001 characters
|
|
1162
|
-
without `tts_model` get 400 before any charge, as with a preset. A name that
|
|
1163
|
-
is neither a preset nor a catalog voice gets 400 `invalid_request` that says
|
|
1164
|
-
the voice is unknown; a voice retired from the catalog gets 400 that says it
|
|
1165
|
-
was retired. Both point to `list_voices`. The language of a voice limits
|
|
1166
|
-
nothing: any catalog voice speaks any language. A run already stored with a
|
|
1167
|
-
voice that was later retired still reads, with its warnings.
|
|
1168
|
-
(clipwright#164)
|
|
1169
|
-
|
|
1170
|
-
### Added
|
|
1171
|
-
|
|
1172
|
-
- `@clipwright/core` exports `VOICE_NAME_PATTERN`, `isVoicePresetName`,
|
|
1173
|
-
`serverUgcInputWith` and `voiceModelEntry`. The subpath
|
|
1174
|
-
`@clipwright/core/voice-admission` exports `serverUgcInput`, which checks a
|
|
1175
|
-
voice name against the catalog, and `catalogVoiceRefusal`. The catalog stays
|
|
1176
|
-
out of the main entry point. (clipwright#164)
|
|
1177
|
-
|
|
1178
|
-
## [0.12.0] - 2026-09-13
|
|
1179
|
-
|
|
1180
|
-
### Changed
|
|
1181
|
-
|
|
1182
|
-
- **Breaking:** *Server-side:* quote and run refuse a key that is not part of
|
|
1183
|
-
the contract with 400 `unknown_field`, before any charge. Such keys were
|
|
1184
|
-
dropped silently before, so a misspelled field fell back to its default:
|
|
1185
|
-
`aspectRatio: "16:9"` rendered 9:16 without a warning. `fields` names each
|
|
1186
|
-
unknown key, and the message suggests the matching field (`aspect_ratio`).
|
|
1187
|
-
Fix the key name. The contract version moved to `2026-09-13`.
|
|
1188
|
-
(clipwright#166)
|
|
1189
|
-
- *Server-side:* the duration estimate for a Cyrillic script uses 2.3 words a
|
|
1190
|
-
second instead of 2.6, measured on `eleven_v3`. A Russian script now
|
|
1191
|
-
quotes and reserves about 13% more credits, closer to what the run is
|
|
1192
|
-
charged. Other scripts keep 2.6. (clipwright#164)
|
|
1193
|
-
- A stress mark (U+0301) at the start of a word is no longer counted as its
|
|
1194
|
-
first letter, so a capital right after the mark stays a capital. A capital
|
|
1195
|
-
vowel later in the same word still marks stress. (clipwright#164)
|
|
1196
|
-
- Each package ships this changelog as `CHANGELOG.md`. (clipwright#102)
|
|
1197
|
-
|
|
1198
|
-
### Added
|
|
1199
|
-
|
|
1200
|
-
- Quote returns `tts_model`, the speech model the run will use.
|
|
1201
|
-
(clipwright#164)
|
|
1202
|
-
- `@clipwright/core` exports `unknownFields`, `unknownFieldError`,
|
|
1203
|
-
`unknownFieldBody` and `ACCEPTED_UGC_FIELDS`, and `unknown_field` is part of
|
|
1204
|
-
`API_ERROR_CODES`. (clipwright#166)
|
|
1205
|
-
|
|
1206
|
-
### Fixed
|
|
1207
|
-
|
|
1208
|
-
- *Server-side:* a body with an empty key name gets 400 `unknown_field`
|
|
1209
|
-
instead of 500 `internal_error`. (clipwright#167)
|
|
1210
|
-
|
|
1211
|
-
## [0.11.0] - 2026-09-13
|
|
1212
|
-
|
|
1213
|
-
### Removed
|
|
1214
|
-
|
|
1215
|
-
- **Breaking:** `eleven_multilingual_v2` is no longer a valid `tts_model`. Quote
|
|
1216
|
-
and run refuse it with 400 before any charge. Pass `eleven_v3`,
|
|
1217
|
-
`eleven_flash_v2_5` or `eleven_turbo_v2_5`, or omit the field. Runs stored with
|
|
1218
|
-
the old value still read. (clipwright#145)
|
|
1219
|
-
|
|
1220
|
-
### Changed
|
|
1221
|
-
|
|
1222
|
-
- **Breaking:** every voice preset and a raw `voice_id` now speak on `eleven_v3`.
|
|
1223
|
-
Before, four of five presets and a raw `voice_id` used `eleven_multilingual_v2`,
|
|
1224
|
-
with a 10,000-character script ceiling. The default ceiling is now 5,000
|
|
1225
|
-
characters. A script of 5,001–10,000 characters that passed before is refused;
|
|
1226
|
-
send it with `tts_model: "eleven_flash_v2_5"` or `"eleven_turbo_v2_5"` (10,000
|
|
1227
|
-
each). The refusal names these models when the script fits them. The voices
|
|
1228
|
-
sound different, and the samples from `list_voices` were re-recorded.
|
|
1229
|
-
(clipwright#145)
|
|
1230
|
-
- **Breaking:** on `eleven_v3`, a single capital vowel after the first letter of a
|
|
1231
|
-
Cyrillic word marks stress: `потОм` is sent as `пото́м` (lowercase vowel plus
|
|
1232
|
-
U+0301). A script that used such a capital for another reason is now spoken
|
|
1233
|
-
differently; write that word in lowercase. A capital at the start of a word, a
|
|
1234
|
-
word in capitals, and a word with a second capital stay as written. Stress marks
|
|
1235
|
-
count toward the character limit. (clipwright#145)
|
|
1236
|
-
- The contract version moved from `2026-08` to `2026-09`. (clipwright#145)
|
|
1237
|
-
|
|
1238
|
-
### Added
|
|
1239
|
-
|
|
1240
|
-
- `tts_model` accepts `eleven_flash_v2_5` and `eleven_turbo_v2_5`, 10,000
|
|
1241
|
-
characters each. (clipwright#145)
|
|
1242
|
-
- *Server-side:* quote and run return a warning when a script with stress marks or
|
|
1243
|
-
in Cyrillic goes to a 2.5 model. The default path stays silent. (clipwright#145)
|
|
1244
|
-
- `@clipwright/core` exports the stress helpers (`STRESS_MARK`,
|
|
1245
|
-
`stressMarksFromCapitals`, `speechTextFor`) and the run preflight schema
|
|
1246
|
-
(`runPreflight`, `parseRunPreflight`). (clipwright#145, clipwright#146)
|
|
1247
|
-
|
|
1248
|
-
### Fixed
|
|
1249
|
-
|
|
1250
|
-
- *Server-side:* for a body with `image`, the 202 response of a run and the quote
|
|
1251
|
-
now return the same `warnings[]`. Warnings that depend on a network probe no
|
|
1252
|
-
longer disappear when a run fails. (clipwright#146)
|
|
1253
|
-
|
|
1254
|
-
## [0.10.0] - 2026-09-11
|
|
1255
|
-
|
|
1256
|
-
### Added
|
|
1257
|
-
|
|
1258
|
-
- MCP tool `get_account`, SDK `getAccount()` and CLI `clipwright account`. All
|
|
1259
|
-
three read `GET /v1/account` (balance, debt, holds, grants) and spend nothing.
|
|
1260
|
-
(clipwright#135)
|
|
1261
|
-
- *Server-side:* quote adds a warning when a run with the same input would be
|
|
1262
|
-
refused with `account_not_admitted`, `debt_outstanding` or
|
|
1263
|
-
`insufficient_credits`. The warning carries the same numbers as the refusal.
|
|
1264
|
-
(clipwright#134)
|
|
1265
|
-
- `@clipwright/core` exports `API_ENDPOINTS`, `QUICKSTART_ENDPOINTS`,
|
|
1266
|
-
`endpointLabel` and `NODE_MIN_MAJOR` (the Node.js major the clients require).
|
|
1267
|
-
(clipwright#135, clipwright#129)
|
|
1268
|
-
|
|
1269
|
-
### Fixed
|
|
1270
|
-
|
|
1271
|
-
- *Server-side:* the `error` of a failed run in `GET /v1/runs/{id}` no longer
|
|
1272
|
-
contains stack frames or internal file paths. (clipwright#133)
|
|
1273
|
-
- *Server-side:* when our wait for the avatar vendor times out, the run is charged
|
|
1274
|
-
nothing, and its warning says what happened. (clipwright#150)
|
|
1275
|
-
|
|
1276
|
-
## [0.9.0] - 2026-09-09
|
|
1277
|
-
|
|
1278
|
-
### Added
|
|
1279
|
-
|
|
1280
|
-
- Each voice in `GET /v1/voices`, `list_voices` and `listVoices()` carries
|
|
1281
|
-
`preview_url` and `preview_expires_at`: a signed link to a sample recorded with
|
|
1282
|
-
that voice and its model. The link is valid for one hour. A voice without a
|
|
1283
|
-
sample has neither field. A 0.8.0 client drops both fields. (clipwright#147)
|
|
1284
|
-
- CLI `clipwright voices` prints the sample link on its own line. (clipwright#147)
|
|
1285
|
-
|
|
1286
|
-
## [0.8.0] - 2026-09-09
|
|
1287
|
-
|
|
1288
|
-
### Added
|
|
1289
|
-
|
|
1290
|
-
- Actor library: `GET /v1/actors`, MCP tool `list_actors`, SDK `listActors()` and
|
|
1291
|
-
CLI `clipwright actors`. Each actor has a stable `actor_id`, a name, a gender,
|
|
1292
|
-
an approximate age, a version and verified image variants. (clipwright#120)
|
|
1293
|
-
- `actor_id` input on quote and run, and CLI `--actor-id` on `make` and `quote`.
|
|
1294
|
-
Do not combine it with `image` or `person`. (clipwright#120)
|
|
1295
|
-
- Quote and run responses carry `actor`: the selected `actor_id`, `version` and
|
|
1296
|
-
`gender`; `{gender}` for the default actor; `null` when you pass your own
|
|
1297
|
-
`image`. (clipwright#64, clipwright#120)
|
|
1298
|
-
|
|
1299
|
-
## [0.7.0] - 2026-09-09
|
|
1300
|
-
|
|
1301
|
-
### Removed
|
|
1302
|
-
|
|
1303
|
-
- **Breaking:** `daily_remaining_credits` is gone from `GET /v1/account` and from
|
|
1304
|
-
the `account` schema in `@clipwright/core`. The per-account daily spend cap it
|
|
1305
|
-
reported was removed. A client that read the field now gets `undefined`; read
|
|
1306
|
-
`balance_credits`, and `debt_credits` for a block. The contract version was not
|
|
1307
|
-
moved for this change: it stayed `2026-08` until 0.11.0, so the header gave no
|
|
1308
|
-
signal. (clipwright#139)
|
|
1309
|
-
- **Breaking:** `@clipwright/core` no longer exports `MAX_SCRIPT_WORDS` or
|
|
1310
|
-
`SCRIPT_SECONDS_BASIS`. Code that imports them fails; use `TTS_MODEL_CHAR_CAP`
|
|
1311
|
-
or `MAX_SCRIPT_CHARS`. (clipwright#128)
|
|
1312
|
-
- *Server-side:* the refusal `daily_cap_exceeded` is no longer produced. Runs
|
|
1313
|
-
refused before keep it in their history. (clipwright#139)
|
|
1314
|
-
- *Server-side:* the refusal `global_cap_exceeded` is no longer produced. The
|
|
1315
|
-
service-wide daily spend cap became an internal alert. (clipwright#141)
|
|
1316
|
-
|
|
1317
|
-
### Changed
|
|
1318
|
-
|
|
1319
|
-
- The 180-word script ceiling is replaced by a character limit per speech model:
|
|
1320
|
-
`eleven_v3` 5,000, `eleven_multilingual_v2` 10,000. Length is counted as
|
|
1321
|
-
JavaScript `.length`, spaces and audio tags included; an emoji may count as two.
|
|
1322
|
-
Longer scripts than before are accepted. The refusal text changed from
|
|
1323
|
-
`script is ~N words; ceiling is 180 words` to
|
|
1324
|
-
`script has N characters; <model> allows at most N characters`; update code
|
|
1325
|
-
that matches on it. (clipwright#128)
|
|
1326
|
-
- **Breaking:** *Server-side:* quote and run refuse a script whose text contains
|
|
1327
|
-
U+FFFD with 400 `script_encoding_lost`, before any charge. Such a script was
|
|
1328
|
-
accepted before and billed for about a second of speech. The bytes were lost
|
|
1329
|
-
before the request left the client: send the script as valid UTF-8.
|
|
1330
|
-
(clipwright#131)
|
|
1331
|
-
- *Server-side:* a run whose speech is impossibly short for its script fails with
|
|
1332
|
-
`speech_too_short_for_script` and is charged nothing, instead of succeeding.
|
|
1333
|
-
Retrying rarely helps. (clipwright#131)
|
|
1334
|
-
- *Server-side:* a new sign-up gets an admitted account with zero credits, so it
|
|
1335
|
-
is no longer refused with `account_not_admitted` until the owner admits it.
|
|
1336
|
-
(clipwright#112)
|
|
1337
|
-
|
|
1338
|
-
## [0.6.0] - 2026-09-06
|
|
1339
|
-
|
|
1340
|
-
### Added
|
|
1341
|
-
|
|
1342
|
-
- `@clipwright/cli` installs a second binary, `clipwright-cli`, next to
|
|
1343
|
-
`clipwright`. An unrelated npm package also ships a `clipwright` binary; the
|
|
1344
|
-
second name avoids that collision. `core`, `sdk` and `mcp-server` have no
|
|
1345
|
-
changes in this release and moved to keep one version. (clipwright#105)
|
|
1346
|
-
|
|
1347
|
-
## [0.5.0] - 2026-09-06
|
|
1348
|
-
|
|
1349
|
-
### Added
|
|
1350
|
-
|
|
1351
|
-
- `POST /v1/uploads` takes a local PNG or JPEG of up to 10 MB and returns
|
|
1352
|
-
`upload_id`, `url`, `media_type`, `bytes`, `width`, `height` and `expires_at`.
|
|
1353
|
-
Pass the https `url` as `image`. The url is valid for 24 hours and the object is
|
|
1354
|
-
kept for 7 days. An account may upload 20 images a day. New refusal codes:
|
|
1355
|
-
`invalid_image`, `unsupported_media_type`, `upload_cap_exceeded`.
|
|
1356
|
-
(clipwright#99)
|
|
1357
|
-
- MCP tool `upload_image`, SDK `uploadImage()`, CLI `clipwright upload <path>`, and
|
|
1358
|
-
`--image`, `--image-file`, `--aspect-ratio`, `--resolution` on CLI `make` and
|
|
1359
|
-
`quote`. (clipwright#99)
|
|
1360
|
-
- `tts_model` input (`eleven_v3` or `eleven_multilingual_v2`) and CLI
|
|
1361
|
-
`--tts-model`. Without it the preset's model is used. Each voice in the catalog
|
|
1362
|
-
names its `model`. A script over the model's character limit (v3 5,000, v2
|
|
1363
|
-
10,000) is refused before any charge, in addition to the 180-word ceiling.
|
|
1364
|
-
(clipwright#101)
|
|
1365
|
-
- MCP `tools/list` describes `image`, `aspect_ratio`, `resolution`, `voice` and
|
|
1366
|
-
`voice_id`; the descriptions were empty before. (clipwright#99)
|
|
1367
|
-
|
|
1368
|
-
### Changed
|
|
1369
|
-
|
|
1370
|
-
- *Server-side:* the `owner_ru_clone` preset speaks on `eleven_v3`. All presets
|
|
1371
|
-
used `eleven_multilingual_v2` before. (clipwright#101)
|
|
1372
|
-
|
|
1373
|
-
## [0.4.0] - 2026-08-28
|
|
1374
|
-
|
|
1375
|
-
### Changed
|
|
1376
|
-
|
|
1377
|
-
- **Breaking:** the default API address in the SDK, CLI and MCP server moved to
|
|
1378
|
-
`https://api.clipwright.io`. The old address
|
|
1379
|
-
`https://api-production-7e69.up.railway.app` still answers, so older clients
|
|
1380
|
-
keep working. If your network allowlists hosts, add `api.clipwright.io`, or pin
|
|
1381
|
-
the old address with `CLIPWRIGHT_API_URL` or the SDK `baseUrl` option. (US-613)
|
|
1382
|
-
|
|
1383
|
-
## [0.3.0] - 2026-08-28
|
|
1384
|
-
|
|
1385
|
-
### Removed
|
|
1386
|
-
|
|
1387
|
-
- **Breaking:** `@clipwright/core` no longer exports `MAX_SCRIPT_SECONDS`. Code
|
|
1388
|
-
that imports it fails; `SCRIPT_SECONDS_BASIS` holds the value (and was removed
|
|
1389
|
-
in turn in 0.7.0).
|
|
1390
|
-
|
|
1391
|
-
### Changed
|
|
1392
|
-
|
|
1393
|
-
- **Breaking:** the CLI and the MCP server refuse a `CLIPWRIGHT_API_URL` that is
|
|
1394
|
-
not `https`. Loopback addresses may stay `http`. Point the variable at an https
|
|
1395
|
-
address. (clipwright#85)
|
|
1396
|
-
- **Breaking:** every URL field of the input is limited to 2,048 characters
|
|
1397
|
-
(`MAX_URL_LENGTH`). A longer URL is refused with 400. Pass a URL of at most
|
|
1398
|
-
2,048 characters, for example by hosting the file at a shorter address.
|
|
1399
|
-
(clipwright#85)
|
|
1400
|
-
- **Breaking:** SDK requests now have deadlines. `requestTimeoutMs` (per client,
|
|
1401
|
-
default 30 s) bounds every request, and `maxWaitMs` (per `makeUgc` call, default
|
|
1402
|
-
10 min) bounds the whole call, including the request in flight. A call that used
|
|
1403
|
-
to hang now rejects. A start request cut off mid-flight throws
|
|
1404
|
-
`ClipwrightResponseError` with `mayHaveTakenEffect: true`: check the run before
|
|
1405
|
-
retrying with a new idempotency key. Raise `requestTimeoutMs` behind a slow
|
|
1406
|
-
proxy.
|
|
1407
|
-
- **Breaking:** *Server-side:* a run from an account not admitted to the beta is
|
|
1408
|
-
refused with 403 `account_not_admitted` before any charge. Topping up does not
|
|
1409
|
-
lift it. The clients parse this refusal from 0.3.0 on. (US-620)
|
|
1410
|
-
- The voice catalog is in English, and the SDK validates the `GET /v1/voices`
|
|
1411
|
-
response. Each voice has `name`, `language`, `gender` and `description`.
|
|
1412
|
-
(clipwright#85)
|
|
1413
|
-
- The MCP server checks the shape of `run_id` in `get_run`. (clipwright#85)
|
|
1414
|
-
- *Server-side:* the video link in a finished run is signed for 7 days instead of
|
|
1415
|
-
1. (clipwright#22)
|
|
1416
|
-
- *Server-side:* a failed run is charged only if the vendor accepted the work that
|
|
1417
|
-
produces the clip. A run that paid only for speech is charged nothing.
|
|
1418
|
-
(clipwright#46)
|
|
1419
|
-
- *Server-side:* credits bought while an account has debt pay the debt first; only
|
|
1420
|
-
the rest reaches the balance. (US-611)
|
|
1421
|
-
|
|
1422
|
-
### Fixed
|
|
1423
|
-
|
|
1424
|
-
- *Server-side:* 401 and validation refusals use the declared error body.
|
|
1425
|
-
Validation errors return `invalid_request` and list each problem as
|
|
1426
|
-
`field: reason`, up to 12. Before, clients reported these bodies as "not a
|
|
1427
|
-
Clipwright error object". (US-616)
|
|
1428
|
-
- *Server-side:* the 202 response of a run carries its `warnings[]`; it always
|
|
1429
|
-
returned an empty list before. (clipwright#64)
|
|
1430
|
-
|
|
1431
|
-
## [0.2.0] - 2026-07-29
|
|
1432
|
-
|
|
1433
|
-
### Added
|
|
1434
|
-
|
|
1435
|
-
- `@clipwright/cli` is published for the first time, under MIT. Commands:
|
|
1436
|
-
`quote`, `make`, `runs <id>`, `voices`. `make` takes `--script`, `--person`,
|
|
1437
|
-
`--captions`, `--voice`, `--voice-id` and `--retry`. (US-622)
|
|
1438
|
-
- *Server-side:* `GET /v1/account` returns `account_id`, `balance_credits`,
|
|
1439
|
-
`debt_credits`, `holds_credits`, `daily_remaining_credits` and `grants`.
|
|
1440
|
-
(US-602)
|
|
1441
|
-
- `@clipwright/core` exports the refusal schemas and the retry policy:
|
|
1442
|
-
`parseApiFailure`, `isRetryableFailure`, `retryDelayMs`, `agentFailureReport`,
|
|
1443
|
-
`apiError`, the 402 and 429 bodies, the rate-limit header names, `account` and
|
|
1444
|
-
`creditGrant`. (US-622)
|
|
1445
|
-
- *Server-side:* a service-wide daily spend cap; a run past it is refused with
|
|
1446
|
-
`global_cap_exceeded`. (US-603)
|
|
1447
|
-
|
|
1448
|
-
### Changed
|
|
1449
|
-
|
|
1450
|
-
- **Breaking:** *Server-side:* a run reserves credits before rendering. Without
|
|
1451
|
-
enough balance the API answers 402 `insufficient_credits`; with unpaid debt, 402
|
|
1452
|
-
`debt_outstanding`, whatever the balance. Buy credits to lift either. (US-602)
|
|
1453
|
-
- **Breaking:** *Server-side:* rate limits per account: 60 requests a minute for
|
|
1454
|
-
starting runs, 300 for quote, voices, run status and account. Over the limit
|
|
1455
|
-
the API answers 429 `rate_limited` with `Retry-After` and `X-RateLimit-*`
|
|
1456
|
-
headers; wait and repeat the same call. At most 3 renders run at once per
|
|
1457
|
-
account; a fourth queues and still returns 202. (US-605)
|
|
1458
|
-
- **Breaking:** the SDK throws `ClipwrightApiError` or `ClipwrightResponseError`
|
|
1459
|
-
(both extend `Error`) instead of a plain `Error`, and reads the status before
|
|
1460
|
-
the body. Code that parsed the message text should read the error's status and
|
|
1461
|
-
code instead. `makeUgc` now waits out 429 and 5xx while polling; money refusals
|
|
1462
|
-
and other 4xx still throw at once. `attempt` must be a positive safe integer and
|
|
1463
|
-
is checked before any request. (US-622)
|
|
1464
|
-
- **Breaking:** MCP tools return a refusal as a JSON report inside the text block,
|
|
1465
|
-
with `isError: true`, instead of one sentence. Agents should branch on its
|
|
1466
|
-
`retryable` field, not on prose. (US-622)
|
|
1467
|
-
- The MCP server starts when `~/.clipwright` is read-only; only `make_ugc`
|
|
1468
|
-
refuses, naming the variable that fixes it. (US-622)
|
|
1469
|
-
- `SKILL.md` inside `@clipwright/mcp-server` is in English. (US-622)
|
|
1470
|
-
- *Server-side:* idempotency keys are scoped to the account, so two accounts can
|
|
1471
|
-
use the same key. (US-604)
|
|
1472
|
-
|
|
1473
|
-
## [0.1.0] - 2026-07-26
|
|
1474
|
-
|
|
1475
|
-
### Added
|
|
1476
|
-
|
|
1477
|
-
- First publication of `@clipwright/core`, `@clipwright/sdk` and
|
|
1478
|
-
`@clipwright/mcp-server` under MIT. `@clipwright/cli` was not published.
|
|
1479
|
-
- API: quote (`POST /v1/skills/make_ugc/quote`), run
|
|
1480
|
-
(`POST /v1/skills/make_ugc/run`, `Idempotency-Key` required), run status
|
|
1481
|
-
(`GET /v1/runs/{id}`), voice catalog (`GET /v1/voices`). Requests carry a
|
|
1482
|
-
`cw_*` bearer token. (US-205, US-516, US-550)
|
|
1483
|
-
- MCP tools `quote_ugc`, `make_ugc`, `get_run`, `list_voices`. `make_ugc` returns
|
|
1484
|
-
a `run_id` at once, and the agent polls `get_run`. (US-206, US-512, US-516)
|
|
1485
|
-
- SDK `ClipwrightClient` with `quoteUgc`, `startUgc`, `makeUgc`, `getRun` and
|
|
1486
|
-
`listVoices`. The idempotency key comes from the input and
|
|
1487
|
-
`CLIPWRIGHT_CLIENT_ID`; `attempt` starts a deliberate new run. (US-201, US-202)
|
|
1488
|
-
- Input: `script` (up to 180 words), `voice`, `voice_id`, `image`,
|
|
1489
|
-
`aspect_ratio` (default 9:16, 16:9 supported), `resolution`, `captions`,
|
|
1490
|
-
`disclosure_overlay`. Parameters that are not honoured come back in
|
|
1491
|
-
`warnings[]`; `webhook_url` is refused with 400. (US-533, US-535, US-539)
|
|
1492
|
-
- Quote returns `credits_estimate`, `duration_estimate_sec`, `warnings`,
|
|
1493
|
-
`contract_version`, `source` and `resolved_aspect_ratio`. A source whose aspect
|
|
1494
|
-
ratio differs from the request by more than 15% is refused before any charge;
|
|
1495
|
-
up to 15% it is snapped with a warning. (US-525)
|
|
1496
|
-
- Credits: 30 per second of video, reserved at start and charged on the measured
|
|
1497
|
-
duration. *Server-side:* a per-account daily spend cap refuses runs with
|
|
1498
|
-
`daily_cap_exceeded`. (US-538, US-537)
|
|
1499
|
-
- Contract version `2026-08` in `X-Clipwright-Contract` and `contract_version`.
|
|
1500
|
-
(US-533)
|