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

# 2026 05 11

<Update label="May 11, 2026" description="Custom PyBaMM model + Li-S support, ECM capacity co-optimization, default project for the Python SDK, structured validation issues">
  ## Custom PyBaMM models with Lithium-Sulfur chemistry

  The `/models/upload-custom` endpoint now accepts a `chemistry` field (defaulting
  to `lithium_ion`), and Li-S models get more accurate and robust initialization
  when they run. The `manage-projects` SDK skill documents the full upload
  workflow — `pybamm.Serialise().save_custom_model(filename=...)` → multipart
  upload → `client.model.get(id)` returns `is_custom_model: true`.

  ## ECM fit: capacity co-optimization and per-segment initial SoC

  Several interlocking improvements to the project-scoped ECM fit. Supplying an
  `ocv_soc_curve` (and optional `bounds_capacity`) lets you co-optimize cell
  capacity `Q` jointly with the fit instead of pinning `Q` to a single seed; on
  a 25 °C rate-test trace the fitted capacity now lands within 0.9 % of the
  coulomb-counting truth across all knot schedules. `initial_soc` accepts a
  list (one entry per measurement) so multi-measurement fits reset SoC at each
  segment boundary instead of integrating coulombs across the gaps; if you omit
  it, an improved auto-seed routine now estimates each segment's starting SoC
  automatically. `num_knots`, `num_knots_r0`, `knot_schedule`, and
  `clamp_max_ratio` are now first-class parameters on `/fit-from-measurements`
  and `/fit-from-file`. A boundary-clamp default was also loosened, fixing an
  issue where it could collapse the R0 fit and cause solver failures on
  rate-test forward simulations.

  ## Default project for the Python SDK

  The `Ionworks` client now resolves a default `project_id` at construction time
  from a `project_id=` argument or the new `IONWORKS_PROJECT_ID` environment
  variable, so callers no longer have to thread `project_id` through every call.
  The previous `PROJECT_ID` env var still works but emits a `DeprecationWarning`.
  All `client.study.*` methods take `project_id` as an optional keyword
  (after the resource ID) defaulting to the client value, and pipelines and
  optimizations auto-inject it into payloads.

  ## Structured measurement-validation issues

  `MeasurementValidationError.errors` is now `list[ValidationIssue]` — a frozen
  dataclass carrying a stable `IssueCode` (StrEnum), `severity`, human-readable
  `message`, and JSON-native `payload`. Downstream code can branch on check
  identity via `e.has_code(IssueCode.CURRENT_SIGN_REVERSED)` instead of grepping
  the message string. `ionworksdata`'s auto-fix path now keys off the new codes;
  `IssueCode` and `ValidationIssue` are re-exported from the top-level
  `ionworks` package.

  <AccordionGroup>
    <Accordion title="Studio">
      **Improvements**

      * Simulation boards now have a dedicated backend API at
        `/projects/{project_id}/studies/{study_id}/simulation_boards`, fixing a
        blank Visualization tab in some cases.
      * Optimization Performance Detail and Performance Summary tabs now surface
        buried `validation_warning` / `validation_not_supported` issues as
        top-level alerts above the tabs, with info "no data" alerts inside the
        tabs for the rare empty-but-valid case.
      * Defensive UX in the Visualization tab: the Data/Visualization toggle
        stays visible even when no board is available, with a warning alert
        prompting the switch back to Data instead of trapping the user on a
        blank page.

      **Fixes**

      * The single simulation result page no longer flashes "Simulation not
        found" before the data loads on a fresh navigation.
    </Accordion>

    <Accordion title="Pipeline">
      **Improvements**

      * `ionworks-schema` gained `Constraint`, `Penalty`, `CMAESOptions`,
        `PSOOptions`, `DEOptions`, `LatinHypercube`, and `Uniform` schema
        classes, plus improved documentation across objectives, data fits,
        parameter estimators, regularizers, and distribution samplers.

      **Fixes**

      * Fixed an issue where a solver failure on a bad parameter combination
        during a fit could crash the whole datafit instead of being handled
        gracefully. Cloud fits stay alive and the offending sample just gets a
        huge cost.
    </Accordion>

    <Accordion title="Python API">
      **Improvements**

      * New `client.urls.measurement(measurement_id, project_id)` helper
        returns the web app deep link for a measurement, so callers don't have
        to hand-build URLs themselves.
    </Accordion>

    <Accordion title="Skills">
      **Improvements**

      * `manage-projects` documents the `/models/upload-custom` multipart
        workflow and the Model / ParameterizedModel disambiguation.
      * `upload-data` and other validation-aware skills updated to reference
        the new `IssueCode` / `ValidationIssue` API and the
        `e.has_code(...)` pattern instead of substring-matching error strings.
    </Accordion>
  </AccordionGroup>
</Update>
