Skip to content

Release 0.13.0 - #848

Merged
dkackman merged 30 commits into
masterfrom
develop
Oct 12, 2026
Merged

dkackman merged 30 commits into
masterfrom
develop

Conversation

@dkackman

Copy link
Copy Markdown
Owner

Merges develop into master for 0.13.0. This is 32 commits since v0.12.0. The release notes are drafted in docs/RELEASING.md under 0.13.0.

Highlights: reference pickers in the web UI (asset:, prompt:, output:, prefixes, for_each and builtin:), with a thumbnail browse dialog; workspace-scoped Workflows and Assets pages; gallery video grids drawn from first-frame thumbnails, and MP4 faststart; quantized-cache KEY_VERSION sweep and fixes to cache clearing (#838-#842, #844, #847); dependency floors refreshed.

Fixed during the pre-release review:

  • huggingface-hub floor reverted to >=1.33.0. Every PyPI diffusers caps hub below 2.0, so >=2.2.0 made a PyPI install unresolvable. CI e2e had been red since that commit.
  • dw/tasks/cuts.py trimmed to 1,098 lines. At 1,100+ it failed the engine size ratchet, which had been red since plan_cuts reads the song length from a suspect tail chunk before dropping it #843.
  • The UI asset and output listings retry after a failed fetch. Before, a failure left them empty for the rest of the session.

Checks: develop CI is green (backend, ui, e2e). Locally, 13,914 backend tests and 545 vitest tests pass; lint, svelte-check and both ratchets are clean.

Review notes, not blocking: the quantized-cache startup sweep deletes *.tmp-* without checking for a live writer. That only matters if two servers share one cache root. Out-of-order listing responses during a workspace switch can briefly show the previous workspace's items.

🤖 Generated with Claude Code

dkackman and others added 30 commits October 11, 2026 19:20
…rphaned staging; memoize scan_all; quiet rescan logging

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…entry.json

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…empty)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…during-clear rule

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…-cache entries

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
#147 let a scheduler or audio_scheduler block be just {"shift": ...}, but
the full view read scheduler.configuration.scheduler_type unguarded. The
throw left the compact digest on screen while the toggle said full - every
H3 template's step. The scheduler section now takes either form, edits the
shift, and shows audio_scheduler; the digest reads both as scheduler lines
rather than listing audio_scheduler as a component.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…faststart

The gallery put a <video preload="metadata"> in every tile. With 310 clips
on lem each one held a connection, and the page hung - the listing itself
answers in 42 ms. The thumbnail route now answers for a video with its
first frame (same ETag/304 validator as an image), and the gallery,
workflows, workflow and overview grids show that as a lazy <img> with a
play badge. The detail views keep their <video>. The assets page is
unchanged: the thumbnail route reads outputs only.

Neither diffusers writer takes muxer options, and both leave the moov atom
after the media data, so a browser fetched the head and then the tail of
every clip before it could show a frame. media.faststart remuxes a saved
MP4 output in place (stream copy, ~0.1 s for a 60 s H3 clip) and keeps the
file as written if that fails. Existing outputs are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…other versions

An entry saved under an older derivation of the key's inputs records the
same package versions as a current one but can never be hit again, so the
version-only sweep kept it forever - lem held 12 such H3 entries (~166 GB)
from before the post-load config read and the hash-ordered module lists
(#826) were fixed. KEY_VERSION goes into the key and entry.json; the
startup sweep deletes an entry with none or another one. This first one
(2) sweeps every entry made before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he examples

The read-only examples were mixed in among the workspace's workflows - 96
templates beside 42 of its own on lem. The workspace page now lists only
writable libraries' workflows, with a quiet "examples N" link to the
shared Examples page; an empty workspace points there too. The Overview's
Workflows panel counts and features the same population.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… an example

A new (unsaved) workflow's file panel gains two rows above folder:
workspace - which workspace it saves into - and start from - blank, or any
of the read-only examples, which loads that example and names the file
after it. New from on a workflow page arrives with that workflow chosen as
the start, so New from and a workspace's + land on the same form.

Moving a draft to another workspace hands it over the way a gallery import
already does (definition, file name, start), and routes there; the
editor's load effect now reads the workspace so the move takes it back
up. New from no longer toasts "Imported from image metadata".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A field that starts an asset: reference now offers the asset library -
thumbnails, a glyph for audio and video, which library it came from - and
prompt: offers the prompt library searched through text, tags and
description, each row showing the prompt's first line. Search matches
every word anywhere in the name, so asset:pri finds cast/priya.png.

Suggest takes an optional `complete` function for these richer rows;
fields wired: variables (editor and run form), arguments, mapping values,
and media inputs, which keep asset completions to their kind and preview
an asset: value. The expanded prompt box's native select becomes the same
search. The asset listing loads on first use per workspace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dialog shows the library as a thumbnail grid, by library in resolution
order (this workspace, shared, examples), searchable, kept to the kind a
media field takes, with the field's current asset marked. Media inputs get
a browse button; a variable or argument holding an asset: reference gets
one beside it.

The gallery thumbnail route now takes an asset: name the way the other
media routes do, so the picker and the asset: completions show small JPEGs
(and a video's first frame) rather than loading full files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
output: now completes like asset: - what earlier runs wrote, newest first,
each row a thumbnail, workflow/file, subfolder and date, and the gallery's
run number. The browse dialog becomes a two-tab picker (Assets | Earlier
runs); the runs tab groups by workflow and can pick the `latest` form so a
later stage follows the newest run. A field holding output: gets the same
browse button and opens on that tab; a media input previews an output:
value, latest included.

The asset and output listings share one lazy, per-workspace store
(lazylist.svelte.ts); the dialog refetches runs on each opening and the
Gallery page refreshes the listing when it loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty field that takes a reference lists asset:, output: and prompt:
on ArrowDown, each with what it names, and two letters that start one
offer it; picking a prefix continues the value - a draft, not a commit -
and the list goes on to that library. Suggest merges a completion's rows
with its plain suggestions, and opens on focus only when asked
(the stored-prompt search).

Step fields now offer item: and item:<field> inside a for_each step,
gather:<step> and previous_result:<step>@<entry> for earlier for_each
steps, and a plain previous_result: to a for_each step only from a
for_each over the same list - drawn from flow.ts's own refusal rules, so
nothing offered is then flagged as dangling.

A sub-workflow step's path field offers the packaged fragments as
builtin: names, listed by a new GET /api/builtin-workflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reference-picker rows pushed app.css to 659 lines, over the UI
ratchet's 600-line ceiling (files_over_size_ceiling 0 -> 1). The list's
rules now live in Suggest.svelte as :global() - it is portalled to the
body, so they must stay global - beside the markup they style.

The baseline's complex_functions is lowered 12 -> 11: splitting
referenceSuggestions and forEachReferences into helpers brought one
long-standing function under the limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pyproject.toml floors raised to the tested venv by
scripts/refresh_dep_floors.py (torch 2.14.1, transformers 5.19.0,
accelerate 1.15.0, peft 0.21.2, fastapi 0.143.0, mcp 2.3.0, ruff 0.17.0,
and the rest). transformers' !=5.17.0 goes with the floor past it - 5.19
casts only a BatchFeature, so the #232 preprocess bug is gone - and its
test now asserts the requirement refuses 5.17.0 rather than the spelling.

diffusers stays >=0.40.0: git HEAD, which Kandinsky 6's piflow scheduler
needs, still reports 0.41.0.dev0, which pip ranks below a 0.41.0 floor.
Raise it when main moves to 0.42.0.dev0.

constraints-openapi.txt moves to fastapi 0.143.0 / pydantic 2.14.1; the
dumped OpenAPI document is unchanged under them.

npm: ranges raised to the installed releases (Playwright 1.64, Svelte
5.57.2, Vite 8.3.4, ESLint 10.12, typescript-eslint 8.71.2, bits-ui
2.19.5, the @lucide/svelte/prettier/vitest bumps) and the DOMPurify
override to 3.4.17. TypeScript and Node (@types/node, engines) are left
where they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
huggingface_hub 2.0 removes the `huggingface-cli` entry point, leaving
`hf`; `hf auth login` already works on the 1.x line installed now. The
gated-model RuntimeError, its tests, README, DEPENDENCIES.md, CLAUDE.md
and .env.example all named the old command - this is the one change a
move to huggingface-hub 2.x needs from us (the suite passes on 2.2.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing caps it below 2 (transformers, diffusers and tokenizers allow
<3). 2.0 moves the HTTP stack to httpx2 and drops long-deprecated APIs
and the huggingface-cli entry point; dw used none of those APIs, and the
login hint moved to `hf auth login` in f404b00.

Verified on 2.2.0: the full suite; on this Mac, public and Xet-backed
downloads, a gated repo refused without a token (GatedRepoError,
dw.plan._model_info blocked, components' auth error mapped), and diffusers
and transformers loads; on lem with its token, FLUX.1-dev's gated config,
_model_info reporting it unblocked, and its VAE weights loaded through
diffusers from a cold cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s first

Deploying 60c2ea5 (huggingface-hub>=2.2.0) failed on lem and mini-ai:
their git diffusers (122b1e11) pins huggingface-hub<2.0, and pip takes an
installed git build as fixed, so `pip install -e .` had no solution. The
rerun then reported success: the failed run had already pulled, so
pyproject.toml no longer showed as changed, the install was skipped, and
the server restarted onto the old packages.

The reinstall now keys on the pyproject.toml last installed successfully
(a hash in venv/, written only after the install), and runs install.sh's
order - diffusers from git, `pip install -e .`, then `pip install
diffusers` for whatever the new commit depends on - as
dw/server/updater.py does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The running copy of deploy.sh is the one from before its own pull, so a
fix to it took effect only on the deploy after the one that brought it -
bb64146 needed two deploys on each box. When the pull changes the
script, it now execs the new copy, passing the commit it started from
(DW_DEPLOY_BEFORE) so the new run still sees everything the pull changed
and does not hand off again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every PyPI diffusers (0.40.0, 0.41.0) requires huggingface-hub<2.0, so a
>=2.2.0 floor makes a PyPI install unresolvable (CI e2e: ResolutionImpossible).
Git diffusers allows <3, which is why lem and mini-ai installed it. hub 2.x
still works where diffusers allows it; raise the floor once a diffusers
release does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d5305df (#843) took it to 1,102 lines and the engine ratchet has failed
CI since. Two comments merged or dropped (the dropped one restated the
warning text below it); no code change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed fetch read as an empty library and was never retried until the
workspace changed, so a server restart left asset: and output:
completions and the picker empty for the session. An ensure() now
refetches once RETRY_MS has passed since the failure - not sooner, since
the failure itself re-runs the derivation that asked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dkackman
dkackman merged commit 9bec123 into master Oct 12, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant