LoRA Dataset Studio v2026.08.10
Two ways to install — and they do not update the same way
git cloneis the one to prefer. Update & restart then runsgit pull --ff-only,
so you get every fix the moment it lands — often days before it is packaged into a
release like this one.This ZIP is a snapshot of this tag. Update & restart will only ever move you to
the next release, so a fix shipped today reaches you whenever the next one is cut.git clone https://github.com/perfectgf/lora-dataset-studio.git cd lora-dataset-studio start.batAlready running a clone? You do not need the ZIP below.
🎁 What's new in v2026.08.10
Find crops & variants shows its work, and remembers running
Three things went wrong around this pass, none of them in the grouping itself. A "Launch all" you stopped before it reached the pass kept announcing "cancelled before it ran" — next to a standalone run that had just found 2358 groups; a step re-run since the report was written now says so, and the banner drops its 🛑 once nothing is left waiting. The run itself showed one line and then nothing for minutes, because its slowest phase — re-reading every file to prove none moved while it worked — ran unannounced; both phases now fill the bar. And the Bank had no memory of the pass at all, so the only way to know whether you had run it was to run it again: the launch window now tells you when it last ran and what it found, and relaunching an untouched Bank answers "already up to date" in a second instead of redoing the work.
The bank filters now sit beside the images they filter
Changing a filter on a 20 000-image bank meant scrolling up to the chips, clicking, and scrolling back down to see what it did. The filters now live in a rail down the left of the grid, and the rail stays put as you scroll, so the chips are still beside the images ten thousand rows down and the result is in front of you as you click. The eight analysis passes moved into a ⚙ Passes panel you open when you need them — all of them are still there, each with the same window, scope and counts as before — which gives the images the third of the screen the passes used to hold. Score, Framing, Medium, Angle, Resolution and Origin fold behind 🎛 More filters so the everyday chips stay on one screen. On a narrow window the rail becomes a drawer behind ☰ Filters, and it remembers whether you keep it open.
Tell whose line is whose on a multi-dataset Canvas
Every connector on the board used to be the same pale grey, so once two datasets had pictures parked near each other their lines crossed and became one tangle. Each dataset now draws its links in its own colour, shown as a dot next to its name in the lane header. The colour is fixed per dataset, so it is the same next time you open the board. The three colours that mean something keep meaning it: amber for a superseded branch, violet for "blended from", cyan for an external LoRA file.
Judge a dataset image while you are looking at it — K, R, S
The full-screen view is where you can actually see whether a hand is right, but the ✓/✕ lived on the thumbnail behind it. It now carries the Bank review bar: ✓ Keep (K), ✕ Reject (R), ⏭ Skip (S or →), and each verdict moves you to the next picture as soon as it is saved. Same keys as ▶ Review in the Image Bank, same green and red, and the same status the grid writes — a chip beside the name says whether the image is kept, rejected or still undecided. ← still goes back without deciding anything, and nothing is ever deleted.
Park a pinned picture below its lane without shoving the next dataset
On the Canvas, dragging a pinned image above its dataset always let it float free — dragging it below pushed every dataset underneath further down the board. Pinned pictures now sit on a free layer in both directions: they overlap the lane below if you park them there, and nothing else moves. Fit still frames them, Export PNG still includes them, and ✦ Tidy up still brings them back beside the run that made them.
Set up ChatGPT with your Plus/Pro plan, no API key
The first-run Setup screen only ever offered an OpenAI API key, so the ChatGPT engine looked like it cost money per image. It now shows both ways in side by side — paste a key, or sign in once with your ChatGPT Plus/Pro subscription and run on your plan's image quota. The step turns green as soon as either one is in place.
Grids and the board load in a blink
Every thumbnail surface — the Canvas board, the dataset grid, Test Studio result tiles, checkpoint pills and the run cards — used to download and decode your full-resolution images just to paint a small tile. They now ask for a right-sized WebP thumbnail instead: a board that pulled 47 MB of pictures fetches 0.4 MB, and off-screen tiles no longer load at all. Opening an image, downloading it or exporting the board still uses the full-quality original — and a pinned image now carries an HQ button that swaps its tile for the original file in place, one picture at a time, for when you are judging skin or fine text and a re-encode is not good enough. A group of pinned images has the same HQ in its title bar, next to Export grid: one click puts the whole strip on its original files for a side-by-side comparison, and one more click gives the board its fast tiles back.
See how hard the machine is working, without leaving the board
The Canvas toolbar now carries a small CPU · GPU · VRAM · RAM readout of the machine running LDS, so you can tell a run that is working from one that is stuck without opening Task Manager. It turns amber past 50% and red past 80%, refreshes only while the tab is open, and folds away with ▾ if you would rather not see it. No NVIDIA card: it simply shows no GPU numbers.
Full-height images on a tablet, with the facts beside them
Opening a generated image on a tablet in landscape used to shrink it to a thumbnail with the prompt, Download and ✨ Upscale & improve buttons stacked below the fold. The picture now takes the whole height on the left and everything else reads in a scrollable column on the right — the same split you already had on a desktop, from 768 px up. Held upright, or on a phone, the stacked layout is unchanged.
The canvas gives the board back its screen on a phone
On a phone the filter row was three wrapped lines floating on the board and the search box you rarely type in took most of one — it is now two lines: the chips keep their icon and their count, and 🔍 unfolds the search only when you ask for it (with the words still shown on the chip while a search is narrowing the board). The page blurb stays out of the way up to a laptop width, and a run in flight is announced once instead of twice when the Generate sheet is open. The board’s floating rows are also properly opaque now, so a strip of pinned images parked in a corner can no longer be read through Reset.
See which images an external LoRA actually touched
A permanent cyan line now joins each 🔌 plugin node to every board image generated with it, and an image’s facts panel lists its External LoRAs on their own row instead of filing them under always-on.
Preview images that finally show YOUR subject
The preview prompts a run renders every few hundred steps used to be generic defaults that describe nobody — so the images you judge an expensive run by showed a stranger. A new 🎲 Use dataset captions button under Preview prompts fills the field with up to five real captions drawn at random from this dataset’s kept images. Click it again for a different draw.
The LoRA Canvas gives the board back to your phone
On a phone the board’s bottom controls took a quarter of the screen, and tapping ☝ Gestures buried the board under its own instructions with no way to put them away. The row is icons-only below a tablet — two rows instead of five, every button still thumb-sized — and the gesture help is now a sheet that floats over the board and closes with its ×. Nothing changes on a desktop.
Pin any LoRA onto the Canvas, even one you never trained here
Pin any LoRA from your ComfyUI folder onto the LoRA Canvas as a 🔌 plugin node and stack it on your generations, with its own strength. It stacks on a run anchored by a checkpoint trained here — there is no solo generation from an external LoRA alone.
The Canvas gives the screen back to the board
Everything that steers the LoRA Canvas — the zoom row, Fit, Tidy up, Generate, the colour key, the gestures sheet, the dataset filter and the banner announcing finished images — used to be stacked above the board. On a phone that chrome cost most of the screen before a single card was drawn, which is why the board opened tiny and pinned under a wall of buttons. Those controls now float ON the board: what it is showing sits along the top, what you do to it sits along the bottom within thumb reach, and the board itself takes back the space they were using. Nothing was removed and nothing moved to another page — the same controls, on the surface they act on.
The canvas filters stopped eating half the screen
The Datasets panel was a fold-out card: unfolded on a library of fourteen datasets it stood 389 px tall on a 720-px screen — 54 % of the window, directly above the board, for anyone who had ever left it open. It is now a single row of chips about 40 px tall. Datasets, Models and Status each open a small menu with the same checkboxes (the dataset menu gained a search of its own, which the three-column list never had), Pinned images and Reset stay in the row, and the run search keeps its full-size box. Every chip shows its count and lights up while it is filtering, so nothing can narrow your board without saying so — and the menus now open above the board instead of under a pinned image.
Run cards stay readable when you zoom the board out
A board holding a dozen datasets is read at 30-40 % zoom, and at that scale a run card's title renders at about four pixels: the canvas was showing you everything and telling you nothing, so finding a run meant zooming in on each one in turn. Below 55 % every card now carries its run number at a constant, readable size, and below 30 % it carries the dataset name too — because the lane headings have gone unreadable by then as well.
Keep a board arrangement instead of losing it to ✦ Tidy up
Laying two datasets' renders out side by side to judge a likeness takes twenty minutes, and until now the board only ever held ONE arrangement: the moment you needed it for something else, your only options were to leave it there forever or throw it away. 💾 Layouts in the board toolbar saves where every run card and every pinned picture sits — closed pictures included — under a name, and puts it back whenever you want. A run deleted since is simply not restored, and the app says how many, rather than leaving you to hunt for the card that is missing.
Save the whole board as a PNG
📷 PNG in the board toolbar writes the entire canvas to one image file: every pinned picture at full size, every run card with its checkpoints, and the lines that join them. Useful for a comparison you want to keep, post, or look at next to something else. It is a redraw of the board, not a screenshot, so the buttons and badges are not in it — and a picture whose file has been cleaned off the disk comes out as a labelled placeholder instead of silently missing.
Bin a bad render from the board itself
The board is where you actually decide a render is a failure — and deleting it meant closing the node, opening the run, finding the checkpoint, opening its gallery, entering Select mode and finding the same picture again. Pinned images now carry a 🗑 next to their ✕. Press it once to arm it, again to delete: ✕ still only takes the picture off the board and remembers where it was, 🗑 deletes the image itself, through the same route (and the same recoverable-or-not setting) the gallery uses.
LoRA strength and blend weights now go up to 5
The weight slider of a 🧬 Blend stopped at 2 and the strength sweep at 4 — both were comfort limits, not technical ones, and pushing an under-trained LoRA or an overwhelming style meant leaving the app for a hand-built workflow. The ceiling is 5 everywhere now: the blend slider, the strength chips behind « + », and the server that validates them. The weight next to each slider is also typeable, so getting to 3.35 no longer means eighty small drags.
A second cloud run on one dataset now actually asks you
Launching a second cloud training on a dataset that already had one was supposed to ask "launch anyway?" and go ahead if you said yes. The question never reached you: the refusal arrived as an error toast printing the question at you, with no way to answer it, so the second run was simply impossible however many times you tried. The confirmation now appears and the run starts when you accept. Nothing about what is allowed has changed — the guard, your fleet limit and your budget behave exactly as before; the answer you gave it was being thrown away. Reported by Arrow (Discord).
Your generated shots are finally all the same size
Klein and Krea 2 Edit used to size their images by two unrelated rules, so one dataset could hold 2 MP Klein tiles next to 0.84 MP Krea ones, in different shapes, with nothing on screen explaining either. There is now a single Output size dial at the top of the Generate variations panel, above the shot cards: both local engines spend that budget, on the shape of the shot card you picked. Klein therefore stops inheriting your reference photo's frame — a 16:9 card renders 16:9 even if your reference is portrait. It ships at 2.0 MP, exactly what Klein always did, so nothing moves until you touch it; drop it for quicker, lighter trial runs, or leave it at 2.0, which is as far as these edit models hold together (go bigger afterwards with ✨ Upscale & improve).
Start ComfyUI from the banner that tells you it is down
When LDS cannot reach ComfyUI, the banner explaining it offered one button: "I restarted ComfyUI — clear it", which only lets you say someone else fixed it. On an install whose ComfyUI this app can launch, there is now a ▶ Start ComfyUI button right there, and it comes first: it is the one that ends the outage rather than declaring it over. The banner then clears itself once ComfyUI actually answers, so a start that spawns and dies cannot be mistaken for a fix, and your paused job resumes on its own. The button is deliberately absent when your ComfyUI is not ours to launch — ComfyUI Desktop, your own launcher script, or one running on another machine — because on the one screen whose job is to unblock you, a button that fails costs more than no button at all.
Picking a Klein model no longer switches Klein off
Choosing a model from the workspace dropdown stored its name without the folder it lives in — and the check that guards that setting only recognised the full path. So the app wrote a value its own guard then called missing, the engine went dark, and the message said no file was missing or broken. Both spellings are now accepted, so nothing you picked was ever wrong. And an unresolvable model no longer takes the whole engine hostage while usable Klein builds sit on your disk: the card asks you to pick one instead. What has not changed is the promise that made that guard exist — a run never quietly loads a file other than the one shown.
Krea 2 Edit now ships tuned for likeness, not for variety
Its two identity dials shipped unpaired — reference grounding at 512 with a reference pull of 0.25, a quarter of what the calibrated 512 profile used. A benchmark scoring generated faces against the reference measured the 1024 / 4.0 pair ahead by a clear margin on bust shots, and it got there while pulling LESS hard on the reference, so the likeness is not bought by recopying the pose you asked to change. Both dials, and sampler steps, now ship at those values. If you had never touched them, your next generations will resemble your reference more; if you prefer the looser, more varied restaging, set grounding back to 512 and the pull to 1.0. Anything you had already changed yourself is left exactly as you set it.
Change the model where you are working, not in Settings
The Krea 2 base could only be set in Settings, so the one thing you reach for when a whole run looks wrong meant leaving the screen you were judging on. It is now in the Krea 2 Edit panel of the work screen, using the same searchable list and writing the same value Settings shows. The Klein model works the same way, and there is now exactly one of each: change it from a dataset screen or from Settings and it is the same setting either way, applying to every run from then on rather than to the batch in front of you. Previously the Klein model was remembered per dataset, so two datasets could disagree with Settings about which model would actually run.
Every Krea build on your disk is offered, warning and all
A checkpoint measured to render noise under the identity-edit LoRA used to be removed from every Krea list, so a file sitting in your own Krea folder was simply absent, with nothing on screen saying it existed or why it had gone. Choosing is yours: those builds are listed again and you can select them. What the app still will not do is pick one FOR you when nothing is pinned, because a base chosen in silence has already sent a run onto the wrong model without anyone noticing until the output was wrong. It is only elected automatically when it is the only Krea build you have, which beats refusing to run at all.
On a phone, the image you opened finally gets the screen
Opening a dataset image on a phone showed you the buttons, not the picture: Crop, Mirror, two Rotates, two Improves and the Klein note stacked into six full-width rows, leaving the photo about 100 px tall — and side-by-side comparison, the one place where size is the whole point, gave each pane even less. Below a phone-sized width the lightbox now flips: the image (or both comparison panes) takes the screen, and every action — compare, crop, mirror, rotate, improve, upscale, the Klein instruction and its editor — moves behind one ☰ Actions button that opens a panel over the bottom of the picture. Measured at 400 px: a single image goes from 96 to 538 px tall with the Klein editor open, and each comparison pane from 144 to 354 px. Esc closes the panel first and the image second, and ⟨ / ⟩ still walk the grid. On a desktop nothing changes — the side rail was already doing this job with space the image cannot use.
A model you just deployed works right away, not a minute later
Deploy a checkpoint, hit Generate, and the job died: "Your ComfyUI does not offer a model file this workflow requires", followed by advice to go and check your ComfyUI address — which was right all along. The app reads the list of models ComfyUI offers once a minute and reuses it, so a model deployed seconds ago was judged against a list drawn up before it existed, and the refusal it produced is final: the job was never retried. Now, before a job is refused over a missing model, the app asks ComfyUI again — once, on the spot, ignoring what it had cached — and the model it finds is used immediately, spelled exactly the way that ComfyUI spells it. When the file really is absent the job still stops before queuing, but the explanation has stopped guessing: it now says the list was just re-read, so a fresh deploy is not what you are looking at, which leaves a second ComfyUI install as the thing to check.
Every Krea 2 Edit dial, on both screens that talk about it
Krea's four calibration dials used to be split three ways: reference grounding was a slider in Settings but only a read-out in the workspace panel, sampler steps existed in Settings alone, and reference pull and identity LoRA strength existed in the panel alone. "Where do I change this?" had a different answer per dial. Now all four — reference grounding, sampler steps, reference pull, identity LoRA strength — are sliders in BOTH places, so you can retune from wherever you happen to be judging the result. There is still exactly one value per dial: every control writes the same global setting, so nothing can disagree with anything. Each slider says in words what its current number means, and offers Reset to default the moment you leave it. The two file-path fields stay in Settings alone — you fill those once at install, not while looking at an image.
Check any image against your reference photo, side by side
The question you ask of a generated shot is "is this still the same person?" — and until now the only way to answer it was to remember the reference photo from another panel. Open any image in the dataset full screen and press ◐ Compare with reference: the reference and the image sit side by side, each named, each filling its own pane. It works on every image, generated or imported, not just on improve candidates — and on an improved one both buttons are there, so you can flip between "is it sharper?" and "is it still them?". The two never open at once, and neither follows you: press ⟩ and the next picture starts clean. Each pane fits its own image and says so — a square head crop next to a full-body plan has no shared scale to promise, unlike the comparison against the original.
Walk a dataset image by image, without closing the picture each time
Reviewing image 41 of 340 full screen used to mean closing it, hunting tile 42 on the wall, and opening that — for every single image. The inspection view now has ⟨ and ⟩ on the edges of the picture, ← and → on the keyboard, and a 12 / 340 badge telling you where you are. It walks what the grid is SHOWING: chip it down to "awaiting ✓/✕", sort by face similarity, and the arrows follow that list in that order, crossing pages as they go — close the view and you are on the page holding the image you were looking at. The ends do not wrap: on the first image ⟨ goes grey and says so, because a loop that silently restarts makes "have I seen everything?" unanswerable. Zoom, an open comparison pane and a running improvement stay behind with the image they belong to, so the pane labelled "original" is always the parent of the picture in front of you. And since moving is only reading, the arrows keep working while a generation or a captioning pass holds the dataset.
Your LoRA preset can now apply itself, every run
Building a generation-LoRA preset in Settings was only half the job: the tuning panel in the workspace opened on "None" every single time you came back to a dataset, so the preset applied only if you remembered to re-pick it — and a run that forgot showed no LoRA at all in the finished image's metadata, which looks exactly like the app ignoring your settings. Each local engine now has its own "Preset selected by default" in Settings → Image engines: pick one and every run starts there. It stays a starting point, not a lock — you can still choose another preset, or None, for a single run without touching the setting. Shipped as None, so nothing changes until you choose. Preset mechanism by @waltm (Discord).
A LoRA line that would be ignored now tells you, in the editor
Both local engines already load one LoRA outside your presets — Klein its consistency LoRA, Krea 2 Edit its identity edit LoRA — and a preset row naming that same file is deliberately dropped: chaining it twice adds both strengths together, well past what the file was trained for, and the result goes blocky. That drop happened in complete silence, one line in a server log nobody reads. Write such a row now and the preset editor says so on that exact line, explains why, and points at the strength setting to change instead. The check spells the path the same way the server does, so a slash the other way round or a different capitalisation cannot slip past it.
Settings now names the Krea base model your runs actually load
The "Base model file" field said "auto — finds a Krea 2 Turbo/Raw build" and stopped there. If your ComfyUI holds more than one candidate — the official Turbo build next to a community finetune whose filename also reads as turbo — the tie-break picked one and never told you which, so the only way to find out was to open a finished PNG and read its metadata. Every judgement about quality in between was about a model you had not chosen. The field now names the file the next run will load — and, when a filename you pinned yourself was not found under any krea folder, says so and names what is being loaded instead.
Fix the improve instruction where it goes wrong, not in Settings
The note under ✨ Upscale & improve already told you what the pass was about to ask Klein for — "add detailed texture, add sharp details…" — and then sent you to Settings to change it. Now you can change it right there: ✎ Edit this instruction here opens the box under the button, in the lightbox and in the bulk toolbar, already filled with the exact text in force. Rewrite it for a drawing, or untick it and let the pass upscale with no instruction at all; both take effect on your next improve, with nothing to save. It edits the app-wide setting — the same value Settings shows, applying to every dataset — and the panel says so before you touch it. Reset to default appears only once you have actually overridden something, and puts you back on the shipped text rather than on a frozen copy of it, so later improvements to that text still reach you.
Stop on a Bank pass answers you the moment you press it
Press Stop while ✨ Score is writing thirty-six thousand rows and nothing appeared to happen for about three seconds — so everyone pressed it again, several times. The click was always registered instantly; it was the banner around it that took that long to refresh, and the button looked exactly the same before and after. It now changes to "Stopping…" the instant you press it and stops taking clicks, without waiting for anything from the server. It also says what it is waiting for, in the words of the step actually running — "finishing the current batch of 200 rows, then saving" is why the counter keeps moving for a moment after you press. And it tells you the price BEFORE you press: while scores are being written, everything already written stays and only the style grouping has to be redone in full, while during the style grouping itself Stop costs nothing because that step is written whole either way.
A pass no longer dies because something else touched its cache file
A ✨ Score over 37,000 images stopped at image 1849 with "Access denied" on its own cache — not a permissions problem, but an antivirus holding the freshly written file for a fraction of a second while the pass tried to swap it into place. On Windows that is enough to refuse the swap, and the work the pass had already computed and written was thrown away with it. Now the swap waits and retries for a few seconds, and if something really is holding the file the message says so instead of sending you into folder permissions. Better still, nothing is lost either way: work a previous run finished but could not file away is picked up automatically when the pass next starts, so a run interrupted by a lock, a crash or a power cut resumes from where it got to. Recovered work is checked before it is trusted — a half-written file is refused and removed rather than quietly becoming your cache. Applies to ✨ Score, faces, the semantic index and the video search vectors.
Big panoramas and camera masters import now — and the size limit is yours to set
A 10418×2100 panorama used to be refused with "reduce the image before import", which was the only advice possible while the limit was welded into the code. The limit is now a setting, and its default has moved from 16 Mi-pixels / 8192 px per side to 64 Mi-pixels / 16384 px — room for a 61 MP camera master or a stitched panorama without a second thought. Settings ▸ Captioning & quality ▸ Image size budget lets you raise it further, or switch it off entirely; the choices are labelled in the memory each one commits (a decoded pixel costs 3 bytes, and an edit can hold a second copy at once), and "No limit" says plainly what it disarms. One number governs the whole app — import, ZIP and scrape ingest, Bank scan and thumbnails, edits, ComfyUI staging and vision captioning — so an image you can import is an image you can look at. And when something is refused, the message now tells you where to change the budget instead of just telling you to shrink the file.
A dataset you can still look through while it works
Starting a generation, a captioning run or a watermark scan used to freeze the whole grid: you could not open an image full screen, zoom into a face, or even tick a box, on a pass that might run for an hour. Inspecting and selecting are reads — they change nothing — so they now stay available throughout. Editing does not: crop, mirror, rotate, keep/reject, captions and delete still wait for the pass to finish, because a second writer would race it. What changed there is that they stop being silently grey — each one now says which pass is holding it, where that pass has got to and how long it still needs ("⚡ Variation generation is running on this dataset — 12 / 64"), and a line above the grid states the rule once: edits wait, looking and ticking do not.
Choose your Klein and Krea model files from a list instead of typing a filename
The Klein model-file fields and the Krea 2 Edit base model and identity LoRA were blank boxes you had to fill from memory — one typo and the engine quietly used a different file. Each is now a searchable list of the model files actually found in your ComfyUI (extra_model_paths.yaml roots included), with a ↻ to rescan after you drop a new one in, and a plain sentence naming the folder when nothing is there. The Krea base list shows only what the app would really elect, so a checkpoint it refuses is never offered. Typing still works for a file that is not on disk yet, or an absolute path from anywhere.
A model file you chose that is no longer there now stops the engine instead of being swapped
If you pinned a Klein or Krea model file and that file is gone or renamed, the app used to fall back to picking one for you and write a line in a log nobody reads — so the graph loaded a file other than the one on screen, and you only found out from the images. Now the pinned name stays in the field, marked "not found", the engine refuses to start and says which file it is looking for. Clearing the field is the explicit way back to automatic detection. The one exception is the shipped identity/consistency LoRA name, which nobody typed: at its default it still recovers a renamed download on its own.
When Krea 2 Edit does not look enough like your reference, you can now fix it
Krea has two dials that decide how strongly it holds on to your reference photo — the reference pull and the identity LoRA's own strength — and neither had a control anywhere in the app: the only way to move them was to hand-edit config.json. They are now sliders in the "🧬 Krea 2 Edit tuning" panel of Generate variations, right where you judge the result. Reference pull is the one to reach for when the face is too loose (it used to ship paired with reference grounding, so raising grounding alone left you on an uncalibrated mix), and the identity LoRA strength has 50% of headroom above its shipped 1.0. Both write your global Krea settings — the panel says so, and each has a one-click way back to the shipped value.
Every pass now tells you how much longer it needs
"12939 / 37800" told you where a pass was, never whether that meant twenty minutes or four hours — so the only way to find out was to sit and watch. Scan, ✨ Score, faces, framing, medium, captioning, watermark, crops & variants, the semantic index and the video passes now add "about 2 hours left" beside their counter, and a refusal to start a second pass tells you how long the first one still needs. The number is measured over the last minute of real work, not averaged since the pass began: a ✨ Score resuming from cache swallows twenty thousand rows in two seconds and an average would have promised "a few seconds" for the next hour and a half. It stays quiet until it can hold still — you get "estimating time left…" rather than a figure that changes every poll — it says "in this step" once a pass has moved on to a different kind of work, and a step with nothing to count (grouping styles, comparing shots) gets no estimate at all rather than an invented one.
An edited reference photo is no longer lost if the app restarts
Editing your reference photo is a paid call that takes one to three minutes. If the app restarted before you pressed Keep, the finished image was still sitting in your dataset folder — but nothing could reach it any more: the modal came back empty, Keep refused, and the result you paid for was deleted half an hour later. It now comes back waiting for your Keep or Discard. If a second engine was still working when the app went down, it says so plainly instead of spinning forever on a result that is not coming.
Installing the video extra no longer claims success when clips still cannot be cut
The video extra delivers two things — reading your files, and encoding the clips you keep — and Setup only ever checked the first. So on a machine where the bundled ffmpeg never finished downloading (or an antivirus emptied it), the install said "✓ installed successfully" while the "Video bank — clip encoding" row stayed ✗ right underneath, behind the very same ↻ button: you reinstalled the half that already worked. That install now fails honestly and tells you which half is missing and what repairs it. The Setup row got stricter too: it runs ffmpeg instead of trusting that a file exists at the right path, so a truncated or quarantined binary is caught in Setup rather than in the middle of an export.
The face-mask preview no longer disappears when you restart
Looking for faces across a concept dataset is the slow part of the training panel — the detector alone takes seconds to load before the first image, then every kept photo on top. That whole pass used to live only in the app's memory, so restarting the server threw it away and the panel offered to run it all over again. It is now saved beside your images and comes back with them. Stopping a pass keeps its credit too: the faces already found survive the restart, so "Resume — 47 of 153 already analyzed" is still waiting for you. If you changed your kept images while the app was down, the preview comes back labelled out of date rather than pretending to be current.
Train the same dataset twice at once
Launch a second cloud run on a dataset that is already training to compare toolkit settings side by side — confirm the extra pod, then follow each run from its own chip on the Training panel. The runs warn you if the dataset changed between launches.
📐 Framing classifies your whole bank instead of a handful of images
On a bank of any size, 📐 Framing could classify a few images and then quietly stop classifying anything at all — the bar kept moving, the log filled with “vision GPU window renewal failed / database is locked”, and stopping the pass reported four images done out of the twelve it had walked. The pass was starving itself: it saved its results in batches of 25 and held the database write lock between them, across model calls that take seconds each, while the check that lets the app talk to the vision model needs that same database every single call. Failing that check is fail-safe by design, so every remaining image was refused rather than mislabelled — correct, and completely invisible. It now saves each image as it goes (measured at 0.17 ms per save) and never holds the lock across a model call, so a pass classifies what you gave it. The 🔎 Watermark scan and the watermark repaint level got the same treatment before they could hit it. And when something does go wrong, every pass now ends the same way whether it finished or you stopped it: what it classified, what it could not read, what was deleted under it, what changed while it was being analysed, and what the model was never shown. Reported by mr.arrow (Discord).
Thanks to Arrow (Discord) — these came from you.
Full changelog: v2026.08.07...v2026.08.10