> ## Documentation Index
> Fetch the complete documentation index at: https://docs.freesolo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> New models, faster training and serving, and platform updates from the Freesolo team.

<Update
  label="August 23, 2026"
  description="2026-08-23"
  tags={["Flash 1.2.104", "Serving", "Training", "CLI"]}
  rss={{
title: "Flash 1.2.104",
description: "Serve in your own Modal or RunPod account, warm-start between any two algorithms, and read retried runs without guessing which worker spoke.",
}}
>
  ## Featured

  ### Serve in your own cloud account

  `flash serve deploy` provisions serving in **your own Modal or RunPod account**
  for one base model and one run's adapter. The GPU runs and bills in your account,
  and you call the provider's HTTPS endpoint directly, with no Freesolo gateway in
  the request path. `flash serve status` proves the current state without touching
  it, and `flash serve undeploy` removes one deployment and proves its resources are
  gone.

  Provider credentials are request-only: read from the environment for one call and
  never stored, logged, or written into the deployment record. The serving image
  must be pinned to a digest, so a deployment cannot drift to different content
  after it is recorded. See
  [Serve in your own account](/guides/deploy-and-chat#serve-in-your-own-account).

  ### Warm start works between any two algorithms

  `[train] init_from_adapter` now accepts a source adapter from **any** algorithm,
  for **any** target. SFT was previously rejected as a warm-start target; all nine
  combinations of `sft`, `grpo`, and `opd` now work, including same-algorithm
  continuation such as `sft` → `sft` to keep training on more data. A warm-started
  SFT run also inherits its source's base-model pin, so the continued adapter stays
  deployable when the upstream base moves. See
  [Warm-start safely](/guides/training#warm-start-safely).

  ### Retried runs say which worker spoke

  `flash runs log` names the attempt each log section came from and tags heartbeats
  from a superseded or torn-down worker, so skimming to the last heartbeat can no
  longer report a dead worker's final lines as live progress. Log artifacts are
  kept even when their attempt cannot be identified.

  <AccordionGroup>
    <Accordion title="Improvements" description="7 items">
      * **Training:** GRPO `group_size` is exactly `2`, `4`, or `8` (default
        `8`), and a step is capped at 512 completions
        (`prompts_per_step x group_size`). Both are checked at submit, before a
        GPU is allocated, and Flash never rewrites the value you authored. See
        [the GRPO rollout
        shape](/reference/configuration#the-grpo-rollout-shape-is-a-fixed-set).
      * **GPUs:** A multi-card quote now shows pooled VRAM against the whole-run
        requirement (`300 GB usable across 2x 180 GB; run needs >= 199 GB`), so a
        shape that fits no longer reads as a rejection. A single-card pin that
        cannot hold the run names the card count that would.
      * **Cost:** SFT `--cost` and `--dry-run` name the published environment and
        commit their counts came from, and say to republish when the numbers look
        stale. Inline `records` are labelled as coming from your config.
      * **Runs:** A failed checkpoint upload reports its cause in the run
        heartbeat and log instead of leaving a silent gap; a later successful
        upload of the same checkpoint clears it.
      * **Runs:** A CUDA out-of-memory failure keeps the allocation figures (how
        much was requested against what the card had), and the bare
        `CUDA error: out of memory` spelling is now classified.
      * **CLI:** An unknown flag comes back with the closest real flag for the
        command you ran, and says when a flag belongs at the root instead of on
        the subcommand.
      * **CLI:** `flash env setup` fills in the `[wandb]` block with your
        project's name and a folder-derived run name; edit or delete it freely.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="August 17, 2026"
  description="2026-08-17"
  tags={["Flash 1.2.63", "Training", "Serving", "Self-hosting"]}
  rss={{
title: "Flash 1.2.63",
description: "SFT estimates are synchronous, multimodal training has explicit limits, and deployments gain a run-scoped chat route.",
}}
>
  ## Featured

  ### SFT estimates return in the same command

  Flash 1.2.63 returns SFT `--cost`, `--dry-run`, and submit preparation
  synchronously from the selected packaged dataset, without a separate profile job
  or training GPU allocation. The estimate is static, so environment-defined
  prompt construction, filtering, and transformations can still change real
  training. See [Cost and billing](/reference/cost-model).

  ### Multimodal training has explicit contracts

  Multimodal training now has explicit input limits and algorithm-specific rules;
  serving has a separate request contract. See [Image
  inputs](/guides/datasets#image-inputs) and [Deploy &
  chat](/guides/deploy-and-chat).

  ### Deployments are easier to call and harder to confuse

  The default `flash models deploy --wait` timeout is now 2400 seconds, and runs
  have an ownership-checked `POST /v1/runs/{run_id}/chat` route. Each run has one
  shared bare alias, so deploying another checkpoint moves that alias. See [Deploy & chat](/guides/deploy-and-chat).

  <AccordionGroup>
    <Accordion title="Improvements" description="6 items">
      * **Training:** Multi-turn SFT masks non-assistant target turns when role
        parsing succeeds. See [Multi-turn SFT
        masking](/guides/datasets#multi-turn-sft-masks-observations).
      * **Configuration:** Delete `model_revision` from older configs; current
        clients reject it and Flash resolves supported revisions internally.
      * **GPUs:** GPU type lists are acceptable classes ranked by cost;
        `[gpu] providers` is an ordered preference, while scalar `type` and
        `provider` values remain hard pins.
      * **Self-hosting:** Use a standalone GitHub source reachable from the plane
        and resolving to `environment.py`; managed Hub slugs are not accepted.
      * **CLI:** `flash env eval TARGET` uses the run's published environment,
        supports split and parameter overrides, and uploads by default.
        `flash runs status <run-id> --json` prints one JSON object, or JSONL
        with `--follow`.
      * **Serving:** Deploying a checkpoint warns before moving the shared bare
        run alias to that checkpoint.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="August 12, 2026"
  description="2026-08-12"
  tags={["Training", "Environments", "Flash CLI"]}
  rss={{
title: "August 12, 2026",
description: "Runs size their own GPUs, the RL optimizer batch gets its own name, and environments can declare their scorer's dependencies again.",
}}
>
  ## Featured

  ### Runs size their own GPUs

  Leave `[gpu] count` out and Flash now picks the smallest shape your run actually
  fits on, then ranks the fitting shapes by cost per step. Configurations that used
  to be rejected for needing more memory than a single card holds - a large model
  at long context, or at a high LoRA rank - now land on two or more cards instead
  of failing.

  Setting `count` (or `--gpus N`) still pins a ceiling that never escalates, and
  pinning `[gpu] type` without a count stays a single-card pin, so naming a
  specific card never quietly bills you for four of them. When a run does not fit,
  the error names the smallest count that would work. See
  [Multi-GPU runs](/reference/configuration#multi-gpu-runs).

  ### The RL optimizer batch has its own name

  GRPO and OPD now author `prompts_per_step`; `batch_size` is SFT-only, and each is
  rejected under the other algorithm.

  They were never the same quantity. Under SFT a measured workload profile turns
  `batch_size` into examples-per-update; under GRPO and OPD the key **is** the
  optimizer batch. So `batch_size = 1`, the standard SFT out-of-memory workaround,
  silently meant one prompt per update when copied into an RL config - the run
  trained, logged, and billed at a fraction of the intended batch without erroring.
  Porting an older RL config is a rename, not a copy: the defaults are `64` for
  GRPO and `8` for OPD. See
  [the optimizer batch](/reference/configuration#the-optimizer-batch-has-a-different-name-per-algorithm).

  <AccordionGroup>
    <Accordion title="Improvements" description="9 items">
      * **Environments:** Environment names are now unique **per project**, not
        per organization. Two projects in one organization can each publish their
        own `math`. The owning project is part of the id, which is now
        `namespace/project/name`, and renaming a project does not change ids it
        already published. Existing environments keep their name and are
        republished under their owning project's slug. **Update your configs:** a
        two-segment `namespace/name` id no longer resolves, so replace it with
        the new id - `flash env list` prints the full id of everything you have
        published.
      * **Environments:** `[environment] pip` is a config key again - declare the
        third-party packages your scorer imports and the worker installs them.
        Entry **syntax** is validated at submit, so a malformed or disallowed
        requirement fails before a GPU is allocated. A well-formed entry that
        cannot resolve - a misspelled name, an impossible version pin - still
        fails during install, after allocation. Pip options and URLs carrying
        credentials are rejected. See [Scorer
        dependencies](/reference/configuration#scorer-dependencies).
      * **Flash CLI:** `flash env list` now shows your organization's published
        environments alongside your local sources, so the id you paste into
        `[environment] id` is in front of you.
      * **Environments:** `flash env list` prints the full id of every published
        environment, which is the value to paste into `[environment] id` after
        this change.
      * **Training:** An OPD run whose rollouts are nearly all truncated now
        fails naming `max_completion_tokens` and the truncated fraction, rather
        than exiting on an opaque subprocess status.
      * **Training:** SFT sequence packing now covers gated-delta-net models,
        which every catalog model is, once the training image can reset example
        boundaries. Previously those runs trained exactly one example per update,
        so a configured `batch_size` did not group anything. Runs that still
        cannot pack - multimodal rows - warn about that.
      * **Training:** A transient package-index failure while installing your
        environment's dependencies is retried instead of failing the run. A real
        resolution or build failure stays terminal rather than burning GPU time
        on a retry that cannot succeed.
      * **Cost:** A GRPO or OPD config that states neither `max_steps` nor
        `max_examples` is now refused rather than quoted. The horizon came from
        the retained prompt pool, so an unbounded pool derived a single step and
        previewed a full run at one step's price.
      * **Self-hosting:** Flash now also installs a `flash-cli` console script.
        The `server` and `dev` extras pull in `runpod-flash`, which claims the
        same `flash` name, so on a plane host `flash` could silently be a
        different tool. `flash-cli` always reaches Flash.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="August 10, 2026"
  description="2026-08-10"
  tags={["Training", "Environments", "Self-hosting"]}
  rss={{
title: "August 10, 2026",
description: "On-policy distillation can train on image prompts, and self-hosted planes get clearer origin and transport settings.",
}}
>
  ## Featured

  ### Distil from image prompts

  On-policy distillation accepts image-bearing prompts when the teacher can
  actually see them. Pick an image-capable `teacher_model` - `qwen3.5-397b-a17b`
  or the new `qwen3-vl-235b` - and a text-only teacher is refused rather than
  silently distilling from a teacher that never saw the pixels. Single-turn only.
  See
  [image-bearing OPD](/reference/configuration#image-bearing-opd).

  <AccordionGroup>
    <Accordion title="Improvements" description="3 items">
      * **Environments:** On the managed service, `[environment] id` takes a
        published `namespace/name` slug only; `github:` refs and GitHub URLs are
        rejected at submit and remain available when self-hosting.
      * **Self-hosting:** The OPD teacher-broker origin is now set with
        `FLASH_PUBLIC_URL`; the former `FLASH_CONTROL_PANEL_URL` is no longer
        read. It is the plane's own worker-reachable origin, not the client's
        `--api-url`.
      * **Self-hosting:** `flash login` warns when given a non-loopback `http://`
        URL, which would send the plane's root credential in cleartext.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="August 9, 2026"
  description="2026-08-09"
  tags={["Flash CLI", "Training", "Self-hosting"]}
  rss={{
title: "August 9, 2026",
description: "SFT is priced from a measured profile, [train] knobs are scoped per algorithm, and Flash can run on your own GPU accounts.",
}}
>
  ## Featured

  ### SFT cost comes from a measured profile, not a guess

  SFT cost depends on the exact tokenized dataset, so `--cost` no longer estimates
  it from a row count. The first `--cost`, `--dry-run`, or `train` for a config
  starts a short profile run that loads your environment and tokenizes exactly the
  rows training would consume, then quotes from that. It is measured once per exact
  config and reused, so only the first submission waits.

  <Note>
    Superseded in Flash 1.2.63 on August 17, 2026. SFT estimates now read the
    packaged dataset synchronously without importing `environment.py`, creating a
    profile run, or allocating a training GPU. This entry remains as release
    history. See [Cost and
    billing](/reference/cost-model#grpo-and-opd-quote-locally-sft-reads-packaged-data).
  </Note>

  ### `[train]` rejects knobs that do not apply to your algorithm

  Setting `group_size` on an SFT run used to be silently ignored, which reads as a
  setting that did nothing. Flash now rejects a knob the chosen algorithm never
  consumes, and names the algorithm in the error, so a typo fails at parse time
  rather than after a GPU is rented. See
  [Knobs are scoped by algorithm](/reference/configuration#knobs-are-scoped-by-algorithm).

  ### Run Flash on your own GPU accounts

  A self-hosted control plane now works against any subset of RunPod, Lambda, and
  Vast: configure the providers you have and the allocator only ranks those.
  Startup preflights the operator config and refuses to boot if it could not run a
  job, hosted-only CLI commands either work locally or say why they cannot, and the
  state directory, logging, and bind address are configurable. See
  [Self-hosting](/guides/self-hosting).

  <AccordionGroup>
    <Accordion title="Improvements" description="6 items">
      * **Training:** `lora_alpha` is authorable again in `[train]`, defaulting to
        `2 * lora_rank`. Omit both it and `lora_rank` when warm-starting from an
        adapter - they are inherited.
      * **Flash CLI:** `flash train --gpus N` requests a card count without editing
        the config. The count is a ceiling, and Flash rents the largest rentable
        shape at or below it.
      * **Models:** 4B and 9B now serve LoRA rank 128, matching what the serving app
        actually supports, and every catalog model accepts a 32768-token context.
      * **Models:** Every trainable model must be in the catalog. An uncatalogued
        `model` is rejected when the config is parsed, before any GPU is allocated.
      * **Environments:** The worker installs one managed requirement set for every
        environment, so `[environment] pip` and the per-run `[worker_env]` table are
        no longer accepted. Import from the `freesolo` SDK and the standard library.
      * **Training:** Multi-card runs are priced for every card they occupied, and
        NVLink scaling is only credited on combinations that actually have it.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="July 31, 2026"
  description="2026-07-31"
  tags={["Flash CLI", "Environments", "Serving"]}
  rss={{
title: "July 31, 2026",
description: "Evaluate a deployed model against held-out suites, and gate scripts on a deploy.",
}}
>
  ## Featured

  ### Evaluate a deployed model against held-out suites

  Put an `evaluations.py` beside your `environment.py` and `flash env eval RUN_ID`
  scores those suites against the deployed adapter. Cases that never reached the
  model are counted as errors instead of averaged in as zeros, so a half-broken
  deployment reads as broken rather than as a weak model. Available in Flash 1.0.34.

  ### Gate a script on a deploy instead of polling

  `flash models deploy --wait` blocks until the revision is actually servable and
  exits non-zero if it fails, so a deploy can be chained in automation.

  <AccordionGroup>
    <Accordion title="Improvements" description="5 items">
      * **Environments:** `flash env test` can drive the split you actually train on
        with `--split` and `--param`, and now fails when every replayed gold answer
        scores zero.
      * **Environments:** Scope an eval with `--suite`, cap it with `--max-cases`, and
        raise `--concurrency` to run cases in parallel.
      * **Serving:** Interrupting `flash models deploy --wait` stops waiting, not the
        deployment.
      * **Flash CLI:** `flash train --dry-run` checks your org balance against the
        quote, so an insufficient balance fails before you submit.
      * **Flash CLI:** `flash env setup` scaffolds a starter `evaluations.py`.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="July 28, 2026"
  description="2026-07-28"
  tags={["Platform", "Tracing", "Serving"]}
  rss={{
title: "July 28, 2026",
description: "Turn your app's live traffic into a training set and get cleaner output from thinking models.",
}}
>
  ## Featured

  ### Turn your app's live traffic into a training set

  Point an OpenAI-compatible client at `https://api.freesolo.co/v1` and Freesolo
  records your app's chat completions against a project, then hands them back as a
  training dataset with `flash traces export`. Secrets are redacted before anything
  is forwarded or stored. See [Tracing](/guides/tracing).

  ### Thinking models split reasoning out of `content`

  Reasoning now comes back in `reasoning_content` and only the answer in `content`,
  in both JSON and streaming responses, so the `</think>` separator no longer leaks
  into `content`.

  <AccordionGroup>
    <Accordion title="Improvements" description="1 item">
      * **Serving:** `flash models chat` folds the two fields back into one
        `<think>...</think>` block, so the CLI still shows the full generation.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="July 27, 2026"
  description="2026-07-27"
  tags={["Flash CLI", "Platform", "Projects", "Serving"]}
  rss={{
title: "July 27, 2026",
description: "Every run and environment belongs to a project, and run and serving commands are grouped.",
}}
>
  ## Featured

  ### Every run and environment belongs to a project

  Training configs take a required top-level `project` UUID, and `flash env push`
  and `flash env delete` take a required `--project`. Flash validates the project
  against your organization before allocating a GPU, so a wrong or missing project
  fails the submit instead of starting paid work. Available in Flash 1.0.25.

  ### Run and serving commands are grouped

  `flash status`, `log`, `cancel`, and `checkpoints` are now `flash runs status`,
  `runs log`, `runs cancel`, and `runs checkpoint`. `flash deploy`, `chat`,
  `undeploy`, `deployments`, and `export` are now `flash models deploy`,
  `models chat`, `models undeploy`, `models deployments`, and `models export`.
  Listing base models is `flash models list`.

  <AccordionGroup>
    <Accordion title="Improvements" description="3 items">
      * **Platform:** Deploy and tear down serving from the dashboard, without
        switching to the CLI.
      * **Platform:** A project selector in the top bar moves between projects from
        anywhere in the dashboard.
      * **Flash CLI:** Create and find projects with `flash projects create` and
        `flash projects list`.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="July 24, 2026"
  description="2026-07-24"
  tags={["Platform", "Projects"]}
  rss={{
title: "July 24, 2026",
description: "Organize runs, environments, and traces into projects.",
}}
>
  ## Featured

  ### Organize runs, environments, and traces into projects

  Group related work under an organization-level project and switch between
  projects from the platform.
</Update>

<Update
  label="July 22, 2026"
  description="2026-07-22"
  tags={["Platform", "Training"]}
  rss={{
title: "July 22, 2026",
description: "Watch training as it happens with live metrics, logs, and sample completions.",
}}
>
  ## Featured

  ### Watch training as it happens

  Live metrics, run logs, and sample completions in the platform, plus per-step
  rewards from the Flash CLI.
</Update>

<Update
  label="July 21, 2026"
  description="2026-07-21"
  tags={["Serving", "Training"]}
  rss={{
title: "July 21, 2026",
description: "7-10x faster generation on 9B and 27B models, and SFT training up to 48% faster.",
}}
>
  ## Featured

  ### 7-10x faster generation on 9B and 27B models

  ### SFT training up to 48% faster

  Lower memory use and faster data processing also unlock longer training contexts.

  <AccordionGroup>
    <Accordion title="Improvements" description="1 item">
      * **Training:** Pure multi-turn GRPO tasks with independently gradable turns
        can choose per-turn or per-episode credit.
    </Accordion>
  </AccordionGroup>
</Update>

<Update
  label="July 20, 2026"
  description="2026-07-20"
  tags={["Models"]}
  rss={{
title: "July 20, 2026",
description: "Train and serve multimodal models with image inputs.",
}}
>
  ## Featured

  ### Train and serve multimodal models

  Use image inputs with multimodal SFT, GRPO, on-policy distillation, and chat
  serving.
</Update>

<Update
  label="July 19, 2026"
  description="2026-07-19"
  tags={["Models"]}
  rss={{
title: "July 19, 2026",
description: "Qwen3.6-27B is now available to train and serve.",
}}
>
  ## Featured

  ### Qwen3.6-27B is now available

  Train and serve Qwen3.6-27B on Freesolo.
</Update>

<Update
  label="July 17, 2026"
  description="2026-07-17"
  tags={["Serving", "Training"]}
  rss={{
title: "July 17, 2026",
description: "32k context windows for training and serving.",
}}
>
  ## Featured

  ### 32k context for training and serving

  Train and serve supported models with context windows up to 32k tokens.
</Update>
